From: Iceman Date: Sun, 26 Mar 2017 13:24:07 +0000 (+0200) Subject: Merge pull request #252 from marshmellow42/master X-Git-Tag: v3.0.0~30 X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/79375850fded8543748afc75f60700484de6617d?hp=9b99a6dbdb981e490af7951a1ac952aefab3cab7 Merge pull request #252 from marshmellow42/master adjust lf menu descriptions --- 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/armsrc/Makefile b/armsrc/Makefile index b698d1f2..73c2290e 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -20,7 +20,7 @@ SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c SRC_ISO14443b = iso14443b.c SRC_CRAPTO1 = crypto1.c des.c aes.c -SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c +SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.c #the FPGA bitstream files. Note: order matters! FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 76b82141..bd3bd845 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -21,6 +21,8 @@ #include "mifareutil.h" #include "BigBuf.h" #include "protocols.h" +#include "parity.h" + static uint32_t iso14a_timeout; int rsamples = 0; @@ -123,25 +125,6 @@ static uint32_t LastProxToAirDuration; #define SEC_Y 0x00 #define SEC_Z 0xc0 -const uint8_t OddByteParity[256] = { - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 -}; - void iso14a_set_trigger(bool enable) { trigger = enable; @@ -180,11 +163,6 @@ void iso14a_set_ATS_timeout(uint8_t *ats) { // Generate the parity value for a byte sequence // //----------------------------------------------------------------------------- -byte_t oddparity (const byte_t bt) -{ - return OddByteParity[bt]; -} - void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) { uint16_t paritybit_cnt = 0; @@ -193,7 +171,7 @@ void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) for (uint16_t i = 0; i < iLen; i++) { // Generate the parity bits - parityBits |= ((OddByteParity[pbtCmd[i]]) << (7-paritybit_cnt)); + parityBits |= ((oddparity8(pbtCmd[i])) << (7-paritybit_cnt)); if (paritybit_cnt == 7) { par[paritybyte_cnt] = parityBits; // save 8 Bits parity parityBits = 0; // and advance to next Parity Byte diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index ec99ab99..60833f18 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -12,6 +12,7 @@ #ifndef __ISO14443A_H #define __ISO14443A_H + #include "common.h" #include "mifaresniff.h" @@ -70,8 +71,6 @@ typedef struct { } tUart; - -extern byte_t oddparity (const byte_t bt); extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); extern void AppendCrc14443a(uint8_t *data, int len); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index a3d6609d..8f141d65 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -16,6 +16,7 @@ #include "mifarecmd.h" #include "apps.h" #include "util.h" +#include "parity.h" #include "crc.h" // the block number for the ISO14443-4 PCB @@ -595,9 +596,9 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ // Return 1 if the nonce is invalid else return 0 int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) { - return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ - (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ - (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; + return ((oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ + (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ + (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; } @@ -770,7 +771,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // Parity validity check for (j = 0; j < 4; j++) { - par_array[j] = (oddparity(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); + par_array[j] = (oddparity8(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); } ncount = 0; diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 48fcd57a..6c843778 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -13,6 +13,7 @@ #include "proxmark3.h" #include "apps.h" #include "util.h" +#include "parity.h" #include "string.h" #include "iso14443crc.h" @@ -50,7 +51,7 @@ void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, u data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i]; if((i&0x0007) == 0) par[i>>3] = 0; - par[i>>3] |= (((filter(pcs->odd) ^ oddparity(bt)) & 0x01)<<(7-(i&0x0007))); + par[i>>3] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01)<<(7-(i&0x0007))); } return; } @@ -99,7 +100,7 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, for (pos = 0; pos < 4; pos++) { ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos]; - par[0] |= (((filter(pcs->odd) ^ oddparity(dcmd[pos])) & 0x01) << (7-pos)); + par[0] |= (((filter(pcs->odd) ^ oddparity8(dcmd[pos])) & 0x01) << (7-pos)); } ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing); @@ -193,7 +194,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN for (pos = 0; pos < 4; pos++) { mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos]; - par[0] |= (((filter(pcs->odd) ^ oddparity(nr[pos])) & 0x01) << (7-pos)); + par[0] |= (((filter(pcs->odd) ^ oddparity8(nr[pos])) & 0x01) << (7-pos)); } // Skip 32 bits in pseudo random generator @@ -204,7 +205,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN { nt = prng_successor(nt,8); mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff); - par[0] |= (((filter(pcs->odd) ^ oddparity(nt & 0xff)) & 0x01) << (7-pos)); + par[0] |= (((filter(pcs->odd) ^ oddparity8(nt)) & 0x01) << (7-pos)); } // Transmit reader nonce and reader answer @@ -427,7 +428,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl for (pos = 0; pos < 18; pos++) { d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; - par[pos>>3] |= (((filter(pcs->odd) ^ oddparity(d_block[pos])) & 0x01) << (7 - (pos&0x0007))); + par[pos>>3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos&0x0007))); } ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); diff --git a/client/Makefile b/client/Makefile index 4bac1ac9..d5bfb086 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 \ @@ -67,6 +67,7 @@ CMDSRCS = crapto1/crapto1.c\ loclass/fileutils.c\ whereami.c\ mifarehost.c\ + parity.c\ crc.c \ crc16.c \ crc64.c \ diff --git a/client/cmdhf.c b/client/cmdhf.c index cb71b93b..dcfb1bdd 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -16,6 +16,7 @@ #include "data.h" #include "ui.h" #include "iso14443crc.h" +#include "parity.h" #include "cmdmain.h" #include "cmdparser.h" #include "cmdhf.h" @@ -481,14 +482,8 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui for (int j = 0; j < data_len && j/16 < 16; j++) { - int oddparity = 0x01; - int k; - - for (k=0 ; k<8 ; k++) { - oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); - } uint8_t parityBits = parityBytes[j>>3]; - if (protocol != ISO_14443B && (isResponse || protocol == ISO_14443A) && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + if (protocol != ISO_14443B && (isResponse || protocol == ISO_14443A) && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]); } else { snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]); 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/cmdlfhitag.c b/client/cmdlfhitag.c index 47a85a1a..718cb703 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -17,6 +17,7 @@ #include "cmdparser.h" #include "common.h" #include "util.h" +#include "parity.h" #include "hitag2.h" #include "hitagS.h" #include "cmdmain.h" @@ -107,15 +108,9 @@ int CmdLFHitagList(const char *Cmd) char line[1000] = ""; int j; for (j = 0; j < len; j++) { - int oddparity = 0x01; - int k; - - for (k=0;k<8;k++) { - oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); - } //if((parityBits >> (len - j - 1)) & 0x01) { - if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { + if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) { sprintf(line+(j*4), "%02x! ", frame[j]); } else { diff --git a/client/mfkey.c b/client/mfkey.c new file mode 100644 index 00000000..60cfcbbf --- /dev/null +++ b/client/mfkey.c @@ -0,0 +1,121 @@ +//----------------------------------------------------------------------------- +// Merlok - June 2011 +// Roel - Dec 2009 +// Unknown author +// +// 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. +//----------------------------------------------------------------------------- +// MIFARE Darkside hack +//----------------------------------------------------------------------------- + +#include "mfkey.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; + uint64_t outkey = 0; + uint64_t key = 0; // recovered key + bool isSuccess = false; + uint8_t counter = 0; + + s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0); + + for(t = s; t->odd | t->even; ++t) { + lfsr_rollback_word(t, 0, 0); + lfsr_rollback_word(t, data.nr, 1); + lfsr_rollback_word(t, data.cuid ^ data.nonce, 0); + crypto1_get_lfsr(t, &key); + crypto1_word(t, data.cuid ^ data.nonce, 0); + crypto1_word(t, data.nr2, 1); + if (data.ar2 == (crypto1_word(t, 0, 0) ^ prng_successor(data.nonce, 64))) { + //PrintAndLog("Found Key: [%012" PRIx64 "]",key); + outkey = key; + counter++; + if (counter == 20) break; + } + } + isSuccess = (counter == 1); + *outputkey = ( isSuccess ) ? outkey : 0; + crypto1_destroy(s); + /* //un-comment to save all keys to a stats.txt file + FILE *fout; + if ((fout = fopen("stats.txt","ab")) == NULL) { + PrintAndLog("Could not create file name stats.txt"); + return 1; + } + fprintf(fout, "mfkey32,%d,%08x,%d,%s,%04x%08x,%.0Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); + fclose(fout); + */ + return isSuccess; +} + +// recover key from 2 reader responses on 2 different tag challenges +bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) { + struct Crypto1State *s, *t; + uint64_t outkey = 0; + uint64_t key = 0; // recovered key + bool isSuccess = false; + int counter = 0; + + s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0); + + for(t = s; t->odd | t->even; ++t) { + lfsr_rollback_word(t, 0, 0); + lfsr_rollback_word(t, data.nr, 1); + lfsr_rollback_word(t, data.cuid ^ data.nonce, 0); + crypto1_get_lfsr(t, &key); + + crypto1_word(t, data.cuid ^ data.nonce2, 0); + crypto1_word(t, data.nr2, 1); + if (data.ar2 == (crypto1_word(t, 0, 0) ^ prng_successor(data.nonce2, 64))) { + //PrintAndLog("Found Key: [%012" PRIx64 "]",key); + outkey=key; + ++counter; + if (counter==20) + break; + } + } + isSuccess = (counter == 1); + *outputkey = ( isSuccess ) ? outkey : 0; + crypto1_destroy(s); + /* // un-comment to output all keys to stats.txt + FILE *fout; + if ((fout = fopen("stats.txt","ab")) == NULL) { + PrintAndLog("Could not create file name stats.txt"); + return 1; + } + fprintf(fout, "moebius,%d,%08x,%d,%s,%04x%08x,%0.Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); + fclose(fout); + */ + return isSuccess; +} + +// recover key from reader response and tag response of one authentication sequence +int mfkey64(nonces_t data, uint64_t *outputkey){ + uint64_t key = 0; // recovered key + uint32_t ks2; // keystream used to encrypt reader response + uint32_t ks3; // keystream used to encrypt tag response + struct Crypto1State *revstate; + + // Extract the keystream from the messages + ks2 = data.ar ^ prng_successor(data.nonce, 64); + ks3 = data.at ^ prng_successor(data.nonce, 96); + revstate = lfsr_recovery64(ks2, ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, data.nr, 1); + lfsr_rollback_word(revstate, data.cuid ^ data.nonce, 0); + crypto1_get_lfsr(revstate, &key); + // PrintAndLog("Found Key: [%012" PRIx64 "]", key); + crypto1_destroy(revstate); + *outputkey = key; + + return 0; +} + + diff --git a/client/mfkey.h b/client/mfkey.h new file mode 100644 index 00000000..ad5a863d --- /dev/null +++ b/client/mfkey.h @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Merlok - June 2011 +// Roel - Dec 2009 +// Unknown author +// +// 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. +//----------------------------------------------------------------------------- +// MIFARE Darkside hack +//----------------------------------------------------------------------------- + +#ifndef MFKEY_H +#define MFKEY_H + +#include +#include + +typedef struct { + uint32_t cuid; + uint8_t sector; + uint8_t keytype; + uint32_t nonce; + uint32_t ar; + uint32_t nr; + uint32_t at; + uint32_t nonce2; + uint32_t ar2; + uint32_t nr2; + } nonces_t; + +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/client/nonce2key.c b/client/nonce2key.c deleted file mode 100644 index acd551e4..00000000 --- a/client/nonce2key.c +++ /dev/null @@ -1,137 +0,0 @@ -//----------------------------------------------------------------------------- -// Merlok - June 2011 -// Roel - Dec 2009 -// Unknown author -// -// 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. -//----------------------------------------------------------------------------- -// MIFARE Darkside hack -//----------------------------------------------------------------------------- - -#include "nonce2key.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; - uint64_t outkey = 0; - uint64_t key = 0; // recovered key - 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) { - lfsr_rollback_word(t, 0, 0); - lfsr_rollback_word(t, data.nr, 1); - lfsr_rollback_word(t, data.cuid ^ data.nonce, 0); - crypto1_get_lfsr(t, &key); - crypto1_word(t, data.cuid ^ data.nonce, 0); - crypto1_word(t, data.nr2, 1); - if (data.ar2 == (crypto1_word(t, 0, 0) ^ prng_successor(data.nonce, 64))) { - //PrintAndLog("Found Key: [%012" PRIx64 "]",key); - outkey = key; - counter++; - if (counter == 20) break; - } - } - 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 - FILE *fout; - if ((fout = fopen("stats.txt","ab")) == NULL) { - PrintAndLog("Could not create file name stats.txt"); - return 1; - } - fprintf(fout, "mfkey32,%d,%08x,%d,%s,%04x%08x,%.0Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); - fclose(fout); - */ - return isSuccess; -} - -// recover key from 2 reader responses on 2 different tag challenges -bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) { - struct Crypto1State *s, *t; - uint64_t outkey = 0; - uint64_t key = 0; // recovered key - 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) { - lfsr_rollback_word(t, 0, 0); - lfsr_rollback_word(t, data.nr, 1); - lfsr_rollback_word(t, data.cuid ^ data.nonce, 0); - crypto1_get_lfsr(t, &key); - - crypto1_word(t, data.cuid ^ data.nonce2, 0); - crypto1_word(t, data.nr2, 1); - if (data.ar2 == (crypto1_word(t, 0, 0) ^ prng_successor(data.nonce2, 64))) { - //PrintAndLog("Found Key: [%012" PRIx64 "]",key); - outkey=key; - ++counter; - if (counter==20) - break; - } - } - 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 - FILE *fout; - if ((fout = fopen("stats.txt","ab")) == NULL) { - PrintAndLog("Could not create file name stats.txt"); - return 1; - } - fprintf(fout, "moebius,%d,%08x,%d,%s,%04x%08x,%0.Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1); - fclose(fout); - */ - return isSuccess; -} - -// recover key from reader response and tag response of one authentication sequence -int mfkey64(nonces_t data, uint64_t *outputkey){ - uint64_t key = 0; // recovered key - uint32_t ks2; // keystream used to encrypt reader response - 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); - revstate = lfsr_recovery64(ks2, ks3); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, data.nr, 1); - lfsr_rollback_word(revstate, data.cuid ^ data.nonce, 0); - crypto1_get_lfsr(revstate, &key); - // PrintAndLog("Found Key: [%012" PRIx64 "]", key); - 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/nonce2key.h deleted file mode 100644 index 795f239d..00000000 --- a/client/nonce2key.h +++ /dev/null @@ -1,36 +0,0 @@ -//----------------------------------------------------------------------------- -// Merlok - June 2011 -// Roel - Dec 2009 -// Unknown author -// -// 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. -//----------------------------------------------------------------------------- -// MIFARE Darkside hack -//----------------------------------------------------------------------------- - -#ifndef __NONCE2KEY_H -#define __NONCE2KEY_H - -#include -#include - -typedef struct { - uint32_t cuid; - uint8_t sector; - uint8_t keytype; - uint32_t nonce; - uint32_t ar; - uint32_t nr; - uint32_t at; - uint32_t nonce2; - uint32_t ar2; - 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); - -#endif diff --git a/client/util.c b/client/util.c index 7c70d55d..d07c915c 100644 --- a/client/util.c +++ b/client/util.c @@ -27,6 +27,7 @@ #ifndef _WIN32 #include #include +#include int ukbhit(void) { @@ -34,19 +35,18 @@ int ukbhit(void) int error; static struct termios Otty, Ntty; - - if ( tcgetattr( 0, &Otty) == -1 ) return -1; + if ( tcgetattr(STDIN_FILENO, &Otty) == -1 ) return -1; Ntty = Otty; - Ntty.c_iflag = 0; /* input mode */ - Ntty.c_oflag = 0; /* output mode */ - Ntty.c_lflag &= ~ICANON; /* raw mode */ - Ntty.c_cc[VMIN] = CMIN; /* minimum time to wait */ - Ntty.c_cc[VTIME] = CTIME; /* minimum characters to wait for */ - - if (0 == (error = tcsetattr(0, TCSANOW, &Ntty))) { - error += ioctl(0, FIONREAD, &cnt); - error += tcsetattr(0, TCSANOW, &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 ); diff --git a/common/crapto1/crapto1.c b/common/crapto1/crapto1.c index 01351731..9187460b 100644 --- a/common/crapto1/crapto1.c +++ b/common/crapto1/crapto1.c @@ -18,7 +18,9 @@ Copyright (C) 2008-2014 bla */ #include "crapto1.h" + #include +#include "parity.h" #if !defined LOWMEM && defined __GNUC__ static uint8_t filterlut[1 << 20]; @@ -117,8 +119,8 @@ update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2) { uint32_t p = *item >> 25; - p = p << 1 | parity(*item & mask1); - p = p << 1 | parity(*item & mask2); + p = p << 1 | evenparity32(*item & mask1); + p = p << 1 | evenparity32(*item & mask2); *item = p << 24 | (*item & 0xffffff); } @@ -174,10 +176,10 @@ recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, if(rem == -1) { for(e = e_head; e <= e_tail; ++e) { - *e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4); + *e = *e << 1 ^ evenparity32(*e & LF_POLY_EVEN) ^ !!(in & 4); for(o = o_head; o <= o_tail; ++o, ++sl) { sl->even = *o; - sl->odd = *e ^ parity(*o & LF_POLY_ODD); + sl->odd = *e ^ evenparity32(*o & LF_POLY_ODD); sl[1].odd = sl[1].even = 0; } } @@ -329,30 +331,30 @@ struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3) continue; for(j = 0; j < 19; ++j) - low = low << 1 | parity(i & S1[j]); + low = low << 1 | evenparity32(i & S1[j]); for(j = 0; j < 32; ++j) - hi[j] = parity(i & T1[j]); + hi[j] = evenparity32(i & T1[j]); for(; tail >= table; --tail) { for(j = 0; j < 3; ++j) { *tail = *tail << 1; - *tail |= parity((i & C1[j]) ^ (*tail & C2[j])); + *tail |= evenparity32((i & C1[j]) ^ (*tail & C2[j])); if(filter(*tail) != oks[29 + j]) goto continue2; } for(j = 0; j < 19; ++j) - win = win << 1 | parity(*tail & S2[j]); + win = win << 1 | evenparity32(*tail & S2[j]); win ^= low; for(j = 0; j < 32; ++j) { - win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]); + win = win << 1 ^ hi[j] ^ evenparity32(*tail & T2[j]); if(filter(win) != eks[j]) goto continue2; } - *tail = *tail << 1 | parity(LF_POLY_EVEN & *tail); - sl->odd = *tail ^ parity(LF_POLY_ODD & win); + *tail = *tail << 1 | evenparity32(LF_POLY_EVEN & *tail); + sl->odd = *tail ^ evenparity32(LF_POLY_ODD & win); sl->even = win; ++sl; sl->odd = sl->even = 0; @@ -380,7 +382,7 @@ uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) out ^= !!in; out ^= (ret = filter(s->odd)) & !!fb; - s->even |= parity(out) << 23; + s->even |= evenparity32(out) << 23; return ret; } /** lfsr_rollback_byte @@ -486,11 +488,11 @@ check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], nr = ks1 ^ (prefix | c << 5); rr = ks2 ^ rresp; - good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); - good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); - good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); - good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); - good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3; + good &= evenparity32(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); + good &= evenparity32(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); + good &= evenparity32(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); + good &= evenparity32(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); + good &= evenparity32(rr & 0x000000ff) ^ parities[c][7] ^ ks3; } return sl + good; diff --git a/common/crapto1/crapto1.h b/common/crapto1/crapto1.h index e718b1f2..8e79d224 100644 --- a/common/crapto1/crapto1.h +++ b/common/crapto1/crapto1.h @@ -25,7 +25,7 @@ extern "C" { #endif struct Crypto1State {uint32_t odd, even;}; -#if defined(__arm__) +#if defined(__arm__) && !defined(__linux__) && !defined(_WIN32) && !defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free() void crypto1_create(struct Crypto1State *s, uint64_t key); #else struct Crypto1State *crypto1_create(uint64_t key); @@ -53,7 +53,7 @@ int nonce_distance(uint32_t from, uint32_t to); int __i;\ for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\ for(__i = FSIZE - 1; __i >= 0; __i--)\ - if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\ + if(BIT(FILTER, __i) ^ evenparity32(__M & 0xFF01))\ break;\ else if(__i)\ __M = prng_successor(__M, (__i == 7) ? 48 : 8);\ @@ -63,24 +63,6 @@ int nonce_distance(uint32_t from, uint32_t to); #define LF_POLY_EVEN (0x870804) #define BIT(x, n) ((x) >> (n) & 1) #define BEBIT(x, n) BIT(x, (n) ^ 24) -static inline int parity(uint32_t x) -{ -#if !defined __i386__ || !defined __GNUC__ - x ^= x >> 16; - x ^= x >> 8; - x ^= x >> 4; - return BIT(0x6996, x & 0xf); -#else - __asm( "movl %1, %%eax\n" - "mov %%ax, %%cx\n" - "shrl $0x10, %%eax\n" - "xor %%ax, %%cx\n" - "xor %%ch, %%cl\n" - "setpo %%al\n" - "movzx %%al, %0\n": "=r"(x) : "r"(x): "eax","ecx"); - return x; -#endif -} static inline int filter(uint32_t const x) { uint32_t f; diff --git a/common/crapto1/crypto1.c b/common/crapto1/crypto1.c index a3f64a9f..19b71cbb 100644 --- a/common/crapto1/crypto1.c +++ b/common/crapto1/crypto1.c @@ -18,12 +18,14 @@ Copyright (C) 2008-2008 bla */ #include "crapto1.h" + #include +#include "parity.h" #define SWAPENDIAN(x)\ (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) -#if defined(__arm__) && !defined(__linux__) && !defined(_WIN32) // bare metal ARM lacks malloc()/free() +#if defined(__arm__) && !defined(__linux__) && !defined(_WIN32) && !defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free() void crypto1_create(struct Crypto1State *s, uint64_t key) { int i; @@ -73,7 +75,7 @@ uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) feedin ^= !!in; feedin ^= LF_POLY_ODD & s->odd; feedin ^= LF_POLY_EVEN & s->even; - s->even = s->even << 1 | parity(feedin); + s->even = s->even << 1 | evenparity32(feedin); t = s->odd, s->odd = s->even, s->even = t; 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/common/parity.c b/common/parity.c new file mode 100644 index 00000000..5eabd3ef --- /dev/null +++ b/common/parity.c @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------------- +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// parity functions (all defined in parity.h) +//----------------------------------------------------------------------------- + +#include + +const uint8_t OddByteParity[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 +}; diff --git a/common/parity.h b/common/parity.h new file mode 100644 index 00000000..615fdeee --- /dev/null +++ b/common/parity.h @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Parity functions +//----------------------------------------------------------------------------- + +// all functions defined in header file by purpose. Allows compiler optimizations. + +#ifndef __PARITY_H +#define __PARITY_H + +#include +#include + +extern const uint8_t OddByteParity[256]; + + +static inline bool oddparity8(const uint8_t x) { + return OddByteParity[x]; +} + + +static inline bool evenparity8(const uint8_t x) { + return !OddByteParity[x]; +} + + +static inline bool evenparity32(uint32_t x) +{ +#if !defined __GNUC__ + x ^= x >> 16; + x ^= x >> 8; + return evenparity8(x); +#else + return __builtin_parity(x); +#endif +} + + +static inline bool oddparity32(uint32_t x) +{ +#if !defined __GNUC__ + x ^= x >> 16; + x ^= x >> 8; + return oddparity8(x); +#else + return !__builtin_parity(x); +#endif +} + +#endif /* __PARITY_H */ diff --git a/tools/mfkey/Makefile b/tools/mfkey/Makefile index 73ce032f..fc6170e4 100755 --- a/tools/mfkey/Makefile +++ b/tools/mfkey/Makefile @@ -1,10 +1,10 @@ -VPATH = ../../common/crapto1 +VPATH = ../../common ../../common/crapto1 ../../client CC = gcc LD = gcc -CFLAGS = -I../../common -Wall -O4 +CFLAGS = -std=c99 -D_ISOC99_SOURCE -I../../common -I../../client -Wall -O3 LDFLAGS = -OBJS = crypto1.o crapto1.o +OBJS = crypto1.o crapto1.o parity.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..4ab4bad4 100755 --- a/tools/mfkey/mfkey32.c +++ b/tools/mfkey/mfkey32.c @@ -1,67 +1,76 @@ #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 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..1b002812 100755 --- a/tools/mfkey/mfkey64.c +++ b/tools/mfkey/mfkey64.c @@ -1,105 +1,101 @@ -#include -#include "crapto1/crapto1.h" #include #include +#include +#include "crapto1/crapto1.h" +#include "util.h" -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 - - 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); + }