basic integration of mfoc + cropto1_bs

Special thanks to @skgsergio for helping with automake stuff :)
This commit is contained in:
Valentín Kivachuk 2018-11-25 17:01:24 +01:00
parent 0723f53aaf
commit fc39e033c4
19 changed files with 73386 additions and 20 deletions

View File

@ -6,7 +6,9 @@ AC_CONFIG_HEADERS([config.h])
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
@ -16,6 +18,11 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
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([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.])])
AX_LIB_READLINE
PKG_CONFIG_REQUIRES="libnfc"
AC_SUBST([PKG_CONFIG_REQUIRES])
@ -35,7 +42,7 @@ AC_FUNC_REALLOC
AC_CHECK_FUNCS([memset])
# C99
CFLAGS="$CFLAGS -std=c99 -O3 -Wall"
CFLAGS="$CFLAGS -std=c99"
AC_CONFIG_FILES([Makefile
src/Makefile])

View File

@ -2,9 +2,50 @@ AM_CFLAGS = @libnfc_CFLAGS@
bin_PROGRAMS = mfoc
noinst_HEADERS = crapto1.h mfoc.h mifare.h nfc-utils.h parity.h
noinst_HEADERS = crapto1.h mfoc.h mifare.h nfc-utils.h parity.h hardnested/hardnested_bruteforce.h hardnested/tables.h cmdhfmfhard.h util.h util_posix.h ui.h
mfoc_SOURCES = crapto1.c crypto1.c mfoc.c mifare.c nfc-utils.c parity.c
mfoc_LDADD = @libnfc_LIBS@
mfoc_SOURCES = crapto1.c crypto1.c mfoc.c mifare.c nfc-utils.c parity.c hardnested/hardnested_bruteforce.c hardnested/tables.c cmdhfmfhard.c util.c util_posix.c ui.c
mfoc_LDADD = @libnfc_LIBS@ $(MULTIARCHOBJS)
dist_man_MANS = mfoc.1
#MULTIARCH = hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c
MULTIARCHOBJS = hardnested/hardnested_bf_core_NOSIMD.o \
hardnested/hardnested_bf_core_MMX.o \
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_NOSIMD.o \
hardnested/hardnested_bitarray_core_MMX.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
HARD_SWITCH_NOSIMD = -mno-mmx -mno-sse2 -mno-avx -mno-avx2 -mno-avx512f
HARD_SWITCH_MMX = -mmmx -mno-sse2 -mno-avx -mno-avx2 -mno-avx512f
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
hardnested/%_NOSIMD.o : hardnested/%.c
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_NOSIMD) -c -o $@ $<
hardnested/%_MMX.o : hardnested/%.c
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_MMX) -c -o $@ $<
hardnested/%_SSE2.o : hardnested/%.c
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_SSE2) -c -o $@ $<
hardnested/%_AVX.o : hardnested/%.c
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX) -c -o $@ $<
hardnested/%_AVX2.o : hardnested/%.c
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX2) -c -o $@ $<
hardnested/%_AVX512.o : hardnested/%.c
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX512) -c -o $@ $<

2880
src/cmdhfmfhard.c Normal file

File diff suppressed because it is too large Load Diff

53
src/cmdhfmfhard.h Normal file
View File

@ -0,0 +1,53 @@
//-----------------------------------------------------------------------------
// 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>
#define NUM_SUMS 19 // number of possible sum property values
typedef enum {
EVEN_STATE = 0,
ODD_STATE = 1
} odd_even_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, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow, int tests);
void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time);
#endif

View File

@ -0,0 +1,662 @@
//-----------------------------------------------------------------------------
// 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_bf_core.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#ifndef __APPLE__
#include <malloc.h>
#endif
#include <stdio.h>
#include <string.h>
#include "../crapto1.h"
#include "../parity.h"
// bitslice type
// while AVX supports 256 bit vector floating point operations, we need integer operations for boolean logic
// same for AVX2 and 512 bit vectors
// using larger vectors works but seems to generate more register pressure
#if defined(__AVX512F__)
#define MAX_BITSLICES 512
#elif defined(__AVX2__)
#define MAX_BITSLICES 256
#elif defined(__AVX__)
#define MAX_BITSLICES 128
#elif defined(__SSE2__)
#define MAX_BITSLICES 128
#else // MMX or SSE or NOSIMD
#define MAX_BITSLICES 64
#endif
#define VECTOR_SIZE (MAX_BITSLICES/8)
typedef unsigned int __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)))
// this needs to be compiled several times for each instruction set.
// For each instruction set, define a dedicated function name:
#if defined (__AVX512F__)
#define BITSLICE_TEST_NONCES bitslice_test_nonces_AVX512
#define CRACK_STATES_BITSLICED crack_states_bitsliced_AVX512
#elif defined (__AVX2__)
#define BITSLICE_TEST_NONCES bitslice_test_nonces_AVX2
#define CRACK_STATES_BITSLICED crack_states_bitsliced_AVX2
#elif defined (__AVX__)
#define BITSLICE_TEST_NONCES bitslice_test_nonces_AVX
#define CRACK_STATES_BITSLICED crack_states_bitsliced_AVX
#elif defined (__SSE2__)
#define BITSLICE_TEST_NONCES bitslice_test_nonces_SSE2
#define CRACK_STATES_BITSLICED crack_states_bitsliced_SSE2
#elif defined (__MMX__)
#define BITSLICE_TEST_NONCES bitslice_test_nonces_MMX
#define CRACK_STATES_BITSLICED crack_states_bitsliced_MMX
#else
#define BITSLICE_TEST_NONCES bitslice_test_nonces_NOSIMD
#define CRACK_STATES_BITSLICED crack_states_bitsliced_NOSIMD
#endif
// typedefs and declaration of functions:
typedef const 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_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;
crack_states_bitsliced_t crack_states_bitsliced_MMX;
crack_states_bitsliced_t crack_states_bitsliced_NOSIMD;
crack_states_bitsliced_t crack_states_bitsliced_dispatch;
typedef void bitslice_test_nonces_t(uint32_t, uint32_t*, uint8_t*);
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;
bitslice_test_nonces_t bitslice_test_nonces_MMX;
bitslice_test_nonces_t bitslice_test_nonces_NOSIMD;
bitslice_test_nonces_t bitslice_test_nonces_dispatch;
#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(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;
}
}
}
}
const 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) {
// 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];
#if defined (DEBUG_BRUTE_FORCE)
uint32_t elimination_step = 0;
#define MAX_ELIMINATION_STEP 32
uint64_t keys_eliminated[MAX_ELIMINATION_STEP] = {0};
#endif
#ifdef DEBUG_KEY_ELIMINATION
bool bucket_contains_test_key[(p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1];
#endif
// constant ones/zeroes
bitslice_t bs_ones;
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
bitslice_t bs_zeroes;
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;
#ifdef DEBUG_KEY_ELIMINATION
bucket_contains_test_key[bitsliced_blocks] = false;
#endif
uint32_t slice_idx;
for (slice_idx = 0; slice_idx < max_slices; ++slice_idx) {
uint32_t e = *(p_even + slice_idx);
#ifdef DEBUG_KEY_ELIMINATION
if (known_target_key != -1 && e == test_state[EVEN_STATE]) {
bucket_contains_test_key[bitsliced_blocks] = true;
// printf("bucket %d contains test key even state\n", bitsliced_blocks);
// printf("in slice %d\n", slice_idx);
}
#endif
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) {
#ifdef DEBUG_KEY_ELIMINATION
// if (known_target_key != -1 && bucket_contains_test_key[block_idx] && *p_odd == test_state[ODD_STATE]) {
// printf("Now testing known target key.\n");
// printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks);
// }
#endif
// 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
#if MAX_BITSLICES > 64
&& results.bytes64[1] == 0
#endif
#if MAX_BITSLICES > 128
&& results.bytes64[2] == 0
&& results.bytes64[3] == 0
#endif
) {
#if defined (DEBUG_BRUTE_FORCE)
if (elimination_step < MAX_ELIMINATION_STEP) {
keys_eliminated[elimination_step] += MAX_BITSLICES;
}
#endif
#ifdef DEBUG_KEY_ELIMINATION
if (known_target_key != -1 && bucket_contains_test_key[block_idx] && *p_odd == test_state[ODD_STATE]) {
printf("Known target key eliminated in brute_force.\n");
printf("block_idx = %d/%d, nonce = %d/%d\n", block_idx, bitsliced_blocks, tests, nonces_to_bruteforce);
}
#endif
goto stop_tests;
}
// prepare for next nonce byte
#if defined (DEBUG_BRUTE_FORCE)
elimination_step++;
#endif
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;
}
#ifdef DEBUG_KEY_ELIMINATION
if (known_target_key != -1 && *p_even_test == test_state[EVEN_STATE] && *p_odd == test_state[ODD_STATE]) {
printf("Known target key eliminated in brute_force verification.\n");
printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks);
}
#endif
}
#ifdef DEBUG_KEY_ELIMINATION
if (known_target_key != -1 && *p_even_test == test_state[EVEN_STATE] && *p_odd == test_state[ODD_STATE]) {
printf("Known target key eliminated in brute_force (results_bit == 0).\n");
printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks);
}
#endif
results64 >>= 1;
p_even_test++;
if (p_even_test == p_even_end) {
goto stop_tests;
}
}
}
stop_tests:
#if defined (DEBUG_BRUTE_FORCE)
elimination_step = 0;
#endif
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);
#if defined (DEBUG_BRUTE_FORCE)
for (uint32_t i = 0; i < MAX_ELIMINATION_STEP; i++) {
printf("Eliminated after %2u test_bytes: %5.2f%%\n", i + 1, (float) keys_eliminated[i] / bucket_states_tested * 100);
}
#endif
return key;
}
#ifndef __MMX__
// pointers to functions:
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;
static SIMDExecInstr intSIMDInstr = SIMD_AUTO;
void SetSIMDInstr(SIMDExecInstr instr) {
intSIMDInstr = instr;
crack_states_bitsliced_function_p = &crack_states_bitsliced_dispatch;
bitslice_test_nonces_function_p = &bitslice_test_nonces_dispatch;
}
SIMDExecInstr GetSIMDInstr() {
SIMDExecInstr instr = SIMD_NONE;
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) instr = SIMD_AVX512;
else if (__builtin_cpu_supports("avx2")) instr = SIMD_AVX2;
#else
if (__builtin_cpu_supports("avx2")) instr = SIMD_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) instr = SIMD_AVX;
else if (__builtin_cpu_supports("sse2")) instr = SIMD_SSE2;
else if (__builtin_cpu_supports("mmx")) instr = SIMD_MMX;
else
#endif
#endif
instr = SIMD_NONE;
return instr;
}
SIMDExecInstr GetSIMDInstrAuto() {
SIMDExecInstr instr = intSIMDInstr;
if (instr == SIMD_AUTO)
return GetSIMDInstr();
return instr;
}
// determine the available instruction set at runtime and call the correct function
const 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 (GetSIMDInstrAuto()) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
case SIMD_AVX512:
crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX512;
break;
#endif
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;
case SIMD_MMX:
crack_states_bitsliced_function_p = &crack_states_bitsliced_MMX;
break;
#endif
#endif
default:
crack_states_bitsliced_function_p = &crack_states_bitsliced_NOSIMD;
break;
}
// 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 (GetSIMDInstrAuto()) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
case SIMD_AVX512:
bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX512;
break;
#endif
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;
case SIMD_MMX:
bitslice_test_nonces_function_p = &bitslice_test_nonces_MMX;
break;
#endif
#endif
default:
bitslice_test_nonces_function_p = &bitslice_test_nonces_NOSIMD;
break;
}
// call the most optimized function for this CPU
(*bitslice_test_nonces_function_p)(nonces_to_bruteforce, bf_test_nonce, bf_test_nonce_par);
}
// Entries to dispatched function calls
const 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);
}
#endif

