Bring hitag2crack tools in main Makefiles

This commit is contained in:
Philippe Teuwen 2020-05-22 19:20:44 +02:00
commit 6d33c0b784
21 changed files with 433 additions and 168 deletions

View file

@ -15,6 +15,8 @@ ifneq (,$(DESTDIR))
endif endif
all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/% mf_nonce_brute/% fpga_compress/% all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/% mf_nonce_brute/% fpga_compress/%
# hitag2crack toolsuite is not yet integrated in "all", it must be called explicitly: "make hitag2crack"
#all clean install uninstall check: %: hitag2crack/%
INSTALLTOOLS=pm3_eml2lower.sh pm3_eml2upper.sh pm3_mfdread.py pm3_mfd2eml.py pm3_eml2mfd.py findbits.py rfidtest.pl xorcheck.py INSTALLTOOLS=pm3_eml2lower.sh pm3_eml2upper.sh pm3_mfdread.py pm3_mfd2eml.py pm3_eml2mfd.py findbits.py rfidtest.pl xorcheck.py
INSTALLSIMFW=sim011.bin sim011.sha512.txt INSTALLSIMFW=sim011.bin sim011.sha512.txt
@ -103,6 +105,9 @@ client/check: FORCE
recovery/check: FORCE recovery/check: FORCE
$(info [*] CHECK $(patsubst %/check,%,$@)) $(info [*] CHECK $(patsubst %/check,%,$@))
$(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@) $(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@)
hitag2crack/check: FORCE
$(info [*] CHECK $(patsubst %/check,%,$@))
$(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@)
common/check: FORCE common/check: FORCE
$(info [*] CHECK $(patsubst %/check,%,$@)) $(info [*] CHECK $(patsubst %/check,%,$@))
$(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@) $(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@)
@ -135,9 +140,12 @@ recovery/install: bootrom/all armsrc/all
recovery/%: FORCE cleanifplatformchanged recovery/%: FORCE cleanifplatformchanged
$(info [*] MAKE $@) $(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C recovery $(patsubst recovery/%,%,$@) DESTDIR=$(MYDESTDIR) $(Q)$(MAKE) --no-print-directory -C recovery $(patsubst recovery/%,%,$@) DESTDIR=$(MYDESTDIR)
hitag2crack/%: FORCE
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C tools/hitag2crack $(patsubst hitag2crack/%,%,$@) DESTDIR=$(MYDESTDIR)
FORCE: # Dummy target to force remake in the subdirectories, even if files exist (this Makefile doesn't know about the prerequisites) FORCE: # Dummy target to force remake in the subdirectories, even if files exist (this Makefile doesn't know about the prerequisites)
.PHONY: all clean install uninstall help _test bootrom fullimage recovery client mfkey nonce2key mf_nonce_brute style miscchecks release FORCE udev accessrights cleanifplatformchanged .PHONY: all clean install uninstall help _test bootrom fullimage recovery client mfkey nonce2key mf_nonce_brute hitag2crack style miscchecks release FORCE udev accessrights cleanifplatformchanged
help: help:
@echo "Multi-OS Makefile" @echo "Multi-OS Makefile"
@ -157,6 +165,7 @@ help:
@echo "+ mfkey - Make tools/mfkey" @echo "+ mfkey - Make tools/mfkey"
@echo "+ nonce2key - Make tools/nonce2key" @echo "+ nonce2key - Make tools/nonce2key"
@echo "+ mf_nonce_brute - Make tools/mf_nonce_brute" @echo "+ mf_nonce_brute - Make tools/mf_nonce_brute"
@echo "+ hitag2crack - Make tools/hitag2crack"
@echo "+ fpga_compress - Make tools/fpga_compress" @echo "+ fpga_compress - Make tools/fpga_compress"
@echo @echo
@echo "+ style - Apply some automated source code formatting rules" @echo "+ style - Apply some automated source code formatting rules"
@ -193,6 +202,8 @@ mf_nonce_brute: mf_nonce_brute/all
fpga_compress: fpga_compress/all fpga_compress: fpga_compress/all
hitag2crack: hitag2crack/all
newtarbin: newtarbin:
$(RM) proxmark3-$(platform)-bin.tar proxmark3-$(platform)-bin.tar.gz $(RM) proxmark3-$(platform)-bin.tar proxmark3-$(platform)-bin.tar.gz
@touch proxmark3-$(platform)-bin.tar @touch proxmark3-$(platform)-bin.tar

View file

@ -72,6 +72,10 @@ On some architectures, pthread library is not present:
* `make client SKIPPTHREAD=1` to skip `-lpthread` at linker stage. * `make client SKIPPTHREAD=1` to skip `-lpthread` at linker stage.
One tool requires a CUDA compilation environment, it can be skipped as well:
* `make hitag2crack SKIPGPU=1` to skip ht2crack5gpu tool when compiling the hitag2crack toolsuite.
Some unittests are available via `make check`, which is actually triggering individual targets as for `make install`. Some unittests are available via `make check`, which is actually triggering individual targets as for `make install`.
`make install` is actually triggering the following individual targets which can be accessed individually: `make install` is actually triggering the following individual targets which can be accessed individually:

View file

@ -0,0 +1,33 @@
# Must be called before any Makefile include
ROOT_DIR:=$(dir $(realpath $(lastword $(MAKEFILE_LIST))))
include ../../Makefile.defs
all clean install uninstall check: %: crack2/% crack3/% crack4/% crack5/%
ifneq ($(SKIPGPU),1)
all clean install uninstall check: %: crack5gpu/%
endif
crack2/%: FORCE
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C crack2 $(patsubst crack2/%,%,$@) DESTDIR=$(MYDESTDIR)
crack3/%: FORCE
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C crack3 $(patsubst crack3/%,%,$@) DESTDIR=$(MYDESTDIR)
crack4/%: FORCE
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C crack4 $(patsubst crack4/%,%,$@) DESTDIR=$(MYDESTDIR)
crack5/%: FORCE
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C crack5 $(patsubst crack5/%,%,$@) DESTDIR=$(MYDESTDIR)
crack5gpu/%: FORCE
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C crack5gpu $(patsubst crack5gpu/%,%,$@) DESTDIR=$(MYDESTDIR)
FORCE: # Dummy target to force remake in the subdirectories, even if files exist (this Makefile doesn't know about the prerequisites)
.phony: crack2 crack3 crack4 crack5 crack5gpu FORCE

View file

@ -1,3 +1,6 @@
#ifndef HT2CRACKUTILS_H
#define HT2CRACKUTILS_H
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
@ -41,3 +44,5 @@ void buildlfsr(Hitag_State *hstate);
#define rev64(X) (rev32(X) + (rev32(X >> 32) << 32)) #define rev64(X) (rev32(X) + (rev32(X >> 32) << 32))
unsigned long hexreversetoulong(char *hex); unsigned long hexreversetoulong(char *hex);
unsigned long long hexreversetoulonglong(char *hex); unsigned long long hexreversetoulonglong(char *hex);
#endif /* HT2CRACKUTILS_H */

View file

@ -1,23 +1,22 @@
CFLAGS?=-Wall -Werror -O3 MYSRCPATHS = ../common
# Linux libs MYSRCS = ht2crackutils.c hitagcrypto.c
LIBS=-pthread -D_GNU_SOURCE MYINCLUDES =-I ../common
# Mac libs MYCFLAGS = -D_GNU_SOURCE
# LIBS= MYDEFS =
VPATH=../common MYLDLIBS = -lpthread
INC=-I ../common
all: ht2crack2buildtable.c ht2crack2search.c ht2crack2gentest.c hitagcrypto.o ht2crackutils.o BINS = ht2crack2buildtable ht2crack2search ht2crack2gentest
$(CC) $(CFLAGS) $(INC) -o ht2crack2buildtable ht2crack2buildtable.c hitagcrypto.o ht2crackutils.o $(LIBS) INSTALLTOOLS = $(BINS)
$(CC) $(CFLAGS) $(INC) -o ht2crack2search ht2crack2search.c hitagcrypto.o ht2crackutils.o $(LIBS)
$(CC) $(CFLAGS) $(INC) -o ht2crack2gentest ht2crack2gentest.c hitagcrypto.o ht2crackutils.o $(LIBS)
ht2crackutils.o: ht2crackutils.c ht2crackutils.h include ../../../Makefile.host
$(CC) $(CFLAGS) -c $<
hitagcrypto.o: hitagcrypto.c hitagcrypto.h # checking platform can be done only after Makefile.host
$(CC) $(CFLAGS) -c $< ifneq (,$(findstring MINGW,$(platform)))
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
CFLAGS += -D_ISOC99_SOURCE
endif
clean: ht2crack2buildtable : $(OBJDIR)/ht2crack2buildtable.o $(MYOBJS)
rm -rf *.o ht2crack2buildtable ht2crack2search ht2crack2gentest ht2crack2search : $(OBJDIR)/ht2crack2search.o $(MYOBJS)
ht2crack2gentest : $(OBJDIR)/ht2crack2gentest.o $(MYOBJS)
fresh: clean all

View file

@ -4,7 +4,7 @@
*/ */
#include "ht2crackutils.h" #include "ht2crackutils.h"
#include <stdlib.h>
// DATAMAX is the size of each bucket (bytes). There are 65536 buckets so choose a value such that // DATAMAX is the size of each bucket (bytes). There are 65536 buckets so choose a value such that
// DATAMAX * 65536 < RAM available. For ex, if you want to use 12GB of RAM (for a 16GB machine // DATAMAX * 65536 < RAM available. For ex, if you want to use 12GB of RAM (for a 16GB machine
@ -53,63 +53,63 @@ uint64_t d2[48];
int nsteps2; int nsteps2;
// create table entry // create table entry
void create_table(struct table *t, int d1, int d2) { static void create_table(struct table *tt, int d_1, int d_2) {
if (!t) { if (!tt) {
printf("create_table: t is NULL\n"); printf("create_table: t is NULL\n");
exit(1); exit(1);
} }
// create some space // create some space
t->data = (unsigned char *)malloc(DATAMAX); tt->data = (unsigned char *)malloc(DATAMAX);
if (!(t->data)) { if (!(tt->data)) {
printf("create_table: cannot malloc data\n"); printf("create_table: cannot malloc data\n");
exit(1); exit(1);
} }
// set data ptr to start of data table // set data ptr to start of data table
t->ptr = t->data; tt->ptr = tt->data;
// init the mutex // init the mutex
if (pthread_mutex_init(&(t->mutex), NULL)) { if (pthread_mutex_init(&(tt->mutex), NULL)) {
printf("create_table: cannot init mutex\n"); printf("create_table: cannot init mutex\n");
exit(1); exit(1);
} }
// create the path // create the path
// sprintf(t->path, "/Volumes/2tb/%02X/%02X.bin", d1 & 0xff, d2 & 0xff); // sprintf(tt->path, "/Volumes/2tb/%02X/%02X.bin", d_1 & 0xff, d_2 & 0xff);
sprintf(t->path, "table/%02x/%02x.bin", d1 & 0xff, d2 & 0xff); sprintf(tt->path, "table/%02x/%02x.bin", d_1 & 0xff, d_2 & 0xff);
} }
// create all table entries // create all table entries
void create_tables(struct table *t) { static void create_tables(struct table *tt) {
int i, j; int i, j;
if (!t) { if (!tt) {
printf("create_tables: t is NULL\n"); printf("create_tables: t is NULL\n");
exit(1); exit(1);
} }
for (i = 0; i < 0x100; i++) { for (i = 0; i < 0x100; i++) {
for (j = 0; j < 0x100; j++) { for (j = 0; j < 0x100; j++) {
create_table(t + ((i * 0x100) + j), i, j); create_table(tt + ((i * 0x100) + j), i, j);
} }
} }
} }
// free the table memory // free the table memory
void free_tables(struct table *t) { static void free_tables(struct table *tt) {
int i; int i;
struct table *ttmp; struct table *ttmp;
if (!t) { if (!tt) {
printf("free_tables: t is NULL\n"); printf("free_tables: t is NULL\n");
exit(1); exit(1);
} }
for (i = 0; i < 0x10000; i++) { for (i = 0; i < 0x10000; i++) {
ttmp = t + i; ttmp = tt + i;
free(ttmp->data); free(ttmp->data);
} }
} }
@ -117,7 +117,7 @@ void free_tables(struct table *t) {
// write (partial) table to file // write (partial) table to file
void writetable(struct table *t1) { static void writetable(struct table *t1) {
int fd; int fd;
if (debug) printf("writetable %s\n", t1->path); if (debug) printf("writetable %s\n", t1->path);
@ -142,7 +142,7 @@ void writetable(struct table *t1) {
// store value in table // store value in table
void store(unsigned char *data) { static void store(unsigned char *data) {
unsigned char d_1, d_2; unsigned char d_1, d_2;
int offset; int offset;
struct table *t1; struct table *t1;
@ -194,7 +194,7 @@ void store(unsigned char *data) {
} }
// writes the ks (keystream) and s (state) // writes the ks (keystream) and s (state)
void write_ks_s(uint32_t ks1, uint32_t ks2, uint64_t shiftreg) { static void write_ks_s(uint32_t ks1, uint32_t ks2, uint64_t shiftreg) {
unsigned char buf[16]; unsigned char buf[16];
// create buffer // create buffer
@ -209,7 +209,7 @@ void write_ks_s(uint32_t ks1, uint32_t ks2, uint64_t shiftreg) {
// builds the di table for jumping // builds the di table for jumping
void builddi(int steps, int table) { static void builddi(int steps, int table) {
uint64_t statemask; uint64_t statemask;
int i; int i;
Hitag_State mystate; Hitag_State mystate;
@ -241,7 +241,7 @@ void builddi(int steps, int table) {
} }
// jump function - quickly jumps a load of steps // jump function - quickly jumps a load of steps
void jumpnsteps(Hitag_State *hstate, int table) { static void jumpnsteps(Hitag_State *hstate, int table) {
uint64_t output = 0; uint64_t output = 0;
uint64_t bitmask; uint64_t bitmask;
int i; int i;
@ -277,14 +277,14 @@ void jumpnsteps(Hitag_State *hstate, int table) {
// thread to build a part of the table // thread to build a part of the table
void *buildtable(void *d) { static void *buildtable(void *dd) {
Hitag_State hstate; Hitag_State hstate;
Hitag_State hstate2; Hitag_State hstate2;
unsigned long i; unsigned long i;
unsigned long maxentries = 1; unsigned long maxentries = 1;
uint32_t ks1; uint32_t ks1;
uint32_t ks2; uint32_t ks2;
int index = (int)(long)d; int index = (int)(long)dd;
int tnum = NUM_BUILD_THREADS; int tnum = NUM_BUILD_THREADS;
/* set random state */ /* set random state */
@ -334,7 +334,7 @@ void *buildtable(void *d) {
// make 'table/' (unsorted) and 'sorted/' dir structures // make 'table/' (unsorted) and 'sorted/' dir structures
void makedirs() { static void makedirs(void) {
char path[32]; char path[32];
int i; int i;
@ -368,7 +368,7 @@ static int datacmp(const void *p1, const void *p2, void *dummy) {
return memcmp(d_1, d_2, DATASIZE); return memcmp(d_1, d_2, DATASIZE);
} }
void *sorttable(void *d) { static void *sorttable(void *dd) {
int i, j; int i, j;
int fdin; int fdin;
int fdout; int fdout;
@ -378,7 +378,7 @@ void *sorttable(void *d) {
struct stat filestat; struct stat filestat;
unsigned char *table = NULL; unsigned char *table = NULL;
uint64_t numentries = 0; uint64_t numentries = 0;
int index = (int)(long)d; int index = (int)(long)dd;
int space = 0x100 / NUM_SORT_THREADS; int space = 0x100 / NUM_SORT_THREADS;
// create table - 50MB should be enough // create table - 50MB should be enough

View file

@ -5,7 +5,7 @@
#include "ht2crackutils.h" #include "ht2crackutils.h"
int makerandom(char *hex, unsigned int len, int fd) { static int makerandom(char *hex, unsigned int len, int fd) {
unsigned char raw[32]; unsigned char raw[32];
int i; int i;
@ -43,7 +43,7 @@ int main(int argc, char *argv[]) {
int urandomfd; int urandomfd;
if (argc < 2) { if (argc < 2) {
printf("ht2crack2gentest number\n"); printf("%s number\n", argv[0]);
exit(1); exit(1);
} }

View file

@ -23,7 +23,7 @@ static int datacmp(const void *p1, const void *p2) {
return memcmp(d1, d2, DATASIZE - 6); return memcmp(d1, d2, DATASIZE - 6);
} }
int loadrngdata(struct rngdata *r, char *file) { static int loadrngdata(struct rngdata *r, char *file) {
int fd; int fd;
int i, j; int i, j;
int nibble; int nibble;
@ -90,7 +90,7 @@ int loadrngdata(struct rngdata *r, char *file) {
return 1; return 1;
} }
int makecand(unsigned char *c, struct rngdata *r, int bitoffset) { static int makecand(unsigned char *c, struct rngdata *r, int bitoffset) {
int bytenum; int bytenum;
int bitnum; int bitnum;
int i; int i;
@ -116,7 +116,7 @@ int makecand(unsigned char *c, struct rngdata *r, int bitoffset) {
// test the candidate against the next or previous rng data // test the candidate against the next or previous rng data
int testcand(unsigned char *f, unsigned char *rt, int fwd) { static int testcand(unsigned char *f, unsigned char *rt, int fwd) {
Hitag_State hstate; Hitag_State hstate;
int i; int i;
uint32_t ks1; uint32_t ks1;
@ -154,7 +154,7 @@ int testcand(unsigned char *f, unsigned char *rt, int fwd) {
} }
} }
int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, unsigned char *s) { static int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, unsigned char *s) {
int fd; int fd;
struct stat filestat; struct stat filestat;
char file[64]; char file[64];
@ -222,7 +222,7 @@ int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, u
} }
int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstate, int *bitoffset) { static int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstate, int *bitoffset) {
int i; int i;
int bitlen; int bitlen;
unsigned char cand[6]; unsigned char cand[6];
@ -276,7 +276,7 @@ int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstat
void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset) { static void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset) {
int i; int i;
if (!s) { if (!s) {
@ -305,7 +305,7 @@ void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset) {
} }
uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr) { static uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr) {
uint64_t key; uint64_t key;
uint64_t keyupper; uint64_t keyupper;
uint32_t uid; uint32_t uid;
@ -368,7 +368,7 @@ int main(int argc, char *argv[]) {
int i; int i;
if (argc < 4) { if (argc < 4) {
printf("ht2crack2search rngdatafile UID nR\n"); printf("%s rngdatafile UID nR\n", argv[0]);
exit(1); exit(1);
} }

View file

@ -1,6 +1,5 @@
ht2crack3 ht2crack3
ht2test ht2crack3test
ht2crack3.exe ht2crack3.exe
ht2test.exe ht2crack3test.exe

View file

@ -1,19 +1,21 @@
CFLAGS?=-Wall -Werror -O3 MYSRCPATHS = ../common
LIBS= MYSRCS = ht2crackutils.c hitagcrypto.c
VPATH=../common MYINCLUDES =-I ../common
INC=-I ../common MYCFLAGS = -D_GNU_SOURCE
MYDEFS =
MYLDLIBS = -lpthread
all: ht2crack3.c ht2test.c hitagcrypto.o ht2crackutils.o BINS = ht2crack3 ht2crack3test
$(CC) $(CFLAGS) $(INC) -o ht2crack3 $< hitagcrypto.o ht2crackutils.o -lpthread $(LIBS) INSTALLTOOLS = $(BINS)
$(CC) $(CFLAGS) $(INC) -o ht2test ht2test.c hitagcrypto.o ht2crackutils.o $(LIBS)
ht2crackutils.o: ht2crackutils.c ht2crackutils.h include ../../../Makefile.host
$(CC) $(CFLAGS) -c $<
hitagcrypto.o: hitagcrypto.c hitagcrypto.h # checking platform can be done only after Makefile.host
$(CC) $(CFLAGS) -c $< ifneq (,$(findstring MINGW,$(platform)))
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
CFLAGS += -D_ISOC99_SOURCE
endif
clean: ht2crack3 : $(OBJDIR)/ht2crack3.o $(MYOBJS)
rm -rf *.o ht2crack3 ht2test ht2crack3test : $(OBJDIR)/ht2crack3test.o $(MYOBJS)
fresh: clean all

View file

@ -31,9 +31,9 @@ Tests
If you happen to know the key and want to check that all your nR aR values If you happen to know the key and want to check that all your nR aR values
are valid (for high-powered demonstrations only, really) then you can use are valid (for high-powered demonstrations only, really) then you can use
the ht2test program to check them. It's otherwise massively pointless and a the ht2crack3test program to check them. It's otherwise massively pointless and a
complete waste of space. complete waste of space.
``` ```
./ht2test NRARFILE KEY UID ./ht2crack3test NRARFILE KEY UID
``` ```

View file

@ -65,7 +65,7 @@ static uint32_t hitag2_crypt(uint64_t s) {
// this function is a modification of the filter function f, based heavily // this function is a modification of the filter function f, based heavily
// on the hitag2_crypt function in Rfidler // on the hitag2_crypt function in Rfidler
int fnP(uint64_t klowery) { static int fnP(uint64_t klowery) {
const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
const uint32_t ht2_function4p = 0xAE83; // 1010 1110 1000 0011 const uint32_t ht2_function4p = 0xAE83; // 1010 1110 1000 0011
@ -84,7 +84,7 @@ int fnP(uint64_t klowery) {
} }
// comparison function for sorting/searching Tklower entries // comparison function for sorting/searching Tklower entries
int Tk_cmp(const void *v1, const void *v2) { static int Tk_cmp(const void *v1, const void *v2) {
const struct Tklower *Tk1 = (struct Tklower *)v1; const struct Tklower *Tk1 = (struct Tklower *)v1;
const struct Tklower *Tk2 = (struct Tklower *)v2; const struct Tklower *Tk2 = (struct Tklower *)v2;
@ -98,7 +98,7 @@ int Tk_cmp(const void *v1, const void *v2) {
} }
// test for bad guesses of kmiddle // test for bad guesses of kmiddle
int is_kmiddle_badguess(uint64_t z, struct Tklower *Tk, int max, int aR0) { static int is_kmiddle_badguess(uint64_t z, struct Tklower *Tk, int max, int aR0) {
struct Tklower *result, target; struct Tklower *result, target;
@ -122,7 +122,7 @@ int is_kmiddle_badguess(uint64_t z, struct Tklower *Tk, int max, int aR0) {
} }
// function to test if a partial key is valid // function to test if a partial key is valid
int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR) { static int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR) {
uint64_t kupper; uint64_t kupper;
uint64_t key; uint64_t key;
Hitag_State hstate; Hitag_State hstate;
@ -178,7 +178,7 @@ int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR
// effectively work out candidates for the lower 34 bits of the key. // effectively work out candidates for the lower 34 bits of the key.
void *crack(void *d) { static void *crack(void *d) {
struct threaddata *data = (struct threaddata *)d; struct threaddata *data = (struct threaddata *)d;
uint64_t uid; uint64_t uid;
struct nRaR *TnRaR; struct nRaR *TnRaR;
@ -321,7 +321,7 @@ int main(int argc, char *argv[]) {
struct threaddata *tdata = NULL; struct threaddata *tdata = NULL;
if (argc < 3) { if (argc < 3) {
printf("ht2crack3 uid nRaRfile\n"); printf("%s uid nRaRfile\n", argv[0]);
exit(1); exit(1);
} }

View file

@ -19,7 +19,7 @@ int main(int argc, char *argv[]) {
char *uid; char *uid;
if (argc < 4) { if (argc < 4) {
printf("ht2test nRaRfile KEY UID\n"); printf("%s nRaRfile KEY UID\n", argv[0]);
exit(1); exit(1);
} }

View file

@ -1,18 +1,20 @@
CFLAGS?=-Wall -Werror -O3 MYSRCPATHS = ../common
LIBS=-lpthread MYSRCS = ht2crackutils.c hitagcrypto.c
VPATH=../common MYINCLUDES =-I ../common
INC=-I ../common MYCFLAGS = -D_GNU_SOURCE
MYDEFS =
MYLDLIBS = -lpthread
all: ht2crack4.c hitagcrypto.o ht2crackutils.o BINS = ht2crack4
$(CC) $(CFLAGS) $(INC) -o ht2crack4 $< hitagcrypto.o ht2crackutils.o $(LIBS) INSTALLTOOLS = $(BINS)
hitagcrypto.o: hitagcrypto.c hitagcrypto.h include ../../../Makefile.host
$(CC) $(CFLAGS) -c $<
ht2crackutils.o: ht2crackutils.c ht2crackutils.h # checking platform can be done only after Makefile.host
$(CC) $(CFLAGS) -c $< ifneq (,$(findstring MINGW,$(platform)))
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
CFLAGS += -D_ISOC99_SOURCE
endif
clean: ht2crack4 : $(OBJDIR)/ht2crack4.o $(MYOBJS)
rm -rf *.o ht2crack4
fresh: clean all

View file

@ -93,7 +93,7 @@ uint64_t uid;
int maxtablesize = 800000; int maxtablesize = 800000;
uint64_t supplied_testkey = 0; uint64_t supplied_testkey = 0;
void usage() { static void usage(void) {
printf("ht2crack4 - K Sheldrake, based on the work of Garcia et al\n\n"); printf("ht2crack4 - K Sheldrake, based on the work of Garcia et al\n\n");
printf("Cracks a HiTag2 key using a small number (4 to 16) of encrypted\n"); printf("Cracks a HiTag2 key using a small number (4 to 16) of encrypted\n");
printf("nonce and challenge response pairs, using a fast correlation\n"); printf("nonce and challenge response pairs, using a fast correlation\n");
@ -147,6 +147,7 @@ double pfnc[][16] = {
/* hitag2_crypt works on the post-shifted form of the lfsr; this is the ref in rfidler code */ /* hitag2_crypt works on the post-shifted form of the lfsr; this is the ref in rfidler code */
/*
static uint32_t hitag2_crypt(uint64_t s) { static uint32_t hitag2_crypt(uint64_t s) {
uint32_t bitindex; uint32_t bitindex;
@ -158,9 +159,10 @@ static uint32_t hitag2_crypt(uint64_t s) {
return (ht2_function5c >> bitindex) & 1; return (ht2_function5c >> bitindex) & 1;
} }
*/
/* ht2crypt works on the pre-shifted form of the lfsr; this is the ref in the paper */ /* ht2crypt works on the pre-shifted form of the lfsr; this is the ref in the paper */
uint64_t ht2crypt(uint64_t s) { static uint64_t ht2crypt(uint64_t s) {
uint64_t bitindex; uint64_t bitindex;
bitindex = (ht2_function4a >> pickbits2_2(s, 2, 5)) & 1; bitindex = (ht2_function4a >> pickbits2_2(s, 2, 5)) & 1;
@ -174,12 +176,13 @@ uint64_t ht2crypt(uint64_t s) {
/* fnL is the feedback function for the reference code */ /* fnL is the feedback function for the reference code */
uint64_t fnL(uint64_t x) { /*
static uint64_t fnL(uint64_t x) {
return (bitn(x, 0) ^ bitn(x, 2) ^ bitn(x, 3) ^ bitn(x, 6) ^ bitn(x, 7) ^ bitn(x, 8) ^ return (bitn(x, 0) ^ bitn(x, 2) ^ bitn(x, 3) ^ bitn(x, 6) ^ bitn(x, 7) ^ bitn(x, 8) ^
bitn(x, 16) ^ bitn(x, 22) ^ bitn(x, 23) ^ bitn(x, 26) ^ bitn(x, 30) ^ bitn(x, 41) ^ bitn(x, 16) ^ bitn(x, 22) ^ bitn(x, 23) ^ bitn(x, 26) ^ bitn(x, 30) ^ bitn(x, 41) ^
bitn(x, 42) ^ bitn(x, 43) ^ bitn(x, 46) ^ bitn(x, 47)); bitn(x, 42) ^ bitn(x, 43) ^ bitn(x, 46) ^ bitn(x, 47));
} }
*/
/* packed_size is an array that maps the number of confirmed bits in a state to /* packed_size is an array that maps the number of confirmed bits in a state to
* the number of relevant bits. * the number of relevant bits.
@ -193,7 +196,7 @@ unsigned int packed_size[] = { 0, 0, 0, 1, 2, 2, 3, 4, 4, 5, 5, 5, 5
/* f20 is the same as hitag2_crypt except it works on the packed version /* f20 is the same as hitag2_crypt except it works on the packed version
* of the state where all 20 relevant bits are squashed together */ * of the state where all 20 relevant bits are squashed together */
uint64_t f20(uint64_t y) { static uint64_t f20(uint64_t y) {
uint64_t bitindex; uint64_t bitindex;
bitindex = (ht2_function4a >> (y & 0xf)) & 1; bitindex = (ht2_function4a >> (y & 0xf)) & 1;
@ -207,7 +210,7 @@ uint64_t f20(uint64_t y) {
/* packstate packs the relevant bits from LFSR state into 20 bits for pre-shifted lfsr */ /* packstate packs the relevant bits from LFSR state into 20 bits for pre-shifted lfsr */
uint64_t packstate(uint64_t s) { static uint64_t packstate(uint64_t s) {
uint64_t packed; uint64_t packed;
packed = pickbits2_2(s, 2, 5); packed = pickbits2_2(s, 2, 5);
@ -221,7 +224,7 @@ uint64_t packstate(uint64_t s) {
/* create_guess_table mallocs the tables */ /* create_guess_table mallocs the tables */
void create_guess_table() { static void create_guess_table(void) {
guesses = (struct guess *)malloc(sizeof(struct guess) * maxtablesize); guesses = (struct guess *)malloc(sizeof(struct guess) * maxtablesize);
if (!guesses) { if (!guesses) {
printf("cannot malloc guess table\n"); printf("cannot malloc guess table\n");
@ -232,7 +235,7 @@ void create_guess_table() {
/* init the guess table by reading in the encrypted nR,aR values and /* init the guess table by reading in the encrypted nR,aR values and
* setting the first 2^16 key guesses */ * setting the first 2^16 key guesses */
void init_guess_table(char *filename, char *uidstr) { static void init_guess_table(char *filename, char *uidstr) {
unsigned int i, j; unsigned int i, j;
FILE *fp; FILE *fp;
char *buf = NULL; char *buf = NULL;
@ -313,7 +316,7 @@ void init_guess_table(char *filename, char *uidstr) {
/* bit_score calculates the ratio of partial states that could generate /* bit_score calculates the ratio of partial states that could generate
* the resulting bit b to all possible states * the resulting bit b to all possible states
* size is the number of confirmed bits in the state */ * size is the number of confirmed bits in the state */
double bit_score(uint64_t s, uint64_t size, uint64_t b) { static double bit_score(uint64_t s, uint64_t size, uint64_t b) {
uint64_t packed; uint64_t packed;
uint64_t chopped; uint64_t chopped;
unsigned int n; unsigned int n;
@ -396,7 +399,7 @@ double bit_score(uint64_t s, uint64_t size, uint64_t b) {
* bit_scores together until no bits remain. bit_scores are * bit_scores together until no bits remain. bit_scores are
* multiplied by the number of relevant bits in the scored state * multiplied by the number of relevant bits in the scored state
* to give weight to more complete states. */ * to give weight to more complete states. */
double score(uint64_t s, unsigned int size, uint64_t ks, unsigned int kssize) { static double score(uint64_t s, unsigned int size, uint64_t ks, unsigned int kssize) {
double sc, sc2; double sc, sc2;
if ((size == 1) || (kssize == 1)) { if ((size == 1) || (kssize == 1)) {
@ -427,7 +430,7 @@ double score(uint64_t s, unsigned int size, uint64_t ks, unsigned int kssize) {
/* score_traces runs score for each encrypted nonce */ /* score_traces runs score for each encrypted nonce */
void score_traces(struct guess *g, unsigned int size) { static void score_traces(struct guess *g, unsigned int size) {
uint64_t lfsr; uint64_t lfsr;
unsigned int i; unsigned int i;
double sc; double sc;
@ -481,7 +484,7 @@ void score_all_traces(unsigned int size)
*/ */
/* score_some_traces runs score_traces for every key guess in a section of the table */ /* score_some_traces runs score_traces for every key guess in a section of the table */
void *score_some_traces(void *data) { static void *score_some_traces(void *data) {
unsigned int i; unsigned int i;
struct thread_data *tdata = (struct thread_data *)data; struct thread_data *tdata = (struct thread_data *)data;
@ -494,7 +497,7 @@ void *score_some_traces(void *data) {
/* score_all_traces runs score_traces for every key guess in the table */ /* score_all_traces runs score_traces for every key guess in the table */
void score_all_traces(unsigned int size) { static void score_all_traces(unsigned int size) {
pthread_t threads[NUM_THREADS]; pthread_t threads[NUM_THREADS];
void *status; void *status;
struct thread_data tdata[NUM_THREADS]; struct thread_data tdata[NUM_THREADS];
@ -535,7 +538,7 @@ void score_all_traces(unsigned int size) {
/* cmp_guess is the comparison function for qsorting the guess table */ /* cmp_guess is the comparison function for qsorting the guess table */
int cmp_guess(const void *a, const void *b) { static int cmp_guess(const void *a, const void *b) {
struct guess *a1 = (struct guess *)a; struct guess *a1 = (struct guess *)a;
struct guess *b1 = (struct guess *)b; struct guess *b1 = (struct guess *)b;
@ -552,7 +555,7 @@ int cmp_guess(const void *a, const void *b) {
/* expand all guesses in first half of (sorted) table by /* expand all guesses in first half of (sorted) table by
* copying them into the second half and extending the copied * copying them into the second half and extending the copied
* ones with an extra 1, leaving the first half with an extra 0 */ * ones with an extra 1, leaving the first half with an extra 0 */
void expand_guesses(unsigned int halfsize, unsigned int size) { static void expand_guesses(unsigned int halfsize, unsigned int size) {
unsigned int i, j; unsigned int i, j;
for (i = 0; i < halfsize; i++) { for (i = 0; i < halfsize; i++) {
@ -567,7 +570,7 @@ void expand_guesses(unsigned int halfsize, unsigned int size) {
/* checks if the supplied test key is still in the table, which /* checks if the supplied test key is still in the table, which
* is useful when testing different scoring methods */ * is useful when testing different scoring methods */
void check_supplied_testkey(unsigned int size) { static void check_supplied_testkey(unsigned int size) {
uint64_t partkey; uint64_t partkey;
unsigned int i; unsigned int i;
@ -586,7 +589,7 @@ void check_supplied_testkey(unsigned int size) {
/* execute_round scores the guesses, sorts them and expands the good half */ /* execute_round scores the guesses, sorts them and expands the good half */
void execute_round(unsigned int size) { static void execute_round(unsigned int size) {
unsigned int halfsize; unsigned int halfsize;
// score all the current guesses // score all the current guesses
@ -614,7 +617,7 @@ void execute_round(unsigned int size) {
/* crack is the main cracking algo; it executes the rounds */ /* crack is the main cracking algo; it executes the rounds */
void crack() { static void crack(void) {
unsigned int i; unsigned int i;
uint64_t revkey; uint64_t revkey;
uint64_t foundkey; uint64_t foundkey;
@ -630,9 +633,9 @@ void crack() {
} }
} }
/* test function to make sure I know how the LFSR works */ /* test function to make sure I know how the LFSR works */
void testkey(uint64_t key) { /*
static void testkey(uint64_t key) {
uint64_t i; uint64_t i;
uint64_t b0to31 = 0; uint64_t b0to31 = 0;
uint64_t ks = 0; uint64_t ks = 0;
@ -689,10 +692,11 @@ void testkey(uint64_t key) {
printbin2(lfsr, 48); printbin2(lfsr, 48);
printf("\n\n"); printf("\n\n");
} }
*/
/* test function to generate test data */ /* test function to generate test data */
void gen_bitstreams_testks(struct guess *g, uint64_t key) { /*
static void gen_bitstreams_testks(struct guess *g, uint64_t key) {
unsigned int i, j; unsigned int i, j;
uint64_t nRxorkey, lfsr, ks; uint64_t nRxorkey, lfsr, ks;
@ -730,10 +734,11 @@ void gen_bitstreams_testks(struct guess *g, uint64_t key) {
} }
} }
} }
*/
/* test function */ /* test function */
void test() { /*
static void test(void) {
uint64_t lfsr; uint64_t lfsr;
uint64_t packed; uint64_t packed;
@ -751,10 +756,10 @@ void test() {
printf("test done\n"); printf("test done\n");
} }
*/
/* check_key tests the potential key against an encrypted nonce, ks pair */ /* check_key tests the potential key against an encrypted nonce, ks pair */
int check_key(uint64_t key, uint64_t enc_nR, uint64_t ks) { static int check_key(uint64_t key, uint64_t enc_nR, uint64_t ks) {
Hitag_State hstate; Hitag_State hstate;
uint64_t bits; uint64_t bits;
int i; int i;

View file

@ -1,17 +1,20 @@
CFLAGS?=-Wall -Werror -O3 MYSRCPATHS = ../common
LIBS=-lpthread MYSRCS = ht2crackutils.c hitagcrypto.c
VPATH=../common MYINCLUDES =-I ../common
INC=-I ../common MYCFLAGS =
MYDEFS =
MYLDLIBS = -lpthread
all: ht2crack5.c ht2crackutils.o hitagcrypto.o BINS = ht2crack5
$(CC) $(CFLAGS) $(INC) -O3 $< -o ht2crack5 ht2crackutils.o hitagcrypto.o $(LIBS) INSTALLTOOLS = $(BINS)
hitagcrypto.o: hitagcrypto.c hitagcrypto.h include ../../../Makefile.host
$(CC) $(CFLAGS) -c $<
ht2crackutils.o: ht2crackutils.c ht2crackutils.h # checking platform can be done only after Makefile.host
$(CC) $(CFLAGS) -c $< ifneq (,$(findstring MINGW,$(platform)))
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
CFLAGS += -D_ISOC99_SOURCE
endif
clean: ht2crack5 : $(OBJDIR)/ht2crack5.o $(MYOBJS)
rm -f *.o ht2crack5
fresh: clean all

View file

@ -55,7 +55,7 @@ bitslice_t bs_zeroes, bs_ones;
#define get_bit(n, word) ((word >> (n)) & 1) #define get_bit(n, word) ((word >> (n)) & 1)
#define get_vector_bit(slice, value) get_bit(slice&0x3f, value.bytes64[slice>>6]) #define get_vector_bit(slice, value) get_bit(slice&0x3f, value.bytes64[slice>>6])
const uint64_t expand(uint64_t mask, uint64_t value) { static uint64_t expand(uint64_t mask, uint64_t value) {
uint64_t fill = 0; uint64_t fill = 0;
for (uint64_t bit_index = 0; bit_index < 48; bit_index++) { for (uint64_t bit_index = 0; bit_index < 48; bit_index++) {
if (mask & 1) { if (mask & 1) {
@ -67,7 +67,7 @@ const uint64_t expand(uint64_t mask, uint64_t value) {
return fill; return fill;
} }
void bitslice(const uint64_t value, bitslice_t *restrict bitsliced_value, const size_t bit_len, bool reverse) { static void bitslice(const uint64_t value, bitslice_t *restrict bitsliced_value, const size_t bit_len, bool reverse) {
size_t bit_idx; size_t bit_idx;
for (bit_idx = 0; bit_idx < bit_len; bit_idx++) { for (bit_idx = 0; bit_idx < bit_len; bit_idx++) {
bool bit; bool bit;
@ -84,7 +84,7 @@ void bitslice(const uint64_t value, bitslice_t *restrict bitsliced_value, const
} }
} }
const uint64_t unbitslice(const bitslice_t *restrict b, const uint8_t s, const uint8_t n) { static uint64_t unbitslice(const bitslice_t *restrict b, const uint8_t s, const uint8_t n) {
uint64_t result = 0; uint64_t result = 0;
for (uint8_t i = 0; i < n; ++i) { for (uint8_t i = 0; i < n; ++i) {
result <<= 1; result <<= 1;
@ -118,7 +118,7 @@ bitslice_t initial_bitslices[48];
size_t filter_pos[20] = {4, 7, 9, 13, 16, 18, 22, 24, 27, 30, 32, 35, 45, 47 }; size_t filter_pos[20] = {4, 7, 9, 13, 16, 18, 22, 24, 27, 30, 32, 35, 45, 47 };
size_t thread_count = 8; size_t thread_count = 8;
uint64_t layer_0_found; uint64_t layer_0_found;
void *find_state(void *thread_d); static void *find_state(void *thread_d);
static void try_state(uint64_t s); static void try_state(uint64_t s);
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -201,7 +201,7 @@ int main(int argc, char *argv[]) {
exit(1); exit(1);
} }
void *find_state(void *thread_d) { static void *find_state(void *thread_d) {
uint64_t thread = (uint64_t)thread_d; uint64_t thread = (uint64_t)thread_d;
for (uint64_t index = thread; index < layer_0_found; index += thread_count) { for (uint64_t index = thread; index < layer_0_found; index += thread_count) {

View file

@ -1,23 +1,27 @@
CFLAGS?=-Wall MYSRCPATHS = ../common
#INCLUDE=-I/usr/local/cuda-7.5/include MYSRCS = ht2crackutils.c hitagcrypto.c
INCLUDE=-I/opt/nvidia/cuda/include MYCFLAGS =
#Linux MYDEFS =
#LIBS=-L/usr/local/cuda-7.5/lib64 -lOpenCL ifeq ($(platform),Darwin)
LIBS=-L/opt/nvidia/cuda/lib64 -lOpenCL MYLDLIBS ?= -framework OpenCL
#Mac else
#LIBS=-framework OpenCL #MYINCLUDES ?=-I/usr/local/cuda-7.5/include
VPATH=../common #MYINCLUDES ?=-I/opt/nvidia/cuda/include
INC=-I ../common #MYLDLIBS ?= -L/usr/local/cuda-7.5/lib64 -lOpenCL
MYLDLIBS ?= -L/opt/nvidia/cuda/lib64 -lOpenCL
endif
MYINCLUDES +=-I ../common
all: ht2crack5.c ht2crackutils.o hitagcrypto.o BINS = ht2crack5gpu
$(CC) $(CFLAGS) $(INC) -o ht2crack5gpu $< ht2crackutils.o hitagcrypto.o $(LIBS) -lpthread INSTALLTOOLS = $(BINS)
hitagcrypto.o: hitagcrypto.c hitagcrypto.h include ../../../Makefile.host
$(CC) $(CFLAGS) $(INCLUDE) -c $<
ht2crackutils.o: ht2crackutils.c ht2crackutils.h # checking platform can be done only after Makefile.host
$(CC) $(CFLAGS) $(INCLUDE) -c $< ifneq (,$(findstring MINGW,$(platform)))
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
CFLAGS += -D_ISOC99_SOURCE
endif
clean: ht2crack5gpu : $(OBJDIR)/ht2crack5gpu.o $(MYOBJS)
rm -f *.o ht2crack5gpu
fresh: clean all

View file

@ -65,7 +65,7 @@ bitslice_t bs_zeroes, bs_ones;
state[-2+i+42].value ^ state[-2+i+43].value ^ state[-2+i+46].value ^ state[-2+i+47].value); state[-2+i+42].value ^ state[-2+i+43].value ^ state[-2+i+46].value ^ state[-2+i+47].value);
#define get_bit(n, word) ((word >> (n)) & 1) #define get_bit(n, word) ((word >> (n)) & 1)
const uint64_t expand(uint64_t mask, uint64_t value) { static uint64_t expand(uint64_t mask, uint64_t value) {
uint64_t fill = 0; uint64_t fill = 0;
for (uint64_t bit_index = 0; bit_index < 48; bit_index++) { for (uint64_t bit_index = 0; bit_index < 48; bit_index++) {
if (mask & 1) { if (mask & 1) {
@ -77,7 +77,7 @@ const uint64_t expand(uint64_t mask, uint64_t value) {
return fill; return fill;
} }
void bitslice(const uint64_t value, bitslice_t *restrict bitsliced_value, const size_t bit_len, bool reverse) { static void bitslice(const uint64_t value, bitslice_t *restrict bitsliced_value, const size_t bit_len, bool reverse) {
size_t bit_idx; size_t bit_idx;
for (bit_idx = 0; bit_idx < bit_len; bit_idx++) { for (bit_idx = 0; bit_idx < bit_len; bit_idx++) {
bool bit; bool bit;
@ -123,7 +123,7 @@ struct context {
}; };
void runKernel(struct context *ctx, uint32_t cand_base, uint64_t *matches, uint32_t *matches_found) { static void runKernel(struct context *ctx, uint32_t cand_base, uint64_t *matches, uint32_t *matches_found) {
int err; int err;
size_t global[2]; size_t global[2];

View file

@ -0,0 +1,118 @@
#!/usr/bin/env python3
"""
HITAG2 cipher
Implemented by Aram Verstegen
"""
import random
def i4(x, a, b, c, d):
return (((x >> a) & 1)*8)+((x >> b) & 1)*4+((x >> c) & 1)*2+((x >> d) & 1)
def f20_4(state):
return ((0x3c65 >> i4(state,34,43,44,46)) & 1)
def f20_3(state):
return (( 0xee5 >> i4(state,28,29,31,33)) & 1)
def f20_2(state):
return (( 0xee5 >> i4(state,17,21,23,26)) & 1)
def f20_1(state):
return (( 0xee5 >> i4(state, 8,12,14,15)) & 1)
def f20_0(state):
return ((0x3c65 >> i4(state, 2, 3, 5, 6)) & 1)
def f20_last(s0,s1,s2,s3,s4):
return (0xdd3929b >> ((s0 * 16)
+ (s1 * 8)
+ (s2 * 4)
+ (s3 * 2)
+ (s4 * 1))) & 1
def f20(state):
return f20_last(f20_0(state), f20_1(state), f20_2(state), f20_3(state), f20_4(state))
def lfsr_bs(state, i):
return (state[i+ 0] ^ state[i+ 2] ^ state[i+ 3] ^ state[i+ 6] ^
state[i+ 7] ^ state[i+ 8] ^ state[i+16] ^ state[i+22] ^
state[i+23] ^ state[i+26] ^ state[i+30] ^ state[i+41] ^
state[i+42] ^ state[i+43] ^ state[i+46] ^ state[i+47])
def f20a_bs(a,b,c,d):
return (~(((a|b)&c)^(a|d)^b)) # 6 ops
def f20b_bs(a,b,c,d):
return (~(((d|c)&(a^b))^(d|a|b))) # 7 ops
def f20c_bs(a,b,c,d,e):
return (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) # 13 ops
def filter_bs(state, i):
return (f20c_bs( f20a_bs(state[i+ 2],state[i+ 3],state[i+ 5],state[i+ 6]),
f20b_bs(state[i+ 8],state[i+12],state[i+14],state[i+15]),
f20b_bs(state[i+17],state[i+21],state[i+23],state[i+26]),
f20b_bs(state[i+28],state[i+29],state[i+31],state[i+33]),
f20a_bs(state[i+34],state[i+43],state[i+44],state[i+46])))
def unbitslice(s, n):
return int(''.join(map(str,map(int,map(bool,s[n:n+48])))[::-1]),2)
def hitag2_init(key, uid, nonce):
state = 0
for i in range(32, 48):
state = (state << 1) | ((key >> i) & 1)
for i in range(0, 32):
state = (state << 1) | ((uid >> i) & 1)
#print '%012x' % state
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
for i in range(0, 32):
nonce_bit = (f20(state) ^ ((nonce >> (31-i)) & 1))
#print nonce_bit
state = (state >> 1) | (((nonce_bit ^ (key >> (31-i))) & 1) << 47)
#print '%012x' % state
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
return state
def lfsr_feedback(state):
return (((state >> 0) ^ (state >> 2) ^ (state >> 3)
^ (state >> 6) ^ (state >> 7) ^ (state >> 8)
^ (state >> 16) ^ (state >> 22) ^ (state >> 23)
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
^ (state >> 42) ^ (state >> 43) ^ (state >> 46)
^ (state >> 47)) & 1)
def lfsr(state):
return (state >> 1) + (lfsr_feedback(state) << 47)
def lfsr_feedback_inv(state):
return (((state >> 47) ^ (state >> 1) ^ (state >> 2)
^ (state >> 5) ^ (state >> 6) ^ (state >> 7)
^ (state >> 15) ^ (state >> 21) ^ (state >> 22)
^ (state >> 25) ^ (state >> 29) ^ (state >> 40)
^ (state >> 41) ^ (state >> 42) ^ (state >> 45)
^ (state >> 46)) & 1)
def lfsr_inv(state):
return ((state << 1) + (lfsr_feedback_inv(state))) & ((1<<48)-1)
def hitag2(state, length=48):
c = 0
for i in range(0, length):
c = (c << 1) | f20(state)
#print '%012x' % state
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
state = lfsr(state)
return c
if __name__ == "__main__":
import sys
if len(sys.argv) == 4:
key = int(sys.argv[1], 16)
uid = int(sys.argv[2], 16)
n = int(sys.argv[3])
for i in range(n):
nonce = random.randrange(2**32)
state = hitag2_init(key, uid, nonce)
print('%08X %08X' % (nonce, hitag2(state, 32)^0xffffffff))
else:
print("Usage: python %s <key> <uid> <nr of nRaR to generate>" % sys.argv[0])

View file

@ -4,10 +4,12 @@ PM3PATH="$(dirname "$0")/.."
cd "$PM3PATH" || exit 1 cd "$PM3PATH" || exit 1
SLOWTESTS=false SLOWTESTS=false
GPUTESTS=false
TESTALL=true TESTALL=true
TESTMFKEY=false TESTMFKEY=false
TESTNONCE2KEY=false TESTNONCE2KEY=false
TESTMFNONCEBRUTE=false TESTMFNONCEBRUTE=false
TESTHITAG2CRACK=false
TESTFPGACOMPRESS=false TESTFPGACOMPRESS=false
TESTBOOTROM=false TESTBOOTROM=false
TESTARMSRC=false TESTARMSRC=false
@ -32,6 +34,10 @@ Usage: $0 [--long] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|mf_nonce_br
SLOWTESTS=true SLOWTESTS=true
shift shift
;; ;;
--gpu)
GPUTESTS=true
shift
;;
--clientbin) --clientbin)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
CLIENTBIN=$2 CLIENTBIN=$2
@ -61,6 +67,11 @@ Usage: $0 [--long] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|mf_nonce_br
TESTFPGACOMPRESS=true TESTFPGACOMPRESS=true
shift shift
;; ;;
hitag2crack)
TESTALL=false
TESTHITAG2CRACK=true
shift
;;
bootrom) bootrom)
TESTALL=false TESTALL=false
TESTBOOTROM=true TESTBOOTROM=true
@ -122,24 +133,45 @@ function CheckFileExist() {
return 1 return 1
} }
# title, command line, check result, repeat several times if failed, ignore if fail # [slow] [gpu] [retry] [ignore] <title> <command_line> <check_result_regex>
# slow: test takes more than ~5s
# gpu: test requires GPU presence
# retry: test repeated up to 3 times in case of failure
# ignore: test failure is not fatal
function CheckExecute() { function CheckExecute() {
if [ "$1" == "slow" ]; then if [ "$1" == "slow" ]; then
SLOWTEST=true local SLOWTEST=true
shift shift
else else
SLOWTEST=false local SLOWTEST=false
fi fi
if [ "$4" ]; then if [ "$1" == "gpu" ]; then
local GPUTEST=true
shift
else
local GPUTEST=false
fi
if [ "$1" == "retry" ]; then
local RETRY="1 2 3 e" local RETRY="1 2 3 e"
shift
else else
local RETRY="e" local RETRY="e"
fi fi
if [ "$1" == "ignore" ]; then
local IGNOREFAILURE=true
shift
else
local IGNOREFAILURE=false
fi
if $SLOWTEST && ! $SLOWTESTS; then if $SLOWTEST && ! $SLOWTESTS; then
echo -e "$1 ${C_YELLOW}[SKIPPED]${C_NC} (slow)\n" echo -e "$1 ${C_YELLOW}[SKIPPED]${C_NC} (slow)\n"
return 0 return 0
fi fi
if $GPUTEST && ! $GPUTESTS; then
echo -e "$1 ${C_YELLOW}[SKIPPED]${C_NC} (gpu)\n"
return 0
fi
for I in $RETRY for I in $RETRY
do do
@ -151,7 +183,7 @@ function CheckExecute() {
if [ ! $I == "e" ]; then echo "retry $I"; fi if [ ! $I == "e" ]; then echo "retry $I"; fi
done done
if [ "$5" ]; then if $IGNOREFAILURE; then
echo -e "$1 ${C_YELLOW}[Ignored]${C_NC}" echo -e "$1 ${C_YELLOW}[Ignored]${C_NC}"
return 0 return 0
fi fi
@ -227,6 +259,54 @@ while true; do
if ! CheckFileExist "mf_nonce_brute exists" "$MFNONCEBRUTEBIN"; then break; fi if ! CheckFileExist "mf_nonce_brute exists" "$MFNONCEBRUTEBIN"; then break; fi
if ! CheckExecute slow "mf_nonce_brute test" "$MFNONCEBRUTEBIN 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a" "Key.*: \[ffffffffffff\]"; then break; fi if ! CheckExecute slow "mf_nonce_brute test" "$MFNONCEBRUTEBIN 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a" "Key.*: \[ffffffffffff\]"; then break; fi
fi fi
# hitag2crack not yet part of "all"
# if $TESTALL || $TESTHITAG2CRACK; then
if $TESTHITAG2CRACK; then
echo -e "\n${C_BLUE}Testing ht2crack2:${C_NC} ${HT2CRACK2PATH:=./tools/hitag2crack/crack2/}"
if ! CheckFileExist "ht2crack2buildtable exists" "$HT2CRACK2PATH/ht2crack2buildtable"; then break; fi
if ! CheckFileExist "ht2crack2gentest exists" "$HT2CRACK2PATH/ht2crack2gentest"; then break; fi
if ! CheckFileExist "ht2crack2search exists" "$HT2CRACK2PATH/ht2crack2search"; then break; fi
# 1.5Tb tables are supposed to be absent, so it's just a fast check without real cracking
if ! CheckExecute "ht2crack2 quick test" "cd $HT2CRACK2PATH; ./ht2crack2gentest 1 && ./runalltests.sh; rm keystream*" "searching on bit"; then break; fi
echo -e "\n${C_BLUE}Testing ht2crack3:${C_NC} ${HT2CRACK3PATH:=./tools/hitag2crack/crack3/}"
if ! CheckFileExist "ht2crack3 exists" "$HT2CRACK3PATH/ht2crack3"; then break; fi
if ! CheckFileExist "ht2crack3test exists" "$HT2CRACK3PATH/ht2crack3test"; then break; fi
HT2CRACK3UID=AABBCCDD
# Test fast only for HT2CRACK3KEY in begin of keyspace!
HT2CRACK3KEY=000102030405
HT2CRACK3N=32
HT2CRACK3NRAR=hitag2_${HT2CRACK3UID}_nrar_${HT2CRACK3N}emul.txt
if ! CheckExecute "ht2crack3 gen testfile" "cd $HT2CRACK3PATH; python3 ../hitag2_gen_nRaR.py $HT2CRACK3KEY $HT2CRACK3UID $HT2CRACK3N > $HT2CRACK3NRAR && echo SUCCESS" "SUCCESS"; then break; fi
if ! CheckExecute "ht2crack3test test" "cd $HT2CRACK3PATH; ./ht2crack3test $HT2CRACK3NRAR $HT2CRACK3KEY $HT2CRACK3UID|grep -v SUCCESS||echo SUCCESS" "SUCCESS"; then break; fi
if ! CheckExecute "ht2crack3 test" "cd $HT2CRACK3PATH; ./ht2crack3 $HT2CRACK3UID $HT2CRACK3NRAR |egrep -v '(trying|partial)'" "key = $HT2CRACK3KEY"; then break; fi
if ! CheckExecute "ht2crack3 rm testfile" "cd $HT2CRACK3PATH; rm $HT2CRACK3NRAR && echo SUCCESS" "SUCCESS"; then break; fi
echo -e "\n${C_BLUE}Testing ht2crack4:${C_NC} ${HT2CRACK4PATH:=./tools/hitag2crack/crack4/}"
if ! CheckFileExist "ht2crack4 exists" "$HT2CRACK4PATH/ht2crack4"; then break; fi
HT2CRACK4UID=12345678
HT2CRACK4KEY=AABBCCDDEEFF
HT2CRACK4N=32
HT2CRACK4NRAR=hitag2_${HT2CRACK4UID}_nrar_${HT2CRACK4N}emul.txt
# The success is probabilistic: a fresh random nRaR file is required for each run
# Order of magnitude to crack it: ~15s -> tagged as "slow"
if ! CheckExecute slow retry ignore "ht2crack4 test" "cd $HT2CRACK4PATH; \
python3 ../hitag2_gen_nRaR.py $HT2CRACK4KEY $HT2CRACK4UID $HT2CRACK4N > $HT2CRACK4NRAR; \
./ht2crack4 -u $HT2CRACK4UID -n $HT2CRACK4NRAR -N 16 -t 500000 2>&1; \
rm $HT2CRACK4NRAR" "key = $HT2CRACK4KEY"; then break; fi
echo -e "\n${C_BLUE}Testing ht2crack5:${C_NC} ${HT2CRACK5PATH:=./tools/hitag2crack/crack5/}"
if ! CheckFileExist "ht2crack5 exists" "$HT2CRACK5PATH/ht2crack5"; then break; fi
echo -e "\n${C_BLUE}Testing ht2crack5gpu:${C_NC} ${HT2CRACK5GPUPATH:=./tools/hitag2crack/crack5gpu/}"
if ! CheckFileExist "ht2crack5gpu exists" "$HT2CRACK5GPUPATH/ht2crack5gpu"; then break; fi
HT2CRACK5GPUUID=12345678
HT2CRACK5GPUKEY=AABBCCDDEEFF
# The speed depends on the nRaR so we'll use two pairs known to work fast
HT2CRACK5GPUNRAR="B438220C 944FFD74 942C59E3 3D450B34"
# Order of magnitude to crack it: ~15s -> tagged as "slow"
if ! CheckExecute slow gpu "ht2crack5gpu test" "cd $HT2CRACK5GPUPATH; ./ht2crack5gpu $HT2CRACK5GPUUID $HT2CRACK5GPUNRAR" "Key: $HT2CRACK5GPUKEY"; then break; fi
fi
if $TESTALL || $TESTCLIENT; then if $TESTALL || $TESTCLIENT; then
echo -e "\n${C_BLUE}Testing client:${C_NC} ${CLIENTBIN:=./client/proxmark3}" echo -e "\n${C_BLUE}Testing client:${C_NC} ${CLIENTBIN:=./client/proxmark3}"
if ! CheckFileExist "proxmark3 exists" "$CLIENTBIN"; then break; fi if ! CheckFileExist "proxmark3 exists" "$CLIENTBIN"; then break; fi
@ -261,7 +341,7 @@ while true; do
echo -e "\n${C_BLUE}Testing HF:${C_NC}" echo -e "\n${C_BLUE}Testing HF:${C_NC}"
if ! CheckExecute "hf mf offline text" "$CLIENTBIN -c 'hf mf'" "at_enc"; then break; fi if ! CheckExecute "hf mf offline text" "$CLIENTBIN -c 'hf mf'" "at_enc"; then break; fi
if ! CheckExecute slow "hf mf hardnested long test" "$CLIENTBIN -c 'hf mf hardnested t 1 000000000000'" "found:" "repeat" "ignore"; then break; fi if ! CheckExecute slow retry ignore "hf mf hardnested long test" "$CLIENTBIN -c 'hf mf hardnested t 1 000000000000'" "found:"; then break; fi
if ! CheckExecute slow "hf iclass long test" "$CLIENTBIN -c 'hf iclass loclass t l'" "verified ok"; then break; fi if ! CheckExecute slow "hf iclass long test" "$CLIENTBIN -c 'hf iclass loclass t l'" "verified ok"; then break; fi
if ! CheckExecute slow "emv long test" "$CLIENTBIN -c 'emv test -l'" "Test(s) \[ OK"; then break; fi if ! CheckExecute slow "emv long test" "$CLIENTBIN -c 'emv test -l'" "Test(s) \[ OK"; then break; fi
if ! $SLOWTESTS; then if ! $SLOWTESTS; then