X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/c8a0f5503172f25620670a9ba992d8c923b5df95..ac4ecfe35327f827aeaf8426af2662c656affd2c:/client/mifare4.c diff --git a/client/mifare4.c b/client/mifare4.c index e1021196..419e9b23 100644 --- a/client/mifare4.c +++ b/client/mifare4.c @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2018 Merlok +// Copyright (C) 2018 drHatson // // 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 @@ -14,26 +15,133 @@ #include "cmdhf14a.h" #include "util.h" #include "ui.h" -#include "polarssl/libpcrypto.h" +#include "crypto/libpcrypto.h" -int CalculateMAC(mf4Session *session, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { - if (!session || !session->Authenticated || !mac || !data || !datalen) +AccessConditions_t MFAccessConditions[] = { + {0x00, "read AB; write AB; increment AB; decrement transfer restore AB"}, + {0x01, "read AB; decrement transfer restore AB"}, + {0x02, "read AB"}, + {0x03, "read B; write B"}, + {0x04, "read AB; writeB"}, + {0x05, "read B"}, + {0x06, "read AB; write B; increment B; decrement transfer restore AB"}, + {0x07, "none"} +}; + +AccessConditions_t MFAccessConditionsTrailer[] = { + {0x00, "read A by A; read ACCESS by A; read B by A; write B by A"}, + {0x01, "write A by A; read ACCESS by A write ACCESS by A; read B by A; write B by A"}, + {0x02, "read ACCESS by A; read B by A"}, + {0x03, "write A by B; read ACCESS by AB; write ACCESS by B; write B by B"}, + {0x04, "write A by B; read ACCESS by AB; write B by B"}, + {0x05, "read ACCESS by AB; write ACCESS by B"}, + {0x06, "read ACCESS by AB"}, + {0x07, "read ACCESS by AB"} +}; + +char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) { + static char StaticNone[] = "none"; + + uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn; + uint8_t data2 = ((data[2]) & 0x0f) >> blockn; + uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn; + + uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01); + + if (blockn == 3) { + for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++) + if (MFAccessConditionsTrailer[i].cond == cond) { + return MFAccessConditionsTrailer[i].description; + } + } else { + for (int i = 0; i < ARRAYLEN(MFAccessConditions); i++) + if (MFAccessConditions[i].cond == cond) { + return MFAccessConditions[i].description; + } + }; + + return StaticNone; +}; + +int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) { + memcpy(&iv[0], session->TI, 4); + memcpy(&iv[4], &session->R_Ctr, 2); + memcpy(&iv[6], &session->W_Ctr, 2); + memcpy(&iv[8], &session->R_Ctr, 2); + memcpy(&iv[10], &session->W_Ctr, 2); + memcpy(&iv[12], &session->R_Ctr, 2); + memcpy(&iv[14], &session->W_Ctr, 2); + + return 0; +} + +int CalculateEncIVResponse(mf4Session *session, uint8_t *iv, bool verbose) { + memcpy(&iv[0], &session->R_Ctr, 2); + memcpy(&iv[2], &session->W_Ctr, 2); + memcpy(&iv[4], &session->R_Ctr, 2); + memcpy(&iv[6], &session->W_Ctr, 2); + memcpy(&iv[8], &session->R_Ctr, 2); + memcpy(&iv[10], &session->W_Ctr, 2); + memcpy(&iv[12], session->TI, 4); + + return 0; +} + + +int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { + if (!session || !session->Authenticated || !mac || !data || !datalen || datalen < 1) return 1; memset(mac, 0x00, 8); + + uint16_t ctr = session->R_Ctr; + switch(mtype) { + case mtypWriteCmd: + case mtypWriteResp: + ctr = session->W_Ctr; + break; + case mtypReadCmd: + case mtypReadResp: + break; + } + + uint8_t macdata[2049] = {data[0], (ctr & 0xFF), (ctr >> 8), 0}; + int macdatalen = datalen; + memcpy(&macdata[3], session->TI, 4); + + switch(mtype) { + case mtypReadCmd: + memcpy(&macdata[7], &data[1], datalen - 1); + macdatalen = datalen + 6; + break; + case mtypReadResp: + macdata[7] = blockNum; + macdata[8] = 0; + macdata[9] = blockCount; + memcpy(&macdata[10], &data[1], datalen - 1); + macdatalen = datalen + 9; + break; + case mtypWriteCmd: + memcpy(&macdata[7], &data[1], datalen - 1); + macdatalen = datalen + 6; + break; + case mtypWriteResp: + macdatalen = 1 + 6; + break; + } if (verbose) - PrintAndLog("MAC data[%d]: %s", datalen, sprint_hex(data, datalen)); + PrintAndLog("MAC data[%d]: %s", macdatalen, sprint_hex(macdata, macdatalen)); - return aes_cmac8(NULL, session->Key, data, mac, datalen); + return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen); } 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}; + uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; + uint8_t RndB[17] = {0}; if (session) session->Authenticated = false; @@ -67,17 +175,17 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF return 3; } - aes_decode(NULL, key, &data[1], Rnd2, 16); - Rnd2[16] = Rnd2[0]; + aes_decode(NULL, key, &data[1], RndB, 16); + RndB[16] = RndB[0]; if (verbose) - PrintAndLog("Rnd2: %s", sprint_hex(Rnd2, 16)); + PrintAndLog("RndB: %s", sprint_hex(RndB, 16)); uint8_t cmd2[33] = {0}; cmd2[0] = 0x72; uint8_t raw[32] = {0}; - memmove(raw, Rnd1, 16); - memmove(&raw[16], &Rnd2[1], 16); + memmove(raw, RndA, 16); + memmove(&raw[16], &RndB[1], 16); aes_encode(NULL, key, raw, &cmd2[1], 32); if (verbose) @@ -97,19 +205,49 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF if (verbose) { PrintAndLog("res: %s", sprint_hex(raw, 32)); - PrintAndLog("Rnd1`: %s", sprint_hex(&raw[4], 16)); + PrintAndLog("RndA`: %s", sprint_hex(&raw[4], 16)); } - if (memcmp(&raw[4], &Rnd1[1], 16)) { + if (memcmp(&raw[4], &RndA[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)); + PrintAndLog("RndA reader: %s", sprint_hex(&RndA[1], 16)); + PrintAndLog("RndA card: %s", sprint_hex(&raw[4], 16)); } DropField(); return 5; } + if (verbose) { + PrintAndLog(" TI: %s", sprint_hex(raw, 4)); + PrintAndLog("pic: %s", sprint_hex(&raw[20], 6)); + PrintAndLog("pcd: %s", sprint_hex(&raw[26], 6)); + } + + uint8_t kenc[16] = {0}; + memcpy(&kenc[0], &RndA[11], 5); + memcpy(&kenc[5], &RndB[11], 5); + for(int i = 0; i < 5; i++) + kenc[10 + i] = RndA[4 + i] ^ RndB[4 + i]; + kenc[15] = 0x11; + + aes_encode(NULL, key, kenc, kenc, 16); + if (verbose) { + PrintAndLog("kenc: %s", sprint_hex(kenc, 16)); + } + + uint8_t kmac[16] = {0}; + memcpy(&kmac[0], &RndA[7], 5); + memcpy(&kmac[5], &RndB[7], 5); + for(int i = 0; i < 5; i++) + kmac[10 + i] = RndA[0 + i] ^ RndB[0 + i]; + kmac[15] = 0x22; + + aes_encode(NULL, key, kmac, kmac, 16); + if (verbose) { + PrintAndLog("kmac: %s", sprint_hex(kmac, 16)); + } + if (!leaveSignalON) DropField(); @@ -118,10 +256,17 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF if (session) { session->Authenticated = true; + session->R_Ctr = 0; + session->W_Ctr = 0; session->KeyNum = keyn[1] + (keyn[0] << 8); - memmove(session->Rnd1, Rnd1, 16); - memmove(session->Rnd2, Rnd2, 16); + memmove(session->RndA, RndA, 16); + memmove(session->RndB, RndB, 16); memmove(session->Key, key, 16); + memmove(session->TI, raw, 4); + memmove(session->PICCap2, &raw[20], 6); + memmove(session->PCDCap2, &raw[26], 6); + memmove(session->Kenc, kenc, 16); + memmove(session->Kmac, kmac, 16); } PrintAndLog("Authentication OK");