View File

@ -0,0 +1,70 @@
//-----------------------------------------------------------------------------
// 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.
*/
#ifndef HARDNESTED_BF_CORE_H__
#define HARDNESTED_BF_CORE_H__
#include "hardnested_bruteforce.h" // statelist_t
typedef enum {
SIMD_AUTO,
SIMD_AVX512,
SIMD_AVX2,
SIMD_AVX,
SIMD_SSE2,
SIMD_MMX,
SIMD_NONE,
} SIMDExecInstr;
extern void SetSIMDInstr(SIMDExecInstr instr);
extern SIMDExecInstr GetSIMDInstrAuto();
extern const 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);
#endif

View File

@ -0,0 +1,625 @@
//-----------------------------------------------------------------------------
// 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_bitarray_core.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef __APPLE__
#include <malloc.h>
#endif
// this needs to be compiled several times for each instruction set.
// For each instruction set, define a dedicated function name:
#if defined (__AVX512F__)
#define MALLOC_BITARRAY malloc_bitarray_AVX512
#define FREE_BITARRAY free_bitarray_AVX512
#define BITCOUNT bitcount_AVX512
#define COUNT_STATES count_states_AVX512
#define BITARRAY_AND bitarray_AND_AVX512
#define BITARRAY_LOW20_AND bitarray_low20_AND_AVX512
#define COUNT_BITARRAY_AND count_bitarray_AND_AVX512
#define COUNT_BITARRAY_LOW20_AND count_bitarray_low20_AND_AVX512
#define BITARRAY_AND4 bitarray_AND4_AVX512
#define BITARRAY_OR bitarray_OR_AVX512
#define COUNT_BITARRAY_AND2 count_bitarray_AND2_AVX512
#define COUNT_BITARRAY_AND3 count_bitarray_AND3_AVX512
#define COUNT_BITARRAY_AND4 count_bitarray_AND4_AVX512
#elif defined (__AVX2__)
#define MALLOC_BITARRAY malloc_bitarray_AVX2
#define FREE_BITARRAY free_bitarray_AVX2
#define BITCOUNT bitcount_AVX2
#define COUNT_STATES count_states_AVX2
#define BITARRAY_AND bitarray_AND_AVX2
#define BITARRAY_LOW20_AND bitarray_low20_AND_AVX2
#define COUNT_BITARRAY_AND count_bitarray_AND_AVX2
#define COUNT_BITARRAY_LOW20_AND count_bitarray_low20_AND_AVX2
#define BITARRAY_AND4 bitarray_AND4_AVX2
#define BITARRAY_OR bitarray_OR_AVX2
#define COUNT_BITARRAY_AND2 count_bitarray_AND2_AVX2
#define COUNT_BITARRAY_AND3 count_bitarray_AND3_AVX2
#define COUNT_BITARRAY_AND4 count_bitarray_AND4_AVX2
#elif defined (__AVX__)
#define MALLOC_BITARRAY malloc_bitarray_AVX
#define FREE_BITARRAY free_bitarray_AVX
#define BITCOUNT bitcount_AVX
#define COUNT_STATES count_states_AVX
#define BITARRAY_AND bitarray_AND_AVX
#define BITARRAY_LOW20_AND bitarray_low20_AND_AVX
#define COUNT_BITARRAY_AND count_bitarray_AND_AVX
#define COUNT_BITARRAY_LOW20_AND count_bitarray_low20_AND_AVX
#define BITARRAY_AND4 bitarray_AND4_AVX
#define BITARRAY_OR bitarray_OR_AVX
#define COUNT_BITARRAY_AND2 count_bitarray_AND2_AVX
#define COUNT_BITARRAY_AND3 count_bitarray_AND3_AVX
#define COUNT_BITARRAY_AND4 count_bitarray_AND4_AVX
#elif defined (__SSE2__)
#define MALLOC_BITARRAY malloc_bitarray_SSE2
#define FREE_BITARRAY free_bitarray_SSE2
#define BITCOUNT bitcount_SSE2
#define COUNT_STATES count_states_SSE2
#define BITARRAY_AND bitarray_AND_SSE2
#define BITARRAY_LOW20_AND bitarray_low20_AND_SSE2
#define COUNT_BITARRAY_AND count_bitarray_AND_SSE2
#define COUNT_BITARRAY_LOW20_AND count_bitarray_low20_AND_SSE2
#define BITARRAY_AND4 bitarray_AND4_SSE2
#define BITARRAY_OR bitarray_OR_SSE2
#define COUNT_BITARRAY_AND2 count_bitarray_AND2_SSE2
#define COUNT_BITARRAY_AND3 count_bitarray_AND3_SSE2
#define COUNT_BITARRAY_AND4 count_bitarray_AND4_SSE2
#elif defined (__MMX__)
#define MALLOC_BITARRAY malloc_bitarray_MMX
#define FREE_BITARRAY free_bitarray_MMX
#define BITCOUNT bitcount_MMX
#define COUNT_STATES count_states_MMX
#define BITARRAY_AND bitarray_AND_MMX
#define BITARRAY_LOW20_AND bitarray_low20_AND_MMX
#define COUNT_BITARRAY_AND count_bitarray_AND_MMX
#define COUNT_BITARRAY_LOW20_AND count_bitarray_low20_AND_MMX
#define BITARRAY_AND4 bitarray_AND4_MMX
#define BITARRAY_OR bitarray_OR_MMX
#define COUNT_BITARRAY_AND2 count_bitarray_AND2_MMX
#define COUNT_BITARRAY_AND3 count_bitarray_AND3_MMX
#define COUNT_BITARRAY_AND4 count_bitarray_AND4_MMX
#else
#define MALLOC_BITARRAY malloc_bitarray_NOSIMD
#define FREE_BITARRAY free_bitarray_NOSIMD
#define BITCOUNT bitcount_NOSIMD
#define COUNT_STATES count_states_NOSIMD
#define BITARRAY_AND bitarray_AND_NOSIMD
#define BITARRAY_LOW20_AND bitarray_low20_AND_NOSIMD
#define COUNT_BITARRAY_AND count_bitarray_AND_NOSIMD
#define COUNT_BITARRAY_LOW20_AND count_bitarray_low20_AND_NOSIMD
#define BITARRAY_AND4 bitarray_AND4_NOSIMD
#define BITARRAY_OR bitarray_OR_NOSIMD
#define COUNT_BITARRAY_AND2 count_bitarray_AND2_NOSIMD
#define COUNT_BITARRAY_AND3 count_bitarray_AND3_NOSIMD
#define COUNT_BITARRAY_AND4 count_bitarray_AND4_NOSIMD
#endif
// typedefs and declaration of functions:
typedef uint32_t* malloc_bitarray_t(uint32_t);
malloc_bitarray_t malloc_bitarray_AVX512, malloc_bitarray_AVX2, malloc_bitarray_AVX, malloc_bitarray_SSE2, malloc_bitarray_MMX, malloc_bitarray_NOSIMD, malloc_bitarray_dispatch;
typedef void free_bitarray_t(uint32_t*);
free_bitarray_t free_bitarray_AVX512, free_bitarray_AVX2, free_bitarray_AVX, free_bitarray_SSE2, free_bitarray_MMX, free_bitarray_NOSIMD, free_bitarray_dispatch;
typedef uint32_t bitcount_t(uint32_t);
bitcount_t bitcount_AVX512, bitcount_AVX2, bitcount_AVX, bitcount_SSE2, bitcount_MMX, bitcount_NOSIMD, bitcount_dispatch;
typedef uint32_t count_states_t(uint32_t*);
count_states_t count_states_AVX512, count_states_AVX2, count_states_AVX, count_states_SSE2, count_states_MMX, count_states_NOSIMD, count_states_dispatch;
typedef void bitarray_AND_t(uint32_t[], uint32_t[]);
bitarray_AND_t bitarray_AND_AVX512, bitarray_AND_AVX2, bitarray_AND_AVX, bitarray_AND_SSE2, bitarray_AND_MMX, bitarray_AND_NOSIMD, bitarray_AND_dispatch;
typedef void bitarray_low20_AND_t(uint32_t*, uint32_t*);
bitarray_low20_AND_t bitarray_low20_AND_AVX512, bitarray_low20_AND_AVX2, bitarray_low20_AND_AVX, bitarray_low20_AND_SSE2, bitarray_low20_AND_MMX, bitarray_low20_AND_NOSIMD, bitarray_low20_AND_dispatch;
typedef uint32_t count_bitarray_AND_t(uint32_t*, uint32_t*);
count_bitarray_AND_t count_bitarray_AND_AVX512, count_bitarray_AND_AVX2, count_bitarray_AND_AVX, count_bitarray_AND_SSE2, count_bitarray_AND_MMX, count_bitarray_AND_NOSIMD, count_bitarray_AND_dispatch;
typedef uint32_t count_bitarray_low20_AND_t(uint32_t*, uint32_t*);
count_bitarray_low20_AND_t count_bitarray_low20_AND_AVX512, count_bitarray_low20_AND_AVX2, count_bitarray_low20_AND_AVX, count_bitarray_low20_AND_SSE2, count_bitarray_low20_AND_MMX, count_bitarray_low20_AND_NOSIMD, count_bitarray_low20_AND_dispatch;
typedef void bitarray_AND4_t(uint32_t*, uint32_t*, uint32_t*, uint32_t*);
bitarray_AND4_t bitarray_AND4_AVX512, bitarray_AND4_AVX2, bitarray_AND4_AVX, bitarray_AND4_SSE2, bitarray_AND4_MMX, bitarray_AND4_NOSIMD, bitarray_AND4_dispatch;
typedef void bitarray_OR_t(uint32_t[], uint32_t[]);
bitarray_OR_t bitarray_OR_AVX512, bitarray_OR_AVX2, bitarray_OR_AVX, bitarray_OR_SSE2, bitarray_OR_MMX, bitarray_OR_NOSIMD, bitarray_OR_dispatch;
typedef uint32_t count_bitarray_AND2_t(uint32_t*, uint32_t*);
count_bitarray_AND2_t count_bitarray_AND2_AVX512, count_bitarray_AND2_AVX2, count_bitarray_AND2_AVX, count_bitarray_AND2_SSE2, count_bitarray_AND2_MMX, count_bitarray_AND2_NOSIMD, count_bitarray_AND2_dispatch;
typedef uint32_t count_bitarray_AND3_t(uint32_t*, uint32_t*, uint32_t*);
count_bitarray_AND3_t count_bitarray_AND3_AVX512, count_bitarray_AND3_AVX2, count_bitarray_AND3_AVX, count_bitarray_AND3_SSE2, count_bitarray_AND3_MMX, count_bitarray_AND3_NOSIMD, count_bitarray_AND3_dispatch;
typedef uint32_t count_bitarray_AND4_t(uint32_t*, uint32_t*, uint32_t*, uint32_t*);
count_bitarray_AND4_t count_bitarray_AND4_AVX512, count_bitarray_AND4_AVX2, count_bitarray_AND4_AVX, count_bitarray_AND4_SSE2, count_bitarray_AND4_MMX, count_bitarray_AND4_NOSIMD, count_bitarray_AND4_dispatch;
inline uint32_t *MALLOC_BITARRAY(uint32_t x) {
#if defined (_WIN32)
return __builtin_assume_aligned(_aligned_malloc((x), __BIGGEST_ALIGNMENT__), __BIGGEST_ALIGNMENT__);
#elif defined (__APPLE__)
uint32_t *allocated_memory;
if (posix_memalign((void**) &allocated_memory, __BIGGEST_ALIGNMENT__, x)) {
return NULL;
} else {
return __builtin_assume_aligned(allocated_memory, __BIGGEST_ALIGNMENT__);
}
#else
return __builtin_assume_aligned(memalign(__BIGGEST_ALIGNMENT__, (x)), __BIGGEST_ALIGNMENT__);
#endif
}
inline void FREE_BITARRAY(uint32_t *x) {
#ifdef _WIN32
_aligned_free(x);
#else
free(x);
#endif
}
inline uint32_t BITCOUNT(uint32_t a) {
return __builtin_popcountl(a);
}
inline uint32_t COUNT_STATES(uint32_t *A) {
uint32_t count = 0;
for (uint32_t i = 0; i < (1 << 19); i++) {
count += BITCOUNT(A[i]);
}
return count;
}
inline void BITARRAY_AND(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];
}
}
inline void BITARRAY_LOW20_AND(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__);
for (uint32_t i = 0; i < (1 << 20); i++) {
if (!b[i]) {
a[i] = 0;
}
}
}
inline uint32_t COUNT_BITARRAY_AND(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 += BITCOUNT(A[i]);
}
return count;
}
inline uint32_t COUNT_BITARRAY_LOW20_AND(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 += BITCOUNT(a[i]);
}
return count;
}
inline void BITARRAY_AND4(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];
}
}
inline void BITARRAY_OR(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];
}
}
inline uint32_t COUNT_BITARRAY_AND2(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 += BITCOUNT(A[i] & B[i]);
}
return count;
}
inline uint32_t COUNT_BITARRAY_AND3(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 += BITCOUNT(A[i] & B[i] & C[i]);
}
return count;
}
inline uint32_t COUNT_BITARRAY_AND4(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 += BITCOUNT(A[i] & B[i] & C[i] & D[i]);
}
return count;
}
#ifndef __MMX__
// pointers to functions:
malloc_bitarray_t *malloc_bitarray_function_p = &malloc_bitarray_dispatch;
free_bitarray_t *free_bitarray_function_p = &free_bitarray_dispatch;
bitcount_t *bitcount_function_p = &bitcount_dispatch;
count_states_t *count_states_function_p = &count_states_dispatch;
bitarray_AND_t *bitarray_AND_function_p = &bitarray_AND_dispatch;
bitarray_low20_AND_t *bitarray_low20_AND_function_p = &bitarray_low20_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;
// determine the available instruction set at runtime and call the correct function
uint32_t *malloc_bitarray_dispatch(uint32_t x) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) malloc_bitarray_function_p = &malloc_bitarray_AVX512;
else if (__builtin_cpu_supports("avx2")) malloc_bitarray_function_p = &malloc_bitarray_AVX2;
#else
if (__builtin_cpu_supports("avx2")) malloc_bitarray_function_p = &malloc_bitarray_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) malloc_bitarray_function_p = &malloc_bitarray_AVX;
else if (__builtin_cpu_supports("sse2")) malloc_bitarray_function_p = &malloc_bitarray_SSE2;
else if (__builtin_cpu_supports("mmx")) malloc_bitarray_function_p = &malloc_bitarray_MMX;
else
#endif
#endif
malloc_bitarray_function_p = &malloc_bitarray_NOSIMD;
// call the most optimized function for this CPU
return (*malloc_bitarray_function_p)(x);
}
void free_bitarray_dispatch(uint32_t *x) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) free_bitarray_function_p = &free_bitarray_AVX512;
else if (__builtin_cpu_supports("avx2")) free_bitarray_function_p = &free_bitarray_AVX2;
#else
if (__builtin_cpu_supports("avx2")) free_bitarray_function_p = &free_bitarray_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) free_bitarray_function_p = &free_bitarray_AVX;
else if (__builtin_cpu_supports("sse2")) free_bitarray_function_p = &free_bitarray_SSE2;
else if (__builtin_cpu_supports("mmx")) free_bitarray_function_p = &free_bitarray_MMX;
else
#endif
#endif
free_bitarray_function_p = &free_bitarray_NOSIMD;
// call the most optimized function for this CPU
(*free_bitarray_function_p)(x);
}
uint32_t bitcount_dispatch(uint32_t a) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) bitcount_function_p = &bitcount_AVX512;
else if (__builtin_cpu_supports("avx2")) bitcount_function_p = &bitcount_AVX2;
#else
if (__builtin_cpu_supports("avx2")) bitcount_function_p = &bitcount_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) bitcount_function_p = &bitcount_AVX;
else if (__builtin_cpu_supports("sse2")) bitcount_function_p = &bitcount_SSE2;
else if (__builtin_cpu_supports("mmx")) bitcount_function_p = &bitcount_MMX;
else
#endif
#endif
bitcount_function_p = &bitcount_NOSIMD;
// call the most optimized function for this CPU
return (*bitcount_function_p)(a);
}
uint32_t count_states_dispatch(uint32_t *bitarray) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) count_states_function_p = &count_states_AVX512;
else if (__builtin_cpu_supports("avx2")) count_states_function_p = &count_states_AVX2;
#else
if (__builtin_cpu_supports("avx2")) count_states_function_p = &count_states_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) count_states_function_p = &count_states_AVX;
else if (__builtin_cpu_supports("sse2")) count_states_function_p = &count_states_SSE2;
else if (__builtin_cpu_supports("mmx")) count_states_function_p = &count_states_MMX;
else
#endif
#endif
count_states_function_p = &count_states_NOSIMD;
// call the most optimized function for this CPU
return (*count_states_function_p)(bitarray);
}
void bitarray_AND_dispatch(uint32_t *A, uint32_t *B) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) bitarray_AND_function_p = &bitarray_AND_AVX512;
else if (__builtin_cpu_supports("avx2")) bitarray_AND_function_p = &bitarray_AND_AVX2;
#else
if (__builtin_cpu_supports("avx2")) bitarray_AND_function_p = &bitarray_AND_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) bitarray_AND_function_p = &bitarray_AND_AVX;
else if (__builtin_cpu_supports("sse2")) bitarray_AND_function_p = &bitarray_AND_SSE2;
else if (__builtin_cpu_supports("mmx")) bitarray_AND_function_p = &bitarray_AND_MMX;
else
#endif
#endif
bitarray_AND_function_p = &bitarray_AND_NOSIMD;
// call the most optimized function for this CPU
(*bitarray_AND_function_p)(A, B);
}
void bitarray_low20_AND_dispatch(uint32_t *A, uint32_t *B) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) bitarray_low20_AND_function_p = &bitarray_low20_AND_AVX512;
else if (__builtin_cpu_supports("avx2")) bitarray_low20_AND_function_p = &bitarray_low20_AND_AVX2;
#else
if (__builtin_cpu_supports("avx2")) bitarray_low20_AND_function_p = &bitarray_low20_AND_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) bitarray_low20_AND_function_p = &bitarray_low20_AND_AVX;
else if (__builtin_cpu_supports("sse2")) bitarray_low20_AND_function_p = &bitarray_low20_AND_SSE2;
else if (__builtin_cpu_supports("mmx")) bitarray_low20_AND_function_p = &bitarray_low20_AND_MMX;
else
#endif
#endif
bitarray_low20_AND_function_p = &bitarray_low20_AND_NOSIMD;
// call the most optimized function for this CPU
(*bitarray_low20_AND_function_p)(A, B);
}
uint32_t count_bitarray_AND_dispatch(uint32_t *A, uint32_t *B) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) count_bitarray_AND_function_p = &count_bitarray_AND_AVX512;
else if (__builtin_cpu_supports("avx2")) count_bitarray_AND_function_p = &count_bitarray_AND_AVX2;
#else
if (__builtin_cpu_supports("avx2")) count_bitarray_AND_function_p = &count_bitarray_AND_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) count_bitarray_AND_function_p = &count_bitarray_AND_AVX;
else if (__builtin_cpu_supports("sse2")) count_bitarray_AND_function_p = &count_bitarray_AND_SSE2;
else if (__builtin_cpu_supports("mmx")) count_bitarray_AND_function_p = &count_bitarray_AND_MMX;
else
#endif
#endif
count_bitarray_AND_function_p = &count_bitarray_AND_NOSIMD;
// 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) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_AVX512;
else if (__builtin_cpu_supports("avx2")) count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_AVX2;
#else
if (__builtin_cpu_supports("avx2")) count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_AVX;
else if (__builtin_cpu_supports("sse2")) count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_SSE2;
else if (__builtin_cpu_supports("mmx")) count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_MMX;
else
#endif
#endif
count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_NOSIMD;
// 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) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) bitarray_AND4_function_p = &bitarray_AND4_AVX512;
else if (__builtin_cpu_supports("avx2")) bitarray_AND4_function_p = &bitarray_AND4_AVX2;
#else
if (__builtin_cpu_supports("avx2")) bitarray_AND4_function_p = &bitarray_AND4_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) bitarray_AND4_function_p = &bitarray_AND4_AVX;
else if (__builtin_cpu_supports("sse2")) bitarray_AND4_function_p = &bitarray_AND4_SSE2;
else if (__builtin_cpu_supports("mmx")) bitarray_AND4_function_p = &bitarray_AND4_MMX;
else
#endif
#endif
bitarray_AND4_function_p = &bitarray_AND4_NOSIMD;
// 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) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) bitarray_OR_function_p = &bitarray_OR_AVX512;
else if (__builtin_cpu_supports("avx2")) bitarray_OR_function_p = &bitarray_OR_AVX2;
#else
if (__builtin_cpu_supports("avx2")) bitarray_OR_function_p = &bitarray_OR_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) bitarray_OR_function_p = &bitarray_OR_AVX;
else if (__builtin_cpu_supports("sse2")) bitarray_OR_function_p = &bitarray_OR_SSE2;
else if (__builtin_cpu_supports("mmx")) bitarray_OR_function_p = &bitarray_OR_MMX;
else
#endif
#endif
bitarray_OR_function_p = &bitarray_OR_NOSIMD;
// 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) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) count_bitarray_AND2_function_p = &count_bitarray_AND2_AVX512;
else if (__builtin_cpu_supports("avx2")) count_bitarray_AND2_function_p = &count_bitarray_AND2_AVX2;
#else
if (__builtin_cpu_supports("avx2")) count_bitarray_AND2_function_p = &count_bitarray_AND2_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) count_bitarray_AND2_function_p = &count_bitarray_AND2_AVX;
else if (__builtin_cpu_supports("sse2")) count_bitarray_AND2_function_p = &count_bitarray_AND2_SSE2;
else if (__builtin_cpu_supports("mmx")) count_bitarray_AND2_function_p = &count_bitarray_AND2_MMX;
else
#endif
#endif
count_bitarray_AND2_function_p = &count_bitarray_AND2_NOSIMD;
// 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) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) count_bitarray_AND3_function_p = &count_bitarray_AND3_AVX512;
else if (__builtin_cpu_supports("avx2")) count_bitarray_AND3_function_p = &count_bitarray_AND3_AVX2;
#else
if (__builtin_cpu_supports("avx2")) count_bitarray_AND3_function_p = &count_bitarray_AND3_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) count_bitarray_AND3_function_p = &count_bitarray_AND3_AVX;
else if (__builtin_cpu_supports("sse2")) count_bitarray_AND3_function_p = &count_bitarray_AND3_SSE2;
else if (__builtin_cpu_supports("mmx")) count_bitarray_AND3_function_p = &count_bitarray_AND3_MMX;
else
#endif
#endif
count_bitarray_AND3_function_p = &count_bitarray_AND3_NOSIMD;
// 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) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) count_bitarray_AND4_function_p = &count_bitarray_AND4_AVX512;
else if (__builtin_cpu_supports("avx2")) count_bitarray_AND4_function_p = &count_bitarray_AND4_AVX2;
#else
if (__builtin_cpu_supports("avx2")) count_bitarray_AND4_function_p = &count_bitarray_AND4_AVX2;
#endif
else if (__builtin_cpu_supports("avx")) count_bitarray_AND4_function_p = &count_bitarray_AND4_AVX;
else if (__builtin_cpu_supports("sse2")) count_bitarray_AND4_function_p = &count_bitarray_AND4_SSE2;
else if (__builtin_cpu_supports("mmx")) count_bitarray_AND4_function_p = &count_bitarray_AND4_MMX;
else
#endif
#endif
count_bitarray_AND4_function_p = &count_bitarray_AND4_NOSIMD;
// call the most optimized function for this CPU
return (*count_bitarray_AND4_function_p)(A, B, C, D);
}
///////////////////////////////////////////////77
// Entries to dispatched function calls
uint32_t *malloc_bitarray(uint32_t x) {
return (*malloc_bitarray_function_p)(x);
}
void free_bitarray(uint32_t *x) {
(*free_bitarray_function_p)(x);
}
uint32_t bitcount(uint32_t a) {
return (*bitcount_function_p)(a);
}
uint32_t count_states(uint32_t *bitarray) {
return (*count_states_function_p)(bitarray);
}
void bitarray_AND(uint32_t *A, uint32_t *B) {
(*bitarray_AND_function_p)(A, B);
}
void bitarray_low20_AND(uint32_t *A, uint32_t *B) {
(*bitarray_low20_AND_function_p)(A, B);
}
uint32_t count_bitarray_AND(uint32_t *A, uint32_t *B) {
return (*count_bitarray_AND_function_p)(A, B);
}
uint32_t count_bitarray_low20_AND(uint32_t *A, uint32_t *B) {
return (*count_bitarray_low20_AND_function_p)(A, B);
}
void bitarray_AND4(uint32_t *A, uint32_t *B, uint32_t *C, uint32_t *D) {
(*bitarray_AND4_function_p)(A, B, C, D);
}
void bitarray_OR(uint32_t *A, uint32_t *B) {
(*bitarray_OR_function_p)(A, B);
}
uint32_t count_bitarray_AND2(uint32_t *A, uint32_t *B) {
return (*count_bitarray_AND2_function_p)(A, B);
}
uint32_t count_bitarray_AND3(uint32_t *A, uint32_t *B, uint32_t *C) {
return (*count_bitarray_AND3_function_p)(A, B, C);
}
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);
}
#endif

