*.dll
*.moc.cpp
*.z
+version.c
+
*.exe
-proxmark
proxmark3
flasher
-version.c
lua
luac
fpga_compress
+mfkey32
+mfkey64
fpga/*
!fpga/tests
!fpga/xst_hf.scr
!fpga/go.bat
!fpga/sim.tcl
-
-
CMDSRCS = crapto1/crapto1.c\
crapto1/crypto1.c\
- nonce2key.c\
+ mfkey.c\
loclass/cipher.c \
loclass/cipherutils.c \
loclass/des.c \
#include "ui.h"\r
#include "mifarehost.h"\r
#include "mifare.h"\r
-#include "nonce2key.h"\r
+#include "mfkey.h"\r
\r
#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up\r
\r
--- /dev/null
+//-----------------------------------------------------------------------------
+// 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;
+}
+
+
--- /dev/null
+//-----------------------------------------------------------------------------
+// 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 <stdint.h>
+#include <stdbool.h>
+
+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
// mifare commands\r
//-----------------------------------------------------------------------------\r
\r
+#include "mifarehost.h"\r
+\r
#include <stdio.h>\r
#include <stdlib.h> \r
#include <string.h>\r
#include "ui.h"\r
#include "util.h"\r
#include "iso14443crc.h"\r
-#include "mifarehost.h"\r
\r
// mifare tracer flags used in mfTraceDecode()\r
#define TRACE_IDLE 0x00\r
// High frequency ISO14443A commands\r
//-----------------------------------------------------------------------------\r
\r
+#ifndef MIFAREHOST_H\r
+#define MIFAREHOST_H\r
+\r
#include <stdint.h>\r
#include <stdbool.h>\r
#include "data.h"\r
extern int loadTraceCard(uint8_t *tuid);\r
extern int saveTraceCard(void);\r
extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);\r
+\r
+#endif\r
+++ /dev/null
-//-----------------------------------------------------------------------------
-// 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 <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#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;
-}
+++ /dev/null
-//-----------------------------------------------------------------------------
-// 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 <stdint.h>
-#include <stdbool.h>
-
-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
#ifndef _WIN32
#include <termios.h>
#include <sys/ioctl.h>
+#include <unistd.h>
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 );
#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);
#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;
--- /dev/null
+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
+
-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))
%.o : %.c
$(CC) $(CFLAGS) -c -o $@ $<
-% : %.c
+% : %.c $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $<
clean:
#include <inttypes.h>
-#include "crapto1/crapto1.h"
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#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 <uid> <nt> <{nr_0}> <{ar_0}> <{nr_1}> <{ar_1}>\n\n",argv[0]);
+ if (argc != 7 && argc != 8) {
+ printf(" syntax: %s <uid> <nt0> <{nr_0}> <{ar_0}> [<nt1>] <{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);
}
+#include <stdio.h>
+#include <strings.h>
#include <inttypes.h>
#include "crapto1/crapto1.h"
-#include <stdio.h>
-#include <string.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
+#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 <uid> <nt> <{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 <uid> <nt> <{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);
+
}