From 4cb4b588c276f8d3c3b4a18dc292d3bfd0e497b9 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 23 Mar 2017 18:06:14 +0100 Subject: [PATCH] Deduplicate mfkey32 and mfkey64 - rename client/nonce2key.[ch] to mfkey.[ch] - leave only main() wrapper in tools/mfkey - add mfkey32 and mfkey64 to .gitignore --- .gitignore | 8 +- client/Makefile | 2 +- client/cmdhfmf.c | 2 +- client/{nonce2key.c => mfkey.c} | 24 +---- client/{nonce2key.h => mfkey.h} | 10 +- client/mifarehost.c | 3 +- client/mifarehost.h | 5 + common/crapto1/readme | 27 +++++ tools/mfkey/Makefile | 8 +- tools/mfkey/mfkey32.c | 94 +++++++++-------- tools/mfkey/mfkey64.c | 178 ++++++++++++++++---------------- 11 files changed, 192 insertions(+), 169 deletions(-) rename client/{nonce2key.c => mfkey.c} (86%) rename client/{nonce2key.h => mfkey.h} (78%) create mode 100644 common/crapto1/readme diff --git a/.gitignore b/.gitignore index 4af73fb1..d08c67b8 100644 --- a/.gitignore +++ b/.gitignore @@ -14,14 +14,16 @@ *.dll *.moc.cpp *.z +version.c + *.exe -proxmark proxmark3 flasher -version.c lua luac fpga_compress +mfkey32 +mfkey64 fpga/* !fpga/tests @@ -34,5 +36,3 @@ fpga/* !fpga/xst_hf.scr !fpga/go.bat !fpga/sim.tcl - - diff --git a/client/Makefile b/client/Makefile index ac7e6f98..1df870b5 100644 --- a/client/Makefile +++ b/client/Makefile @@ -58,7 +58,7 @@ CORESRCS = uart.c \ CMDSRCS = crapto1/crapto1.c\ crapto1/crypto1.c\ - nonce2key.c\ + mfkey.c\ loclass/cipher.c \ loclass/cipherutils.c \ loclass/des.c \ diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 47660a6e..7a6aaa3b 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -19,7 +19,7 @@ #include "ui.h" #include "mifarehost.h" #include "mifare.h" -#include "nonce2key.h" +#include "mfkey.h" #define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up diff --git a/client/nonce2key.c b/client/mfkey.c similarity index 86% rename from client/nonce2key.c rename to client/mfkey.c index acd551e4..60cfcbbf 100644 --- a/client/nonce2key.c +++ b/client/mfkey.c @@ -10,15 +10,11 @@ // MIFARE Darkside hack //----------------------------------------------------------------------------- -#include "nonce2key.h" +#include "mfkey.h" -#include -#include -#include -#include "mifarehost.h" -#include "util.h" #include "crapto1/crapto1.h" + // recover key from 2 different reader responses on same tag challenge bool mfkey32(nonces_t data, uint64_t *outputkey) { struct Crypto1State *s,*t; @@ -27,8 +23,6 @@ bool mfkey32(nonces_t data, uint64_t *outputkey) { bool isSuccess = false; uint8_t counter = 0; - uint64_t t1 = msclock(); - s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0); for(t = s; t->odd | t->even; ++t) { @@ -46,8 +40,6 @@ bool mfkey32(nonces_t data, uint64_t *outputkey) { } } isSuccess = (counter == 1); - t1 = msclock() - t1; - //if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, counter); *outputkey = ( isSuccess ) ? outkey : 0; crypto1_destroy(s); /* //un-comment to save all keys to a stats.txt file @@ -70,9 +62,6 @@ bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) { bool isSuccess = false; int counter = 0; - //PrintAndLog("Enter mfkey32_moebius"); - uint64_t t1 = msclock(); - s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0); for(t = s; t->odd | t->even; ++t) { @@ -92,8 +81,6 @@ bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) { } } isSuccess = (counter == 1); - t1 = msclock() - t1; - // PrintAndLog("Time in mfkey32_moebius: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, counter); *outputkey = ( isSuccess ) ? outkey : 0; crypto1_destroy(s); /* // un-comment to output all keys to stats.txt @@ -115,9 +102,6 @@ int mfkey64(nonces_t data, uint64_t *outputkey){ uint32_t ks3; // keystream used to encrypt tag response struct Crypto1State *revstate; - // PrintAndLog("Enter mfkey64"); - uint64_t t1 = msclock(); - // Extract the keystream from the messages ks2 = data.ar ^ prng_successor(data.nonce, 64); ks3 = data.at ^ prng_successor(data.nonce, 96); @@ -131,7 +115,7 @@ int mfkey64(nonces_t data, uint64_t *outputkey){ crypto1_destroy(revstate); *outputkey = key; - t1 = msclock() - t1; - // PrintAndLog("Time in mfkey64: %.1f seconds \n", (float)t1/1000.0); return 0; } + + diff --git a/client/nonce2key.h b/client/mfkey.h similarity index 78% rename from client/nonce2key.h rename to client/mfkey.h index 795f239d..ad5a863d 100644 --- a/client/nonce2key.h +++ b/client/mfkey.h @@ -10,8 +10,8 @@ // MIFARE Darkside hack //----------------------------------------------------------------------------- -#ifndef __NONCE2KEY_H -#define __NONCE2KEY_H +#ifndef MFKEY_H +#define MFKEY_H #include #include @@ -29,8 +29,8 @@ typedef struct { uint32_t nr2; } nonces_t; -bool mfkey32(nonces_t data, uint64_t *outputkey); -bool mfkey32_moebius(nonces_t data, uint64_t *outputkey); -int mfkey64(nonces_t data, uint64_t *outputkey); +extern bool mfkey32(nonces_t data, uint64_t *outputkey); +extern bool mfkey32_moebius(nonces_t data, uint64_t *outputkey); +extern int mfkey64(nonces_t data, uint64_t *outputkey); #endif diff --git a/client/mifarehost.c b/client/mifarehost.c index cbd79cf7..c6c6877e 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -8,6 +8,8 @@ // mifare commands //----------------------------------------------------------------------------- +#include "mifarehost.h" + #include #include #include @@ -20,7 +22,6 @@ #include "ui.h" #include "util.h" #include "iso14443crc.h" -#include "mifarehost.h" // mifare tracer flags used in mfTraceDecode() #define TRACE_IDLE 0x00 diff --git a/client/mifarehost.h b/client/mifarehost.h index a9db4ec3..c5644442 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -8,6 +8,9 @@ // High frequency ISO14443A commands //----------------------------------------------------------------------------- +#ifndef MIFAREHOST_H +#define MIFAREHOST_H + #include #include #include "data.h" @@ -42,3 +45,5 @@ extern int isBlockTrailer(int blockN); extern int loadTraceCard(uint8_t *tuid); extern int saveTraceCard(void); extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); + +#endif diff --git a/common/crapto1/readme b/common/crapto1/readme new file mode 100644 index 00000000..d57fa3e0 --- /dev/null +++ b/common/crapto1/readme @@ -0,0 +1,27 @@ +CRAPTO1 +------- + Provides a set of library functions which aid the verification + of crypto1 weaknesses. + + In short a partial implementation of: + Dismantling MIFARE Classic + URL: http://www.sos.cs.ru.nl/applications/rfid/2008-esorics.pdf + Flavio D. Garcia, Gerhard de Koning Gans, Ruben Muijrers, + Peter van Rossum, Roel Verdult, Ronny Wichers Schreur, Bart Jacobs + Institute for Computing and Information Sciences, + Radboud University Nijmegen, The Netherlands + {{flaviog,petervr,ronny,bart}@cs, {gkoningg,rmuijrer,rverdult}@sci}.ru.nl + and + Wirelessly Pickpocketing a Mifare Classic Card + URL: http://www.cs.ru.nl/~flaviog/publications/Pickpocketing.Mifare.pdf + Flavio D. Garcia, Peter van Rossum, Roel Verdult, Ronny Wichers Schreur + Radboud University Nijmegen, The Netherlands + {flaviog,petervr,rverdult,ronny}@cs.ru.nl + and + THE DARK SIDE OF SECURITY BY OBSCURITY + URL: http://eprint.iacr.org/2009/137 + and Cloning MiFare Classic Rail and Building Passes, Anywhere, Anytime + Nicolas T. Courtois + University College London, Computer Science, + Gower street, WC1E 6BT, London, UK + diff --git a/tools/mfkey/Makefile b/tools/mfkey/Makefile index 73ce032f..da7d431a 100755 --- a/tools/mfkey/Makefile +++ b/tools/mfkey/Makefile @@ -1,10 +1,10 @@ -VPATH = ../../common/crapto1 +VPATH = ../../common/crapto1 ../../client CC = gcc LD = gcc -CFLAGS = -I../../common -Wall -O4 +CFLAGS = -I../../common -I../../client -Wall -O4 LDFLAGS = -OBJS = crypto1.o crapto1.o +OBJS = crypto1.o crapto1.o util.o mfkey.o EXES = mfkey32 mfkey64 WINEXES = $(patsubst %, %.exe, $(EXES)) @@ -13,7 +13,7 @@ all: $(OBJS) $(EXES) %.o : %.c $(CC) $(CFLAGS) -c -o $@ $< -% : %.c +% : %.c $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $< clean: diff --git a/tools/mfkey/mfkey32.c b/tools/mfkey/mfkey32.c index a018c5df..0b62f051 100755 --- a/tools/mfkey/mfkey32.c +++ b/tools/mfkey/mfkey32.c @@ -1,67 +1,77 @@ #include -#include "crapto1/crapto1.h" +#include #include #include +#include "crapto1/crapto1.h" +#include "mfkey.h" +#include "util.h" +// 32 bit recover key from 2 nonces +#include int main (int argc, char *argv[]) { - struct Crypto1State *s,*t; - uint64_t key; // recovered key - uint32_t uid; // serial number - uint32_t nt; // tag challenge - uint32_t nr0_enc; // first encrypted reader challenge - uint32_t ar0_enc; // first encrypted reader response - uint32_t nr1_enc; // second encrypted reader challenge - uint32_t ar1_enc; // second encrypted reader response + + nonces_t data; uint32_t ks2; // keystream used to encrypt reader response + uint64_t key; // recovered key - printf("MIFARE Classic key recovery - based 32 bits of keystream\n"); + printf("MIFARE Classic key recovery - based on 32 bits of keystream\n"); printf("Recover key from two 32-bit reader authentication answers only!\n\n"); - if (argc < 7) { - printf(" syntax: %s <{nr_0}> <{ar_0}> <{nr_1}> <{ar_1}>\n\n",argv[0]); + if (argc != 7 && argc != 8) { + printf(" syntax: %s <{nr_0}> <{ar_0}> [] <{nr_1}> <{ar_1}>\n", argv[0]); + printf(" (you may omit nt1 if it is equal to nt0)\n\n"); return 1; } - sscanf(argv[1],"%x",&uid); - sscanf(argv[2],"%x",&nt); - sscanf(argv[3],"%x",&nr0_enc); - sscanf(argv[4],"%x",&ar0_enc); - sscanf(argv[5],"%x",&nr1_enc); - sscanf(argv[6],"%x",&ar1_enc); + bool moebius_attack = (argc == 8); + + sscanf(argv[1],"%x",&data.cuid); + sscanf(argv[2],"%x",&data.nonce); + data.nonce2 = data.nonce; + sscanf(argv[3],"%x",&data.nr); + sscanf(argv[4],"%x",&data.ar); + if (moebius_attack) { + sscanf(argv[5],"%x",&data.nonce2); + sscanf(argv[6],"%x",&data.nr2); + sscanf(argv[7],"%x",&data.ar2); + } else { + sscanf(argv[5],"%x",&data.nr2); + sscanf(argv[6],"%x",&data.ar2); + } printf("Recovering key for:\n"); - printf(" uid: %08x\n",uid); - printf(" nt: %08x\n",nt); - printf(" {nr_0}: %08x\n",nr0_enc); - printf(" {ar_0}: %08x\n",ar0_enc); - printf(" {nr_1}: %08x\n",nr1_enc); - printf(" {ar_1}: %08x\n",ar1_enc); + printf(" uid: %08x\n",data.cuid); + printf(" nt0: %08x\n",data.nonce); + printf(" {nr_0}: %08x\n",data.nr); + printf(" {ar_0}: %08x\n",data.ar); + printf(" nt1: %08x\n",data.nonce2); + printf(" {nr_1}: %08x\n",data.nr2); + printf(" {ar_1}: %08x\n",data.ar2); + uint64_t start_time = msclock(); + // Generate lfsr succesors of the tag challenge printf("\nLFSR succesors of the tag challenge:\n"); - printf(" nt': %08x\n",prng_successor(nt, 64)); - printf(" nt'': %08x\n",prng_successor(nt, 96)); + printf(" nt': %08x\n",prng_successor(data.nonce, 64)); + printf(" nt'': %08x\n",prng_successor(data.nonce, 96)); // Extract the keystream from the messages printf("\nKeystream used to generate {ar} and {at}:\n"); - ks2 = ar0_enc ^ prng_successor(nt, 64); + ks2 = data.ar ^ prng_successor(data.nonce, 64); printf(" ks2: %08x\n",ks2); - s = lfsr_recovery32(ar0_enc ^ prng_successor(nt, 64), 0); - - for(t = s; t->odd | t->even; ++t) { - lfsr_rollback_word(t, 0, 0); - lfsr_rollback_word(t, nr0_enc, 1); - lfsr_rollback_word(t, uid ^ nt, 0); - crypto1_get_lfsr(t, &key); - crypto1_word(t, uid ^ nt, 0); - crypto1_word(t, nr1_enc, 1); - if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt, 64))) { - printf("\nFound Key: [%012" PRIx64 "]\n\n",key); - break; - } + bool success; + if (moebius_attack) { + success = mfkey32_moebius(data, &key); + } else { + success = mfkey32(data, &key); + } + + if (success) { + printf("Recovered key: %012" PRIx64 "\n", key); + } else { + printf("Couldn't recover key.\n"); } - free(s); - return 0; + printf("Time spent: %1.2f seconds\n", (float)(msclock() - start_time)/1000.0); } diff --git a/tools/mfkey/mfkey64.c b/tools/mfkey/mfkey64.c index 4b9b29ee..4e9876c5 100755 --- a/tools/mfkey/mfkey64.c +++ b/tools/mfkey/mfkey64.c @@ -1,105 +1,101 @@ +#include +#include #include #include "crapto1/crapto1.h" -#include -#include - -int main (int argc, char *argv[]) { - struct Crypto1State *revstate; - uint64_t key; // recovered key - uint32_t uid; // serial number - uint32_t nt; // tag challenge - uint32_t nr_enc; // encrypted reader challenge - uint32_t ar_enc; // encrypted reader response - uint32_t at_enc; // encrypted tag response - uint32_t ks2; // keystream used to encrypt reader response - uint32_t ks3; // keystream used to encrypt tag response +#include "util.h" - printf("MIFARE Classic key recovery - based 64 bits of keystream\n"); - printf("Recover key from only one complete authentication!\n\n"); +int main (int argc, char *argv[]) +{ + uint32_t uid; // serial numDber + uint32_t nt; // tag challenge + uint32_t nr_enc; // encrypted reader challenge + uint32_t ar_enc; // encrypted reader response + uint32_t at_enc; // encrypted tag response + uint64_t key = 0; // recovered key + struct Crypto1State *revstate; + uint32_t ks2; // keystream used to encrypt reader response + uint32_t ks3; // keystream used to encrypt tag response - if (argc < 6 ) { - printf(" syntax: %s <{nr}> <{ar}> <{at}> [enc] [enc...]\n\n", argv[0]); - return 1; - } + printf("MIFARE Classic key recovery - based on 64 bits of keystream\n"); + printf("Recover key from only one complete authentication!\n\n"); - int encc = argc - 6; - int enclen[encc]; - uint8_t enc[encc][120]; + if (argc < 6 ) { + printf(" syntax: %s <{nr}> <{ar}> <{at}> [enc] [enc...]\n\n", argv[0]); + return 1; + } - sscanf(argv[1], "%x", &uid); - sscanf(argv[2], "%x", &nt); - sscanf(argv[3], "%x", &nr_enc); - sscanf(argv[4], "%x", &ar_enc); - sscanf(argv[5], "%x", &at_enc); - for (int i = 0; i < encc; i++) { - enclen[i] = strlen(argv[i + 6]) / 2; - for (int i2 = 0; i2 < enclen[i]; i2++) { - sscanf(argv[i+6] + i2*2,"%2x", (unsigned int *)&enc[i][i2]); - } - } - printf("Recovering key for:\n"); + int encc = argc - 6; + int enclen[encc]; + uint8_t enc[encc][120]; - printf(" uid: %08x\n", uid); - printf(" nt: %08x\n", nt); - printf(" {nr}: %08x\n", nr_enc); - printf(" {ar}: %08x\n", ar_enc); - printf(" {at}: %08x\n", at_enc); - for (int i = 0; i < encc; i++) { - printf("{enc%d}: ", i); - for (int i2 = 0; i2 < enclen[i]; i2++) { - printf("%02x", enc[i][i2]); - } - printf("\n"); - } + sscanf(argv[1], "%x", &uid); + sscanf(argv[2], "%x", &nt); + sscanf(argv[3], "%x", &nr_enc); + sscanf(argv[4], "%x", &ar_enc); + sscanf(argv[5], "%x", &at_enc); + for (int i = 0; i < encc; i++) { + enclen[i] = strlen(argv[i + 6]) / 2; + for (int i2 = 0; i2 < enclen[i]; i2++) { + sscanf(argv[i+6] + i2*2,"%2x", (unsigned int*)&enc[i][i2]); + } + } + printf("Recovering key for:\n"); + printf(" uid: %08x\n", uid); + printf(" nt: %08x\n", nt); + printf(" {nr}: %08x\n", nr_enc); + printf(" {ar}: %08x\n", ar_enc); + printf(" {at}: %08x\n", at_enc); + for (int i = 0; i < encc; i++) { + printf("{enc%d}: ", i); + for (int i2 = 0; i2 < enclen[i]; i2++) { + printf("%02x", enc[i][i2]); + } + printf("\n"); + } - /* - uint32_t uid = 0x9c599b32; - uint32_t tag_challenge = 0x82a4166c; - uint32_t nr_enc = 0xa1e458ce; - uint32_t reader_response = 0x6eea41e0; - uint32_t tag_response = 0x5cadf439; -*/ - // Generate lfsr succesors of the tag challenge - printf("\nLFSR succesors of the tag challenge:\n"); - printf(" nt': %08x\n",prng_successor(nt, 64)); - printf(" nt'': %08x\n",prng_successor(nt, 96)); + printf("\nLFSR successors of the tag challenge:\n"); + printf(" nt' : %08x\n",prng_successor(nt, 64)); + printf(" nt'': %08x\n",prng_successor(nt, 96)); - // Extract the keystream from the messages - printf("\nKeystream used to generate {ar} and {at}:\n"); - ks2 = ar_enc ^ prng_successor(nt, 64); - ks3 = at_enc ^ prng_successor(nt, 96); - printf(" ks2: %08x\n",ks2); - printf(" ks3: %08x\n",ks3); + // Extract the keystream from the messages + ks2 = ar_enc ^ prng_successor(nt, 64); + ks3 = at_enc ^ prng_successor(nt, 96); + + uint64_t start_time = msclock(); + revstate = lfsr_recovery64(ks2, ks3); + uint64_t time_spent = msclock() - start_time; + printf("Time spent in lfsr_recovery64(): %1.2f seconds\n", (float)time_spent/1000.0); + printf("\nKeystream used to generate {ar} and {at}:\n"); + printf(" ks2: %08x\n",ks2); + printf(" ks3: %08x\n",ks3); - revstate = lfsr_recovery64(ks2, ks3); + // Decrypting communication using keystream if presented + if (argc > 6 ) { + printf("\nDecrypted communication:\n"); + uint8_t ks4; + int rollb = 0; + for (int i = 0; i < encc; i++) { + printf("{dec%d}: ", i); + for (int i2 = 0; i2 < enclen[i]; i2++) { + ks4 = crypto1_byte(revstate, 0, 0); + printf("%02x", ks4 ^ enc[i][i2]); + rollb += 1; + } + printf("\n"); + } + for (int i = 0; i < rollb; i++) { + lfsr_rollback_byte(revstate, 0, 0); + } + } - // Decrypting communication using keystream if presented - if (argc > 6 ) { - printf("\nDecrypted communication:\n"); - uint8_t ks4; - int rollb = 0; - for (int i = 0; i < encc; i++) { - printf("{dec%d}: ", i); - for (int i2 = 0; i2 < enclen[i]; i2++) { - ks4 = crypto1_byte(revstate, 0, 0); - printf("%02x", ks4 ^ enc[i][i2]); - rollb += 1; - } - printf("\n"); - } - for (int i = 0; i < rollb; i++) { - lfsr_rollback_byte(revstate, 0, 0); - } - } - - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, nr_enc, 1); - lfsr_rollback_word(revstate, uid ^ nt, 0); - crypto1_get_lfsr(revstate, &key); - printf("\nFound Key: [%012" PRIx64"]\n\n",key); - crypto1_destroy(revstate); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, nr_enc, 1); + lfsr_rollback_word(revstate, uid ^ nt, 0); + crypto1_get_lfsr(revstate, &key); + crypto1_destroy(revstate); - return 0; + printf("\nFound Key: [%012" PRIx64"]\n\n",key); + } -- 2.39.5