View File

@ -0,0 +1,69 @@
//-----------------------------------------------------------------------------
// 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.
*/
#ifndef HARDNESTED_BITARRAY_CORE_H__
#define HARDNESTED_BITARRAY_CORE_H__
#include <stdint.h>
extern uint32_t *malloc_bitarray(uint32_t x);
extern void free_bitarray(uint32_t *x);
extern uint32_t bitcount(uint32_t a);
extern uint32_t count_states(uint32_t *A);
extern void bitarray_AND(uint32_t *A, uint32_t *B);
extern void bitarray_low20_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);
#endif

View File

@ -0,0 +1,464 @@
//-----------------------------------------------------------------------------
// 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 <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
//#include "proxmark3.h"
#include "../cmdhfmfhard.h"
#include "hardnested_bf_core.h"
#include "../ui.h"
#include "../util.h"
#include "../util_posix.h"
#include "../crapto1.h"
#include "../parity.h"
#define NUM_BRUTE_FORCE_THREADS (num_CPUs())
#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
#define TEST_BENCH_FILENAME "hardnested/bf_bench_data.bin"
//#define WRITE_BENCH_FILE
// debugging options
#define DEBUG_KEY_ELIMINATION
// #define DEBUG_BRUTE_FORCE
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;
} *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) {
#if defined (DEBUG_BRUTE_FORCE)
printf("Thread %u starts working on bucket %u\n", thread_id, current_bucket);
#endif
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);
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0);
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);
}
}
}
current_bucket += NUM_BRUTE_FORCE_THREADS;
}
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;
// printf("Nonces to bruteforce: %d\n", nonces_to_bruteforce);
// printf("Common bits of first 4 2nd nonce bytes (before sorting): %u %u %u\n",
// trailing_zeros(bf_test_nonce_2nd_byte[1] ^ bf_test_nonce_2nd_byte[0]),
// trailing_zeros(bf_test_nonce_2nd_byte[2] ^ bf_test_nonce_2nd_byte[1]),
// trailing_zeros(bf_test_nonce_2nd_byte[3] ^ bf_test_nonce_2nd_byte[2]));
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
// && trailing_zeros(bf_test_nonce_2nd_byte[n1] ^ bf_test_nonce_2nd_byte[n2])
// > trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3])
) {
for (uint16_t n4 = 0; n4 < nonces_to_bruteforce; n4++) {
if ((n4 != n3 && n4 != n2 && n4 != n1) || nonces_to_bruteforce < 4
// && trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3])
// > trailing_zeros(bf_test_nonce_2nd_byte[n3] ^ bf_test_nonce_2nd_byte[n4])
) {
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];
}
}
#if defined (WRITE_BENCH_FILE)
static void write_benchfile(statelist_t *candidates) {
printf("Writing brute force benchmark data...");
FILE *benchfile = fopen(TEST_BENCH_FILENAME, "wb");
fwrite(&nonces_to_bruteforce, 1, sizeof (nonces_to_bruteforce), benchfile);
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
fwrite(&(bf_test_nonce[i]), 1, sizeof (bf_test_nonce[i]), benchfile);
fwrite(&(bf_test_nonce_par[i]), 1, sizeof (bf_test_nonce_par[i]), benchfile);
}
uint32_t num_states = MIN(candidates->len[EVEN_STATE], TEST_BENCH_SIZE);
fwrite(&num_states, 1, sizeof (num_states), benchfile);
for (uint32_t i = 0; i < num_states; i++) {
fwrite(&(candidates->states[EVEN_STATE][i]), 1, sizeof (uint32_t), benchfile);
}
num_states = MIN(candidates->len[ODD_STATE], TEST_BENCH_SIZE);
fwrite(&num_states, 1, sizeof (num_states), benchfile);
for (uint32_t i = 0; i < num_states; i++) {
fwrite(&(candidates->states[ODD_STATE][i]), 1, sizeof (uint32_t), benchfile);
}
fclose(benchfile);
printf("done.\n");
}
#endif
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) {
#if defined (WRITE_BENCH_FILE)
write_benchfile(candidates);
#endif
bool silent = (bf_rate != NULL);
// if (!silent) {
// PrintAndLog("Brute force phase starting.");
// PrintAndLog("Using %u-bit bitslices", MAX_BITSLICES);
// }
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++;
}
}
uint64_t start_time = msclock();
// enumerate states using all hardware threads, each thread handles one bucket
// if (!silent) {
// PrintAndLog("Starting %u cracking threads to search %u buckets containing a total of %" PRIu64" states...\n", NUM_BRUTE_FORCE_THREADS, bucket_count, maximum_states);
// printf("Common bits of first 4 2nd nonce bytes: %u %u %u\n",
// trailing_zeros(bf_test_nonce_2nd_byte[1] ^ bf_test_nonce_2nd_byte[0]),
// trailing_zeros(bf_test_nonce_2nd_byte[2] ^ bf_test_nonce_2nd_byte[1]),
// trailing_zeros(bf_test_nonce_2nd_byte[3] ^ bf_test_nonce_2nd_byte[2]));
// }
pthread_t threads[NUM_BRUTE_FORCE_THREADS];
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;
} thread_args[NUM_BRUTE_FORCE_THREADS];
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; 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;
pthread_create(&threads[i], NULL, crack_states_thread, (void*) &thread_args[i]);
}
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
pthread_join(threads[i], 0);
}
uint64_t elapsed_time = msclock() - start_time;
// if (!silent) {
// printf("Brute force completed after testing %" PRIu64" (2^%1.1f) keys in %1.1f seconds at a rate of %1.0f (2^%1.1f) keys per second.\n",
// num_keys_tested,
// log(num_keys_tested) / log(2.0),
// (float)elapsed_time/1000.0,
// (float)num_keys_tested / ((float)elapsed_time / 1000.0),
// log((float)num_keys_tested / ((float)elapsed_time/1000.0)) / log(2.0));
// }
if (bf_rate != NULL) {
*bf_rate = (float) num_keys_tested / ((float) elapsed_time / 1000.0);
}
return (keys_found != 0);
}
static bool read_bench_data(statelist_t *test_candidates) {
size_t bytes_read = 0;
uint32_t temp = 0;
uint32_t num_states = 0;
uint32_t states_read = 0;
char bench_file_path[strlen(".") + strlen(TEST_BENCH_FILENAME) + 1];
strcpy(bench_file_path, ".");
strcat(bench_file_path, TEST_BENCH_FILENAME);
FILE *benchfile = fopen(bench_file_path, "rb");
if (benchfile == NULL) {
return false;
}
bytes_read = fread(&nonces_to_bruteforce, 1, sizeof (nonces_to_bruteforce), benchfile);
if (bytes_read != sizeof (nonces_to_bruteforce)) {
fclose(benchfile);
return false;
}
for (uint16_t i = 0; i < nonces_to_bruteforce && i < 256; i++) {
bytes_read = fread(&bf_test_nonce[i], 1, sizeof (uint32_t), benchfile);
if (bytes_read != sizeof (uint32_t)) {
fclose(benchfile);
return false;
}
bf_test_nonce_2nd_byte[i] = (bf_test_nonce[i] >> 16) & 0xff;
bytes_read = fread(&bf_test_nonce_par[i], 1, sizeof (uint8_t), benchfile);
if (bytes_read != sizeof (uint8_t)) {
fclose(benchfile);
return false;
}
}
bytes_read = fread(&num_states, 1, sizeof (uint32_t), benchfile);
if (bytes_read != sizeof (uint32_t)) {
fclose(benchfile);
return false;
}
for (states_read = 0; states_read < MIN(num_states, TEST_BENCH_SIZE); states_read++) {
bytes_read = fread(test_candidates->states[EVEN_STATE] + states_read, 1, sizeof (uint32_t), benchfile);
if (bytes_read != sizeof (uint32_t)) {
fclose(benchfile);
return false;
}
}
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++) {
bytes_read = fread(&temp, 1, sizeof (uint32_t), benchfile);
if (bytes_read != sizeof (uint32_t)) {
fclose(benchfile);
return false;
}
}
for (states_read = 0; states_read < MIN(num_states, TEST_BENCH_SIZE); states_read++) {
bytes_read = fread(test_candidates->states[ODD_STATE] + states_read, 1, sizeof (uint32_t), benchfile);
if (bytes_read != sizeof (uint32_t)) {
fclose(benchfile);
return false;
}
}
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];
}
fclose(benchfile);
return true;
}
float brute_force_benchmark() {
statelist_t test_candidates[NUM_BRUTE_FORCE_THREADS];
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_BRUTE_FORCE_THREADS - 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_BRUTE_FORCE_THREADS - 1].next = NULL;
if (!read_bench_data(test_candidates)) {
PrintAndLog("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_BRUTE_FORCE_THREADS; 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_BRUTE_FORCE_THREADS;
float bf_rate;
brute_force_bs(&bf_rate, test_candidates, 0, 0, maximum_states, NULL, 0);
free(test_candidates[0].states[ODD_STATE]);
free(test_candidates[0].states[EVEN_STATE]);
return bf_rate;
}

View File

@ -0,0 +1,36 @@
//-----------------------------------------------------------------------------
// 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"
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);
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

