Mfp commands (#698)
authorOleg Moiseenko <807634+merlokk@users.noreply.github.com>
Wed, 24 Oct 2018 16:58:12 +0000 (19:58 +0300)
committerpwpiwi <pwpiwi@users.noreply.github.com>
Wed, 24 Oct 2018 16:58:12 +0000 (18:58 +0200)
* add write perso from https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua
* commit perso from https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L184
* added errors https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L91
* fix bug in CLIParamHexToBuf
* added init card command
* auth4 refactoring
* add changelog

CHANGELOG.md
client/Makefile
client/cliparser/cliparser.c
client/cliparser/cliparser.h
client/cmdhf14a.c
client/cmdhfmf.c
client/cmdhfmfp.c
client/mifare4.c [new file with mode: 0644]
client/mifare4.h [new file with mode: 0644]
common/polarssl/libpcrypto.c [new file with mode: 0644]
common/polarssl/libpcrypto.h [new file with mode: 0644]

index fbc40cda0a0c74dfb1708aa8cf0d1ef9bc5950f5..5f1847e1d8eb854d89bb1fc80add0abe38458a69 100644 (file)
@@ -9,6 +9,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 ### Fixed
 
 ### Added
+- `hf mfp` group of commands (Merlok)
 
 ## [v3.1.0][2018-10-10]
 
index c0a319a4c58be4f7485cb421b3979ac071f38592..72d5080d5e82d26dc13f8124fa8a2e57b2db8a2f 100644 (file)
@@ -110,6 +110,7 @@ CMDSRCS =   $(SRC_SMARTCARD) \
                        polarssl/bignum.c\
                        polarssl/rsa.c\
                        polarssl/sha1.c\
+                       polarssl/libpcrypto.c\
                        cliparser/argtable3.c\
                        cliparser/cliparser.c\
                        mfkey.c\
@@ -120,6 +121,7 @@ CMDSRCS =   $(SRC_SMARTCARD) \
                        loclass/fileutils.c\
                        whereami.c\
                        mifarehost.c\
+                       mifare4.c\
                        parity.c\
                        crc.c \
                        crc16.c \
index 931d68cd20dbeed1a99c948ec0a0ed17d430cc67..954220398c655ce5d8009dbb69f8e75afdbbd08e 100644 (file)
@@ -156,7 +156,7 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
        
        int ibuf = 0;
        uint8_t buf[256] = {0};
-       int res = CLIParamStrToBuf(argstr, buf, maxdatalen, &ibuf);
+       int res = CLIParamStrToBuf(argstr, buf, maxdatalen * 2, &ibuf); // *2 because here HEX
        if (res || !ibuf)
                return res;
        
index 2f5ac317ad1f078465f4ab93e0161796e7b5817c..c4bc7068e4020f05b9230273685d5f89c5540e13 100644 (file)
@@ -17,6 +17,7 @@
 
 #define arg_getsize(a) (sizeof(a) / sizeof(a[0]))
 #define arg_get_lit(n)(((struct arg_lit*)argtable[n])->count)
+#define arg_get_int_count(n)(((struct arg_int*)argtable[n])->count)
 #define arg_get_int(n)(((struct arg_int*)argtable[n])->ival[0])
 #define arg_get_str(n)((struct arg_str*)argtable[n])
 #define arg_get_str_len(n)(strlen(((struct arg_str*)argtable[n])->sval[0]))
index 316541884edd4c54d565e9ec1991daae210d8443..326eaf50f91316a7540d61e1702e10e06c494e4e 100644 (file)
@@ -750,6 +750,11 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
         recv = resp.d.asBytes;
         int iLen = resp.arg[0];
                
+        if(!iLen) {
+                       PrintAndLog("14aRAW ERROR: No card response.");
+            return 1;
+               }
+               
                *dataoutlen = iLen - 2;
                if (*dataoutlen < 0)
                        *dataoutlen = 0;
@@ -766,11 +771,6 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
                
                memcpy(dataout, &recv[2], *dataoutlen);
                
-        if(!iLen) {
-                       PrintAndLog("14aRAW ERROR: No card response.");
-            return 1;
-               }
-
                // CRC Check
                if (iLen == -1) {
                        PrintAndLog("14aRAW ERROR: ISO 14443A CRC error.");
index eb85b8c578f0ceaa5f3ff5f7465c5287f764de4c..83180e7d096975cc8d0a41a4b12ddbac9368bc2f 100644 (file)
@@ -29,7 +29,7 @@
 #include "hardnested/hardnested_bf_core.h"\r
 #include "cliparser/cliparser.h"\r
 #include "cmdhf14a.h"\r
-#include <polarssl/aes.h>\r
+#include "mifare4.h"\r
 \r
 #define NESTED_SECTOR_RETRY     10                     // how often we try mfested() until we give up\r
 \r
@@ -2637,50 +2637,12 @@ int CmdDecryptTraceCmds(const char *Cmd){
        return tryDecryptWord(param_get32ex(Cmd,0,0,16),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),data,len/2);\r
 }\r
 \r
-int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){\r
-       uint8_t iiv[16] = {0};\r
-       if (iv)\r
-               memcpy(iiv, iv, 16);\r
-       \r
-       aes_context aes;\r
-       aes_init(&aes);\r
-       if (aes_setkey_enc(&aes, key, 128))\r
-               return 1;\r
-       if (aes_crypt_cbc(&aes, AES_ENCRYPT, length, iiv, input, output))\r
-               return 2;\r
-       aes_free(&aes);\r
-\r
-       return 0;\r
-}\r
-\r
-int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){\r
-       uint8_t iiv[16] = {0};\r
-       if (iv)\r
-               memcpy(iiv, iv, 16);\r
-       \r
-       aes_context aes;\r
-       aes_init(&aes);\r
-       if (aes_setkey_dec(&aes, key, 128))\r
-               return 1;\r
-       if (aes_crypt_cbc(&aes, AES_DECRYPT, length, iiv, input, output))\r
-               return 2;\r
-       aes_free(&aes);\r
-\r
-       return 0;\r
-}\r
-\r
 int CmdHF14AMfAuth4(const char *cmd) {\r
        uint8_t keyn[20] = {0};\r
        int keynlen = 0;\r
        uint8_t key[16] = {0};\r
        int keylen = 0;\r
-       uint8_t data[257] = {0};\r
-       int datalen = 0;\r
-       \r
-       uint8_t Rnd1[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00};\r
-       uint8_t Rnd2[17] = {0};\r
-       \r
-       \r
+\r
        CLIParserInit("hf mf auth4", \r
                "Executes AES authentication command in ISO14443-4", \r
                "Usage:\n\thf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n"\r
@@ -2694,8 +2656,8 @@ int CmdHF14AMfAuth4(const char *cmd) {
        };\r
        CLIExecWithReturn(cmd, argtable, true);\r
        \r
-       CLIGetStrWithReturn(1, keyn, &keynlen);\r
-       CLIGetStrWithReturn(2, key, &keylen);\r
+       CLIGetHexWithReturn(1, keyn, &keynlen);\r
+       CLIGetHexWithReturn(2, key, &keylen);\r
        CLIParserFree();\r
        \r
        if (keynlen != 2) {\r
@@ -2708,73 +2670,7 @@ int CmdHF14AMfAuth4(const char *cmd) {
                return 1;\r
        }\r
 \r
-       uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00};\r
-       int res = ExchangeRAW14a(cmd1, sizeof(cmd1), true, true, data, sizeof(data), &datalen);\r
-       if (res) {\r
-               PrintAndLog("ERROR exchande raw error: %d", res);\r
-               DropField();\r
-               return 2;\r
-       }\r
-       \r
-       PrintAndLog("<phase1: %s", sprint_hex(data, datalen));\r
-               \r
-       if (datalen < 1) {\r
-               PrintAndLog("ERROR: card response length: %d", datalen);\r
-               DropField();\r
-               return 3;\r
-       }\r
-       \r
-       if (data[0] != 0x90) {\r
-               PrintAndLog("ERROR: card response error: %02x", data[2]);\r
-               DropField();\r
-               return 3;\r
-       }\r
-\r
-       if (datalen != 19) { // code 1b + 16b + crc 2b\r
-               PrintAndLog("ERROR: card response must be 19 bytes long instead of: %d", datalen);\r
-               DropField();\r
-               return 3;\r
-       }\r
-       \r
-    aes_decode(NULL, key, &data[1], Rnd2, 16);\r
-       Rnd2[16] = Rnd2[0];\r
-       PrintAndLog("Rnd2: %s", sprint_hex(Rnd2, 16));\r
-\r
-       uint8_t cmd2[33] = {0};\r
-       cmd2[0] = 0x72;\r
-\r
-       uint8_t raw[32] = {0};\r
-       memmove(raw, Rnd1, 16);\r
-       memmove(&raw[16], &Rnd2[1], 16);\r
-\r
-    aes_encode(NULL, key, raw, &cmd2[1], 32);\r
-       PrintAndLog(">phase2: %s", sprint_hex(cmd2, 33));\r
-       \r
-       res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, false, data, sizeof(data), &datalen);\r
-       if (res) {\r
-               PrintAndLog("ERROR exchande raw error: %d", res);\r
-               DropField();\r
-               return 4;\r
-       }\r
-       \r
-       PrintAndLog("<phase2: %s", sprint_hex(data, datalen));\r
-\r
-    aes_decode(NULL, key, &data[1], raw, 32);\r
-       PrintAndLog("res: %s", sprint_hex(raw, 32));\r
-       \r
-       PrintAndLog("Rnd1`: %s", sprint_hex(&raw[4], 16));\r
-       if (memcmp(&raw[4], &Rnd1[1], 16)) {\r
-               PrintAndLog("\nERROR: Authentication FAILED. rnd not equal");\r
-               PrintAndLog("rnd1 reader: %s", sprint_hex(&Rnd1[1], 16));\r
-               PrintAndLog("rnd1   card: %s", sprint_hex(&raw[4], 16));\r
-               DropField();\r
-               return 5;\r
-       }\r
-\r
-       DropField();\r
-       PrintAndLog("\nAuthentication OK");\r
-       \r
-       return 0;\r
+       return MifareAuth4(NULL, keyn, key, true, false, true);\r
 }\r
 \r
 static command_t CommandTable[] =\r