67327
src/hardnested/tables.c Normal file

File diff suppressed because it is too large Load Diff

37
src/hardnested/tables.h Normal file
View File

@ -0,0 +1,37 @@
/*
* 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);
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 */

View File

@ -47,7 +47,7 @@
#include "crapto1.h"
// Internal
#include "config.h"
#include "../config.h"
#include "mifare.h"
#include "nfc-utils.h"
#include "mfoc.h"
@ -95,18 +95,18 @@ int main(int argc, char *const argv[])
// Array with default Mifare Classic keys
uint8_t defaultKeys[][6] = {
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // Default key (first key used by program if no user defined key)
{0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, // NFCForum MAD key
{0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, // NFCForum content key
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Blank key
{0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5},
{0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd},
{0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a},
{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
{0x71, 0x4c, 0x5c, 0x88, 0x6e, 0x97},
{0x58, 0x7e, 0xe5, 0xf9, 0x35, 0x0f},
{0xa0, 0x47, 0x8c, 0xc3, 0x90, 0x91},
{0x53, 0x3c, 0xb6, 0xc7, 0x23, 0xf6},
{0x8f, 0xd0, 0xa4, 0xf2, 0x56, 0xe9}
// {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, // NFCForum MAD key
// {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, // NFCForum content key
// {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Blank key
// {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5},
// {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd},
// {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a},
// {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
// {0x71, 0x4c, 0x5c, 0x88, 0x6e, 0x97},
// {0x58, 0x7e, 0xe5, 0xf9, 0x35, 0x0f},
// {0xa0, 0x47, 0x8c, 0xc3, 0x90, 0x91},
// {0x53, 0x3c, 0xb6, 0xc7, 0x23, 0xf6},
// {0x8f, 0xd0, 0xa4, 0xf2, 0x56, 0xe9}
};
@ -941,8 +941,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
uint32_t Nt, NtLast, NtProbe, NtEnc, Ks1;
int i;
uint32_t m;
uint32_t m, i;
uint8_t pbits = 0, p;
// Prepare AUTH command
Auth[0] = (t.sectors[e_sector].foundKeyA) ? MC_AUTH_A : MC_AUTH_B;
@ -1175,6 +1175,39 @@ 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;
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, 0x00, 0) ^ Auth[i];
// Encrypt the parity bits with the 4 plaintext bytes
AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]);
}
if (nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar, Rx, sizeof (Rx), RxPar) < 0) {
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;
}
// num_acquired_nonces += add_nonce(NtEnc, pbits);
}
crypto1_destroy(pcs);
return 0;
}

110
src/ui.c Normal file
View File

@ -0,0 +1,110 @@
//-----------------------------------------------------------------------------
// 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>
#ifndef EXTERNAL_PRINTANDLOG
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <readline/readline.h>
#include <pthread.h>
#endif
#include "ui.h"
double CursorScaleFactor = 1;
int PlotGridX = 0, PlotGridY = 0, PlotGridXdefault = 64, PlotGridYdefault = 64, CursorCPos = 0, CursorDPos = 0;
bool flushAfterWrite = false; //buzzy
int GridOffset = 0;
bool GridLocked = false;
bool showDemod = true;
static char *logfilename = "proxmark3.log";
#ifndef EXTERNAL_PRINTANDLOG
static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
void PrintAndLog(char *fmt, ...) {
char *saved_line;
int saved_point;
va_list argptr, argptr2;
static FILE *logfile = NULL;
static int logging = 1;
// lock this section to avoid interlacing prints from different threads
pthread_mutex_lock(&print_lock);
if (logging && !logfile) {
logfile = fopen(logfilename, "a");
if (!logfile) {
fprintf(stderr, "Can't open logfile, logging disabled!\n");
logging = 0;
}
}
// If there is an incoming message from the hardware (eg: lf hid read) in
// the background (while the prompt is displayed and accepting user input),
// stash the prompt and bring it back later.
#ifdef RL_STATE_READCMD
// We are using GNU readline. libedit (OSX) doesn't support this flag.
int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0;
if (need_hack) {
saved_point = rl_point;
saved_line = rl_copy_text(0, rl_end);
rl_save_prompt();
rl_replace_line("", 0);
rl_redisplay();
}
#endif
va_start(argptr, fmt);
va_copy(argptr2, argptr);
vprintf(fmt, argptr);
printf(" "); // cleaning prompt
va_end(argptr);
printf("\n");
#ifdef RL_STATE_READCMD
// We are using GNU readline. libedit (OSX) doesn't support this flag.
if (need_hack) {
rl_restore_prompt();
rl_replace_line(saved_line, 0);
rl_point = saved_point;
rl_redisplay();
free(saved_line);
}
#endif
if (logging && logfile) {
vfprintf(logfile, fmt, argptr2);
fprintf(logfile, "\n");
fflush(logfile);
}
va_end(argptr2);
if (flushAfterWrite) //buzzy
{
fflush(NULL);
}
//release lock
pthread_mutex_unlock(&print_lock);
}
#endif
void SetLogFilename(char *fn) {
logfilename = fn;
}
void SetFlushAfterWrite(bool flush_after_write) {
flushAfterWrite = flush_after_write;
}