index 34abbed0db432d2d66a18c0b93539c8371f7b63f..a4c53f56d8882bb8beb3b1cd2c73d7b4a2669101 100644 (file)
 #include "ui.h"
 #include "cmdhf14a.h"
 #include "mifare.h"
+#include "mifare4.h"
+#include "cliparser/cliparser.h"
+#include "polarssl/libpcrypto.h"
+
+static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+typedef struct {
+       uint8_t Code;
+       const char *Description;
+} PlusErrorsElm;
+
+static const PlusErrorsElm PlusErrors[] = {
+       {0xFF, ""},
+       {0x00, "Unknown error"},
+       {0x09, "Invalid block number"},
+       {0x0b, "Command code error"},
+       {0x0c, "Length error"},
+       {0x90, "OK"},
+};
+int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm);
+
+const char * GetErrorDescription(uint8_t errorCode) {
+       for(int i = 0; i < PlusErrorsLen; i++)
+               if (errorCode == PlusErrors[i].Code)
+                       return PlusErrors[i].Description;
+               
+       return PlusErrors[0].Description;
+}
 
 static int CmdHelp(const char *Cmd);
 
+static bool VerboseMode = false;
+void SetVerboseMode(bool verbose) {
+       VerboseMode = verbose;
+}
+
+int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
+       if(VerboseMode)
+               PrintAndLog(">>> %s", sprint_hex(datain, datainlen));
+       
+       int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
+
+       if(VerboseMode)
+               PrintAndLog("<<< %s", sprint_hex(dataout, *dataoutlen));
+       
+       return res;
+}
+
+int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
+       uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
+       memmove(&rcmd[3], key, 16);
+       
+       return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
+}
+
+int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
+       uint8_t rcmd[1] = {0xaa};
+       
+       return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
+}
+
 int CmdHFMFPInfo(const char *cmd) {
        
        if (cmd && strlen(cmd) > 0)
@@ -103,10 +161,254 @@ int CmdHFMFPInfo(const char *cmd) {
        return 0;
 }
 
+int CmdHFMFPWritePerso(const char *cmd) {
+       uint8_t keyNum[64] = {0};
+       int keyNumLen = 0;
+       uint8_t key[64] = {0};
+       int keyLen = 0;
+
+       CLIParserInit("hf mfp wrp", 
+               "Executes Write Perso command. Can be used in SL0 mode only.", 
+               "Usage:\n\thf mfp wrp 4000 000102030405060708090a0b0c0d0e0f -> write key (00..0f) to key number 4000 \n"
+                       "\thf mfp wrp 4000 -> write default key(0xff..0xff) to key number 4000");
+
+       void* argtable[] = {
+               arg_param_begin,
+               arg_lit0("vV",  "verbose", "show internal data."),
+               arg_str1(NULL,  NULL,      "<HEX key number (2b)>", NULL),
+               arg_strx0(NULL,  NULL,     "<HEX key (16b)>", NULL),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
+       
+       bool verbose = arg_get_lit(1);
+       CLIGetHexWithReturn(2, keyNum, &keyNumLen);
+       CLIGetHexWithReturn(3, key, &keyLen);
+       CLIParserFree();
+       
+       SetVerboseMode(verbose);
+       
+       if (!keyLen) {
+               memmove(key, DefaultKey, 16);
+               keyLen = 16;
+       }
+       
+       if (keyNumLen != 2) {
+               PrintAndLog("Key number length must be 2 bytes instead of: %d", keyNumLen);
+               return 1;
+       }
+       if (keyLen != 16) {
+               PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
+               return 1;
+       }
+
+       uint8_t data[250] = {0};
+       int datalen = 0;
+
+       int res = MFPWritePerso(keyNum, key, true, false, data, sizeof(data), &datalen);
+       if (res) {
+               PrintAndLog("Exchange error: %d", res);
+               return res;
+       }
+       
+       if (datalen != 3) {
+               PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
+               return 1;
+       }
+
+       if (data[0] != 0x90) {
+               PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0]));
+               return 1;
+       }
+       PrintAndLog("Write OK.");
+       
+       return 0;
+}
+
+uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
+
+int CmdHFMFPInitPerso(const char *cmd) {
+       int res;
+       uint8_t key[256] = {0};
+       int keyLen = 0;
+       uint8_t keyNum[2] = {0};
+       uint8_t data[250] = {0};
+       int datalen = 0;
+
+       CLIParserInit("hf mfp initp", 
+               "Executes Write Perso command for all card's keys. Can be used in SL0 mode only.", 
+               "Usage:\n\thf mfp initp 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)\n"
+                       "\thf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange");
+
+       void* argtable[] = {
+               arg_param_begin,
+               arg_litn("vV",  "verbose", 0, 2, "show internal data."),
+               arg_strx0(NULL,  NULL,      "<HEX key (16b)>", NULL),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
+       
+       bool verbose = arg_get_lit(1);
+       bool verbose2 = arg_get_lit(1) > 1;
+       CLIGetHexWithReturn(2, key, &keyLen);
+       CLIParserFree();
+
+       if (keyLen && keyLen != 16) {
+               PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
+               return 1;
+       }
+       
+       if (!keyLen)
+               memmove(key, DefaultKey, 16);
+
+       SetVerboseMode(verbose2);
+       for (uint16_t sn = 0x4000; sn < 0x4050; sn++) {
+               keyNum[0] = sn >> 8;
+               keyNum[1] = sn & 0xff;
+               res = MFPWritePerso(keyNum, key, (sn == 0x4000), true, data, sizeof(data), &datalen);
+               if (!res && (datalen == 3) && data[0] == 0x09) {
+                       PrintAndLog("2k card detected.");
+                       break;
+               }
+               if (res || (datalen != 3) || data[0] != 0x90) {
+                       PrintAndLog("Write error on address %04x", sn);
+                       break;
+               }
+       }
+       
+       SetVerboseMode(verbose);
+       for (int i = 0; i < sizeof(CardAddresses) / 2; i++) {
+               keyNum[0] = CardAddresses[i] >> 8;
+               keyNum[1] = CardAddresses[i] & 0xff;
+               res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen);
+               if (!res && (datalen == 3) && data[0] == 0x09) {
+                       PrintAndLog("Skipped[%04x]...", CardAddresses[i]);
+               } else {
+                       if (res || (datalen != 3) || data[0] != 0x90) {
+                               PrintAndLog("Write error on address %04x", CardAddresses[i]);
+                               break;
+                       }
+               }
+       }
+       
+       DropField();
+       
+       if (res)
+               return res;
+       
+       PrintAndLog("Done.");
+       
+       return 0;
+}
+
+int CmdHFMFPCommitPerso(const char *cmd) {
+       CLIParserInit("hf mfp commitp", 
+               "Executes Commit Perso command. Can be used in SL0 mode only.", 
+               "Usage:\n\thf mfp commitp ->  \n");
+
+       void* argtable[] = {
+               arg_param_begin,
+               arg_lit0("vV",  "verbose", "show internal data."),
+               arg_int0(NULL,  NULL,      "SL mode", NULL),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
+       
+       bool verbose = arg_get_lit(1);
+       CLIParserFree();
+       
+       SetVerboseMode(verbose);
+       
+       uint8_t data[250] = {0};
+       int datalen = 0;
+
+       int res = MFPCommitPerso(true, false, data, sizeof(data), &datalen);
+       if (res) {
+               PrintAndLog("Exchange error: %d", res);
+               return res;
+       }
+       
+       if (datalen != 3) {
+               PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
+               return 1;
+       }
+
+       if (data[0] != 0x90) {
+               PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0]));
+               return 1;
+       }
+       PrintAndLog("Switch level OK.");
+
+       return 0;
+}
+
+int CmdHFMFPAuth(const char *cmd) {
+       uint8_t keyn[250] = {0};
+       int keynlen = 0;
+       uint8_t key[250] = {0};
+       int keylen = 0;
+       
+       CLIParserInit("hf mfp auth", 
+               "Executes AES authentication command in ISO14443-4", 
+               "Usage:\n\thf mfp auth 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
+                       "\thf mfp auth 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data\n");
+
+       void* argtable[] = {
+               arg_param_begin,
+               arg_lit0("vV",  "verbose", "show internal data."),
+               arg_str1(NULL,  NULL,     "<Key Num (HEX 2 bytes)>", NULL),
+               arg_str1(NULL,  NULL,     "<Key Value (HEX 16 bytes)>", NULL),
+               arg_param_end
+       };
+       CLIExecWithReturn(cmd, argtable, true);
+       
+       bool verbose = arg_get_lit(1);
+       CLIGetHexWithReturn(2, keyn, &keynlen);
+       CLIGetHexWithReturn(3, key, &keylen);
+       CLIParserFree();
+       
+       if (keynlen != 2) {
+               PrintAndLog("ERROR: <Key Num> must be 2 bytes long instead of: %d", keynlen);
+               return 1;
+       }
+       
+       if (keylen != 16) {
+               PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
+               return 1;
+       }
+
+       return MifareAuth4(NULL, keyn, key, true, false, verbose);
+}
+
+int CmdHFMFPRdbl(const char *cmd) {
+       //mf4Session session
+       //int res = MifareAuth4(&session, keyn, key, true, false, verbose);
+       //res = Read();
+       
+       return 0;
+}
+
+int CmdHFMFPRdsc(const char *cmd) {
+       
+       return 0;
+}
+
+int CmdHFMFPWrbl(const char *cmd) {
+       
+       return 0;
+}
+
 static command_t CommandTable[] =
 {
   {"help",             CmdHelp,                                        1, "This help"},
   {"info",            CmdHFMFPInfo,                    0, "Info about Mifare Plus tag"},
+  {"wrp",                     CmdHFMFPWritePerso,              0, "Write Perso command"},
+  {"initp",           CmdHFMFPInitPerso,               0, "Fills all the card's keys"},
+  {"commitp",                 CmdHFMFPCommitPerso,             0, "Move card to SL1 or SL3 mode"},
+  {"auth",            CmdHFMFPAuth,                    0, "Authentication in iso1443-4"},
+//  {"rdbl",          CmdHFMFPRdbl,                    0, "Read blocks"},
+//  {"rdsc",          CmdHFMFPRdsc,                    0, "Read sectors"},
+//  {"wrbl",          CmdHFMFPWrbl,                    0, "Write blocks"},
   {NULL,               NULL,                                   0, NULL}
 };
 