30
src/ui.h Normal file
View File

@ -0,0 +1,30 @@
//-----------------------------------------------------------------------------
// 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 ShowGui(void);
void HideGraphWindow(void);
void ShowGraphWindow(void);
void RepaintGraphWindow(void);
void PrintAndLog(char *fmt, ...);
void SetLogFilename(char *fn);
void SetFlushAfterWrite(bool flush_after_write);
extern double CursorScaleFactor;
extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, CursorCPos, CursorDPos, GridOffset;
extern bool GridLocked;
extern bool showDemod;
#endif

666
src/util.c Normal file
View File

@ -0,0 +1,666 @@
//-----------------------------------------------------------------------------
// 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 <stdint.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#endif
#define MAX_BIN_BREAK_LENGTH (3072+384+1)
#ifndef _WIN32
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
int ukbhit(void) {
int cnt = 0;
int error;
static struct termios Otty, Ntty;
if (tcgetattr(STDIN_FILENO, &Otty) == -1) return -1;
Ntty = Otty;
Ntty.c_iflag = 0x0000; // input mode
Ntty.c_oflag = 0x0000; // output mode
Ntty.c_lflag &= ~ICANON; // control mode = raw
Ntty.c_cc[VMIN] = 1; // return if at least 1 character is in the queue
Ntty.c_cc[VTIME] = 0; // no timeout. Wait forever
if (0 == (error = tcsetattr(STDIN_FILENO, TCSANOW, &Ntty))) { // set new attributes
error += ioctl(STDIN_FILENO, FIONREAD, &cnt); // get number of characters availabe
error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes
}
return ( error == 0 ? cnt : -1);
}
#else
#include <conio.h>
int ukbhit(void) {
return kbhit();
}
#endif
// log files functions
void AddLogLine(char *file, char *extData, char *c) {
FILE *fLog = NULL;
char filename[FILE_PATH_SIZE] = {0x00};
int len = 0;
len = strlen(file);
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
memcpy(filename, file, len);
fLog = fopen(filename, "a");
if (!fLog) {
printf("Could not append log file %s", filename);
return;
}
fprintf(fLog, "%s", extData);
fprintf(fLog, "%s\n", c);
fclose(fLog);
}
void AddLogHex(char *fileName, char *extData, const uint8_t * data, const size_t len) {
AddLogLine(fileName, extData, sprint_hex(data, len));
}
void AddLogUint64(char *fileName, char *extData, const uint64_t data) {
char buf[100] = {0};
sprintf(buf, "%x%x", (unsigned int) ((data & 0xFFFFFFFF00000000) >> 32), (unsigned int) (data & 0xFFFFFFFF));
AddLogLine(fileName, extData, buf);
}
void AddLogCurrentDT(char *fileName) {
char buff[20];
struct tm *curTime;
time_t now = time(0);
curTime = gmtime(&now);
strftime(buff, sizeof (buff), "%Y-%m-%d %H:%M:%S", curTime);
AddLogLine(fileName, "\nanticollision: ", buff);
}
void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount) {
char * fnameptr = fileName;
memset(fileName, 0x00, 200);
for (int j = 0; j < byteCount; j++, fnameptr += 2)
sprintf(fnameptr, "%02x", (unsigned int) uid[j]);
sprintf(fnameptr, "%s", ext);
}
void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len,
const size_t min_str_len, const size_t spaces_between, bool uppercase) {
char *tmp = (char *) buf;
size_t i;
memset(tmp, 0x00, hex_max_len);
int maxLen = (hex_len > hex_max_len) ? hex_max_len : hex_len;
for (i = 0; i < maxLen; ++i, tmp += 2 + spaces_between) {
sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]);
for (int j = 0; j < spaces_between; j++)
sprintf(tmp + 2 + j, " ");
}
i *= (2 + spaces_between);
int minStrLen = min_str_len > i ? min_str_len : 0;
if (minStrLen > hex_max_len)
minStrLen = hex_max_len;
for (; i < minStrLen; i++, tmp += 1)
sprintf(tmp, " ");
return;
}
// printing and converting functions
char *sprint_hex(const uint8_t *data, const size_t len) {
static char buf[1025] = {0};
hex_to_buffer((uint8_t *) buf, data, len, sizeof (buf) - 1, 0, 1, false);
return buf;
}
char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len) {
static char buf[1025] = {0};
hex_to_buffer((uint8_t *) buf, data, len, sizeof (buf) - 1, min_str_len, 0, false);
return buf;
}
char *sprint_hex_inrow(const uint8_t *data, const size_t len) {
return sprint_hex_inrow_ex(data, len, 0);
}
char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks) {
// make sure we don't go beyond our char array memory
int max_len;
if (breaks == 0)
max_len = (len > MAX_BIN_BREAK_LENGTH) ? MAX_BIN_BREAK_LENGTH : len;
else
max_len = (len + (len / breaks) > MAX_BIN_BREAK_LENGTH) ? MAX_BIN_BREAK_LENGTH : len + (len / breaks);
static char buf[MAX_BIN_BREAK_LENGTH]; // 3072 + end of line characters if broken at 8 bits
//clear memory
memset(buf, 0x00, sizeof (buf));
char *tmp = buf;
size_t in_index = 0;
// loop through the out_index to make sure we don't go too far
for (size_t out_index = 0; out_index < max_len; out_index++) {
// set character - (should be binary but verify it isn't more than 1 digit)
if (data[in_index] < 10)
sprintf(tmp++, "%u", (unsigned int) data[in_index]);
// check if a line break is needed and we have room to print it in our array
if ((breaks > 0) && !((in_index + 1) % breaks) && (out_index + 1 < max_len)) {
// increment and print line break
out_index++;
sprintf(tmp++, "%s", "\n");
}
in_index++;
}
return buf;
}
char *sprint_bin(const uint8_t *data, const size_t len) {
return sprint_bin_break(data, len, 0);
}
char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len) {
static char buf[1024];
char *tmp = buf;
memset(buf, 0x00, 1024);
size_t max_len = (len > 1010) ? 1010 : len;
size_t i = 0;
while (i < max_len) {
char c = data[i];
tmp[i] = ((c < 32) || (c == 127)) ? '.' : c;
++i;
}
int minStrLen = min_str_len > i ? min_str_len : 0;
for (; i < minStrLen; ++i)
tmp[i] = ' ';
return buf;
}
//least significant bit first
void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) {
for (int i = 0; i < len; ++i) {
dest[i] = n & 1;
n >>= 1;
}
}
// Swap bit order on a uint32_t value. Can be limited by nrbits just use say 8bits reversal
// And clears the rest of the bits.
uint32_t SwapBits(uint32_t value, int nrbits) {
uint32_t newvalue = 0;
for (int i = 0; i < nrbits; i++) {
newvalue ^= ((value >> i) & 1) << (nrbits - 1 - i);
}
return newvalue;
}
// aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp
// to
// hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii
// up to 64 bytes or 512 bits
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize) {
static uint8_t buf[64];
memset(buf, 0x00, 64);
uint8_t *tmp = buf;
for (uint8_t block = 0; block < (uint8_t) (len / blockSize); block++) {
for (size_t i = 0; i < blockSize; i++) {
tmp[i + (blockSize * block)] = src[(blockSize - 1 - i)+(blockSize * block)];
}
}
return tmp;
}
//assumes little endian
char * printBits(size_t const size, void const * const ptr) {
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
static char buf[1024];
char * tmp = buf;
int i, j;
for (i = size - 1; i >= 0; i--) {
for (j = 7; j >= 0; j--) {
byte = b[i] & (1 << j);
byte >>= j;
sprintf(tmp, "%u", (unsigned int) byte);
tmp++;
}
}
return buf;
}
char * printBitsPar(const uint8_t *b, size_t len) {
static char buf1[512] = {0};
static char buf2[512] = {0};
static char *buf;
if (buf != buf1)
buf = buf1;
else
buf = buf2;
memset(buf, 0x00, 512);
for (int i = 0; i < len; i++) {
buf[i] = ((b[i / 8] << (i % 8)) & 0x80) ? '1' : '0';
}
return buf;
}
// -------------------------------------------------------------------------
// string parameters lib
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// line - param line
// bg, en - symbol numbers in param line of beginning and ending parameter
// paramnum - param number (from 0)
// -------------------------------------------------------------------------
int param_getptr(const char *line, int *bg, int *en, int paramnum) {
int i;
int len = strlen(line);
*bg = 0;
*en = 0;
// skip spaces
while (line[*bg] == ' ' || line[*bg] == '\t') (*bg)++;
if (*bg >= len) {
return 1;
}
for (i = 0; i < paramnum; i++) {
while (line[*bg] != ' ' && line[*bg] != '\t' && line[*bg] != '\0') (*bg)++;
while (line[*bg] == ' ' || line[*bg] == '\t') (*bg)++;
if (line[*bg] == '\0') return 1;
}
*en = *bg;
while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0') (*en)++;
(*en)--;
return 0;
}
int param_getlength(const char *line, int paramnum) {
int bg, en;
if (param_getptr(line, &bg, &en, paramnum)) return 0;
return en - bg + 1;
}
char param_getchar(const char *line, int paramnum) {
return param_getchar_indx(line, 0, paramnum);
}
char param_getchar_indx(const char *line, int indx, int paramnum) {
int bg, en;
if (param_getptr(line, &bg, &en, paramnum)) return 0x00;
if (bg + indx > en)
return '\0';
return line[bg + indx];
}
uint8_t param_get8(const char *line, int paramnum) {
return param_get8ex(line, paramnum, 0, 10);
}
/**
* @brief Reads a decimal integer (actually, 0-254, not 255)
* @param line
* @param paramnum
* @return -1 if error
*/
uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination) {
uint8_t val = param_get8ex(line, paramnum, 255, 10);
if ((int8_t) val == -1) return 1;
(*destination) = val;
return 0;
}
/**
* @brief Checks if param is decimal
* @param line
* @param paramnum
* @return
*/
uint8_t param_isdec(const char *line, int paramnum) {
int bg, en;
//TODO, check more thorougly
if (!param_getptr(line, &bg, &en, paramnum)) return 1;
// return strtoul(&line[bg], NULL, 10) & 0xff;
return 0;
}
uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base) {
int bg, en;
if (!param_getptr(line, &bg, &en, paramnum))
return strtoul(&line[bg], NULL, base) & 0xff;
else
return deflt;
}
uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base) {
int bg, en;
if (!param_getptr(line, &bg, &en, paramnum))
return strtoul(&line[bg], NULL, base);
else
return deflt;
}
uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base) {
int bg, en;
if (!param_getptr(line, &bg, &en, paramnum))
return strtoull(&line[bg], NULL, base);
else
return deflt;
}
int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt) {
int bg, en, temp, i;
if (hexcnt % 2)
return 1;
if (param_getptr(line, &bg, &en, paramnum)) return 1;
if (en - bg + 1 != hexcnt)
return 1;
for (i = 0; i < hexcnt; i += 2) {
if (!(isxdigit((unsigned char) line[bg + i]) && isxdigit((unsigned char) line[bg + i + 1]))) return 1;
sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp);
data[i / 2] = temp & 0xff;
}
return 0;
}
int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt) {
int bg, en, temp, i;
//if (hexcnt % 2)
// return 1;
if (param_getptr(line, &bg, &en, paramnum)) return 1;
*hexcnt = en - bg + 1;
if (*hexcnt % 2) //error if not complete hex bytes
return 1;
for (i = 0; i < *hexcnt; i += 2) {
if (!(isxdigit((unsigned char) line[bg + i]) && isxdigit((unsigned char) line[bg + i + 1]))) return 1;
sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp);
data[i / 2] = temp & 0xff;
}
return 0;
}
int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxdatalen, int *datalen) {
int bg, en;
uint32_t temp;
char buf[5] = {0};
if (param_getptr(line, &bg, &en, paramnum)) return 1;
*datalen = 0;
int indx = bg;
while (line[indx]) {
if (line[indx] == '\t' || line[indx] == ' ') {
indx++;
continue;
}
if (isxdigit((unsigned char) line[indx])) {
buf[strlen(buf) + 1] = 0x00;
buf[strlen(buf)] = line[indx];
} else {
// if we have symbols other than spaces and hex
return 1;
}
if (*datalen >= maxdatalen) {
// if we dont have space in buffer and have symbols to translate
return 2;
}
if (strlen(buf) >= 2) {
sscanf(buf, "%x", &temp);
data[*datalen] = (uint8_t) (temp & 0xff);
*buf = 0;
(*datalen)++;
}
indx++;
}
if (strlen(buf) > 0)
//error when not completed hex bytes
return 3;
return 0;
}
int param_getstr(const char *line, int paramnum, char * str, size_t buffersize) {
int bg, en;
if (param_getptr(line, &bg, &en, paramnum)) {
return 0;
}
// Prevent out of bounds errors
if (en - bg + 1 >= buffersize) {
printf("out of bounds error: want %d bytes have %zd bytes\n", en - bg + 1 + 1, buffersize);
return 0;
}
memcpy(str, line + bg, en - bg + 1);
str[en - bg + 1] = 0;
return en - bg + 1;
}
/*
The following methods comes from Rfidler sourcecode.
https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/
*/
// convert hex to sequence of 0/1 bit values
// returns number of bits converted
int hextobinarray(char *target, char *source) {
int length, i, count = 0;
char* start = source;
char x;
length = strlen(source);
// process 4 bits (1 hex digit) at a time
while (length--) {
x = *(source++);
// capitalize
if (x >= 'a' && x <= 'f')
x -= 32;
// convert to numeric value
if (x >= '0' && x <= '9')
x -= '0';
else if (x >= 'A' && x <= 'F')
x -= 'A' - 10;
else {
printf("Discovered unknown character %c %d at idx %tu of %s\n", x, x, source - start, start);
return 0;
}
// output
for (i = 0; i < 4; ++i, ++count)
*(target++) = (x >> (3 - i)) & 1;
}
return count;
}
// convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source)
// return number of bits converted
int binarraytohex(char *target, char *source, int length) {
unsigned char i, x;
int j = length;
if (j % 4)
return 0;
while (j) {
for (i = x = 0; i < 4; ++i)
x += (source[i] << (3 - i));
sprintf(target, "%X", (unsigned int) x);
++target;
source += 4;
j -= 4;
}
return length;
}
// return parity bit required to match type
uint8_t GetParity(uint8_t *bits, uint8_t type, int length) {
int x;
for (x = 0; length > 0; --length)
x += bits[length - 1];
x %= 2;
return x ^ type;
}
// add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half
void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length) {
*(target++) = GetParity(source, EVEN, length / 2);
memcpy(target, source, length);
target += length;
*(target) = GetParity(source + length / 2, ODD, length / 2);
}
// xor two arrays together for len items. The dst array contains the new xored values.
void xor(unsigned char *dst, unsigned char *src, size_t len) {
for (; len > 0; len--, dst++, src++)
*dst ^= *src;
}
// RotateLeft - Ultralight, Desfire, works on byte level
// 00-01-02 >> 01-02-00
void rol(uint8_t *data, const size_t len) {
uint8_t first = data[0];
for (size_t i = 0; i < len - 1; i++) {
data[i] = data[i + 1];
}
data[len - 1] = first;
}
// Replace unprintable characters with a dot in char buffer
void clean_ascii(unsigned char *buf, size_t len) {
for (size_t i = 0; i < len; i++) {
if (!isprint(buf[i]))
buf[i] = '.';
}
}
// replace \r \n to \0
void strcleanrn(char *buf, size_t len) {
strcreplace(buf, len, '\n', '\0');
strcreplace(buf, len, '\r', '\0');
}
// replace char in buffer
void strcreplace(char *buf, size_t len, char from, char to) {
for (size_t i = 0; i < len; i++) {
if (buf[i] == from)
buf[i] = to;
}
}
char *strmcopy(char *buf) {
char * str = NULL;
if ((str = (char*) malloc(strlen(buf) + 1)) != NULL) {
memset(str, 0, strlen(buf) + 1);
strcpy(str, buf);
}
return str;
}
// determine number of logical CPU cores (use for multithreaded functions)
extern int num_CPUs(void) {
#if defined(_WIN32)
#include <sysinfoapi.h>
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#elif defined(__linux__) || defined(__APPLE__)
#include <unistd.h>
return sysconf(_SC_NPROCESSORS_ONLN);
#else
return 1;
#endif
}

95
src/util.h Normal file
View File

@ -0,0 +1,95 @@
//-----------------------------------------------------------------------------
// 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>
#ifndef ROTR
#define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
#endif
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef arraylen
#define arraylen(x) (sizeof(x)/sizeof((x)[0]))
#endif
#define EVEN 0
#define ODD 1
#ifndef FILE_PATH_SIZE
#define FILE_PATH_SIZE 2000
#endif
extern int ukbhit(void);
extern void AddLogLine(char *fileName, char *extData, char *c);
extern void AddLogHex(char *fileName, char *extData, const uint8_t * data, const size_t len);
extern void AddLogUint64(char *fileName, char *extData, const uint64_t data);
extern void AddLogCurrentDT(char *fileName);
extern void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount);
extern void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len,
const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase);
extern char *sprint_hex(const uint8_t * data, const size_t len);
extern char *sprint_hex_inrow(const uint8_t *data, const size_t len);
extern char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len);
extern char *sprint_bin(const uint8_t * data, const size_t len);
extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks);
extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len);
extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
extern uint64_t bytes_to_num(uint8_t* src, size_t len);
extern void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
extern void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
extern char *printBits(size_t const size, void const * const ptr);
extern char * printBitsPar(const uint8_t *b, size_t len);
extern uint32_t SwapBits(uint32_t value, int nrbits);
extern uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
extern int param_getlength(const char *line, int paramnum);
extern char param_getchar(const char *line, int paramnum);
extern char param_getchar_indx(const char *line, int indx, int paramnum);
extern int param_getptr(const char *line, int *bg, int *en, int paramnum);
extern uint8_t param_get8(const char *line, int paramnum);
extern uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base);
extern uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base);
extern uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base);
extern uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination);
extern uint8_t param_isdec(const char *line, int paramnum);
extern int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
extern int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt);
extern int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxdatalen, int *datalen);
extern int param_getstr(const char *line, int paramnum, char * str, size_t buffersize);
extern int hextobinarray(char *target, char *source);
extern int binarraytohex(char *target, char *source, int length);
extern uint8_t GetParity(uint8_t *string, uint8_t type, int length);
extern void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length);
extern void xor(unsigned char *dst, unsigned char *src, size_t len);
extern void rol(uint8_t *data, const size_t len);
extern void clean_ascii(unsigned char *buf, size_t len);
void strcleanrn(char *buf, size_t len);
void strcreplace(char *buf, size_t len, char from, char to);
char *strmcopy(char *buf);
extern int num_CPUs(void); // number of logical CPUs
#endif // UTIL_H__

135
src/util_posix.c Normal file
View File

@ -0,0 +1,135 @@
//-----------------------------------------------------------------------------
// 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>
#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)
#include <sys/types.h>
// WORKAROUND FOR MinGW (some versions - use if normal code does not compile)
// It has no _ftime_s and needs explicit inclusion of timeb.h
#include <sys/timeb.h>
struct _timeb t;
_ftime(&t);
return 1000 * (uint64_t) t.time + t.millitm;
// NORMAL CODE (use _ftime_s)
//struct _timeb t;
//if (_ftime_s(&t)) {
// return 0;
//} else {
// return 1000 * 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