diff --git a/client/mifare4.c b/client/mifare4.c
new file mode 100644 (file)
index 0000000..3489c85
--- /dev/null
@@ -0,0 +1,118 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 Merlok
+//
+// 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.
+//-----------------------------------------------------------------------------
+// iso14443-4 mifare commands
+//-----------------------------------------------------------------------------
+
+#include "mifare4.h"
+#include <ctype.h>
+#include <string.h>
+#include "cmdhf14a.h"
+#include "util.h"
+#include "ui.h"
+#include "polarssl/libpcrypto.h"
+
+int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) {
+       uint8_t data[257] = {0};
+       int datalen = 0;
+       
+       uint8_t Rnd1[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00};
+       uint8_t Rnd2[17] = {0};
+       
+       if (session)
+               session->Authenticated = false; 
+       
+       uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00};
+       int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen);
+       if (res) {
+               PrintAndLog("ERROR exchande raw error: %d", res);
+               DropField();
+               return 2;
+       }
+       
+       if (verbose)
+               PrintAndLog("<phase1: %s", sprint_hex(data, datalen));
+               
+       if (datalen < 1) {
+               PrintAndLog("ERROR: card response length: %d", datalen);
+               DropField();
+               return 3;
+       }
+       
+       if (data[0] != 0x90) {
+               PrintAndLog("ERROR: card response error: %02x", data[2]);
+               DropField();
+               return 3;
+       }
+
+       if (datalen != 19) { // code 1b + 16b + crc 2b
+               PrintAndLog("ERROR: card response must be 19 bytes long instead of: %d", datalen);
+               DropField();
+               return 3;
+       }
+       
+    aes_decode(NULL, key, &data[1], Rnd2, 16);
+       Rnd2[16] = Rnd2[0];
+       if (verbose)
+               PrintAndLog("Rnd2: %s", sprint_hex(Rnd2, 16));
+
+       uint8_t cmd2[33] = {0};
+       cmd2[0] = 0x72;
+
+       uint8_t raw[32] = {0};
+       memmove(raw, Rnd1, 16);
+       memmove(&raw[16], &Rnd2[1], 16);
+
+       aes_encode(NULL, key, raw, &cmd2[1], 32);
+       if (verbose)
+               PrintAndLog(">phase2: %s", sprint_hex(cmd2, 33));
+       
+       res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, false, data, sizeof(data), &datalen);
+       if (res) {
+               PrintAndLog("ERROR exchande raw error: %d", res);
+               DropField();
+               return 4;
+       }
+       
+       if (verbose)
+               PrintAndLog("<phase2: %s", sprint_hex(data, datalen));
+
+       aes_decode(NULL, key, &data[1], raw, 32);
+       
+       if (verbose) {
+               PrintAndLog("res: %s", sprint_hex(raw, 32));
+               PrintAndLog("Rnd1`: %s", sprint_hex(&raw[4], 16));
+       }
+
+       if (memcmp(&raw[4], &Rnd1[1], 16)) {
+               PrintAndLog("\nERROR: Authentication FAILED. rnd not equal");
+               if (verbose) {
+                       PrintAndLog("rnd1 reader: %s", sprint_hex(&Rnd1[1], 16));
+                       PrintAndLog("rnd1   card: %s", sprint_hex(&raw[4], 16));
+               }
+               DropField();
+               return 5;
+       }
+
+       if (!leaveSignalON)
+               DropField();
+
+       if (verbose)
+               PrintAndLog("");
+
+       if (session) {
+               session->Authenticated = true;
+               session->KeyNum = keyn[1] + (keyn[0] << 8);
+               memmove(session->Rnd1, Rnd1, 16);
+               memmove(session->Rnd2, Rnd2, 16);
+       }
+       
+       PrintAndLog("Authentication OK");
+       
+       return 0;
+}
+
diff --git a/client/mifare4.h b/client/mifare4.h
new file mode 100644 (file)
index 0000000..7071184
--- /dev/null
@@ -0,0 +1,30 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 Merlok
+//
+// 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.
+//-----------------------------------------------------------------------------
+// iso14443-4 mifare commands
+//-----------------------------------------------------------------------------
+
+#ifndef MIFARE4_H
+#define MIFARE4_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+typedef struct {
+       bool Authenticated;
+       uint16_t KeyNum;
+       uint8_t Rnd1[16];
+       uint8_t Rnd2[16];
+       
+}mf4Session;
+
+extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose);
+
+
+
+#endif // mifare4.h
diff --git a/common/polarssl/libpcrypto.c b/common/polarssl/libpcrypto.c
new file mode 100644 (file)
index 0000000..032c3a1
--- /dev/null
@@ -0,0 +1,44 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 Merlok
+//
+// 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.
+//-----------------------------------------------------------------------------
+// crypto commands
+//-----------------------------------------------------------------------------
+
+#include "polarssl/libpcrypto.h"
+#include <polarssl/aes.h>
+
+int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){
+       uint8_t iiv[16] = {0};
+       if (iv)
+               memcpy(iiv, iv, 16);
+       
+       aes_context aes;
+       aes_init(&aes);
+       if (aes_setkey_enc(&aes, key, 128))
+               return 1;
+       if (aes_crypt_cbc(&aes, AES_ENCRYPT, length, iiv, input, output))
+               return 2;
+       aes_free(&aes);
+
+       return 0;
+}
+
+int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){
+       uint8_t iiv[16] = {0};
+       if (iv)
+               memcpy(iiv, iv, 16);
+       
+       aes_context aes;
+       aes_init(&aes);
+       if (aes_setkey_dec(&aes, key, 128))
+               return 1;
+       if (aes_crypt_cbc(&aes, AES_DECRYPT, length, iiv, input, output))
+               return 2;
+       aes_free(&aes);
+
+       return 0;
+}
\ No newline at end of file
diff --git a/common/polarssl/libpcrypto.h b/common/polarssl/libpcrypto.h
new file mode 100644 (file)
index 0000000..84732cd
--- /dev/null
@@ -0,0 +1,20 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2018 Merlok
+//
+// 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.
+//-----------------------------------------------------------------------------
+// crypto commands
+//-----------------------------------------------------------------------------
+
+#ifndef LIBPCRYPTO_H
+#define LIBPCRYPTO_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length);
+extern int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length);
+
+#endif /* libpcrypto.h */
Impressum, Datenschutz