Fixes
This commit is contained in:
@@ -30,17 +30,13 @@
|
||||
#include <string.h>
|
||||
#include <util.h>
|
||||
#include "commonutil.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "mbedtls/des.h"
|
||||
#include "aes.h"
|
||||
#include "des.h"
|
||||
#include "ui.h"
|
||||
#include "crc.h"
|
||||
#include "crc16.h" // crc16 ccitt
|
||||
#include "crc32.h"
|
||||
|
||||
mbedtls_des_context ctx;
|
||||
mbedtls_des3_context ctx3;
|
||||
mbedtls_aes_context actx;
|
||||
|
||||
#ifndef AddCrc14A
|
||||
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
#endif
|
||||
@@ -58,17 +54,20 @@ static inline void update_key_schedules(desfirekey_t key) {
|
||||
/******************************************************************************/
|
||||
|
||||
void des_encrypt(void *out, const void *in, const void *key) {
|
||||
mbedtls_des_context ctx;
|
||||
mbedtls_des_setkey_enc(&ctx, key);
|
||||
mbedtls_des_crypt_ecb(&ctx, in, out);
|
||||
}
|
||||
|
||||
void des_decrypt(void *out, const void *in, const void *key) {
|
||||
mbedtls_des_context ctx;
|
||||
mbedtls_des_setkey_dec(&ctx, key);
|
||||
mbedtls_des_crypt_ecb(&ctx, in, out);
|
||||
}
|
||||
|
||||
void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode) {
|
||||
if (length % 8) return;
|
||||
mbedtls_des3_context ctx3;
|
||||
if (keymode == 2) mbedtls_des3_set2key_dec(&ctx3, key);
|
||||
else mbedtls_des3_set3key_dec(&ctx3, key);
|
||||
|
||||
@@ -95,6 +94,7 @@ void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key,
|
||||
|
||||
void tdes_nxp_send(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode) {
|
||||
if (length % 8) return;
|
||||
mbedtls_des3_context ctx3;
|
||||
if (keymode == 2) mbedtls_des3_set2key_enc(&ctx3, key);
|
||||
else mbedtls_des3_set3key_enc(&ctx3, key);
|
||||
|
||||
@@ -556,9 +556,11 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||
mifare_cypher_blocks_chained(tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER);
|
||||
|
||||
if (0 != memcmp((uint8_t *)data + *nbytes, (uint8_t *)edata + edl - 8, 4)) {
|
||||
#ifdef WITH_DEBUG
|
||||
PrintAndLogEx(NORMAL, "Expected MAC %s", sprint_hex(data + *nbytes, key_macing_length(key)));
|
||||
PrintAndLogEx(NORMAL, "Actual MAC %s", sprint_hex(edata + edl - 8, key_macing_length(key)));
|
||||
#ifdef WITH_DEBUG
|
||||
#endif
|
||||
#ifdef WITH_DEBUG
|
||||
Dbprintf("MACing not verified");
|
||||
hexdump((uint8_t *)data + *nbytes, key_macing_length(key), "Expect ", 0);
|
||||
hexdump((uint8_t *)edata + edl - 8, key_macing_length(key), "Actual ", 0);
|
||||
@@ -768,43 +770,52 @@ void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect,
|
||||
break;
|
||||
case T_3DES:
|
||||
switch (operation) {
|
||||
case MCO_ENCYPHER:
|
||||
case MCO_ENCYPHER: {
|
||||
mbedtls_des3_context ctx3;
|
||||
mbedtls_des3_set2key_enc(&ctx3, key->data);
|
||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||
break;
|
||||
case MCO_DECYPHER:
|
||||
}
|
||||
case MCO_DECYPHER: {
|
||||
mbedtls_des3_context ctx3;
|
||||
mbedtls_des3_set2key_dec(&ctx3, key->data);
|
||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_3K3DES:
|
||||
switch (operation) {
|
||||
case MCO_ENCYPHER:
|
||||
case MCO_ENCYPHER: {
|
||||
mbedtls_des3_context ctx3;
|
||||
mbedtls_des3_set3key_enc(&ctx3, key->data);
|
||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT);
|
||||
break;
|
||||
case MCO_DECYPHER:
|
||||
}
|
||||
case MCO_DECYPHER: {
|
||||
mbedtls_des3_context ctx3;
|
||||
mbedtls_des3_set3key_dec(&ctx3, key->data);
|
||||
mbedtls_des3_crypt_ecb(&ctx3, data, edata);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_DECRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT);
|
||||
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_AES:
|
||||
switch (operation) {
|
||||
case MCO_ENCYPHER: {
|
||||
mbedtls_aes_context actx;
|
||||
mbedtls_aes_init(&actx);
|
||||
mbedtls_aes_setkey_enc(&actx, key->data, 128);
|
||||
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_ENCRYPT, sizeof(edata), ivect, data, edata);
|
||||
@@ -812,6 +823,7 @@ void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect,
|
||||
break;
|
||||
}
|
||||
case MCO_DECYPHER: {
|
||||
mbedtls_aes_context actx;
|
||||
mbedtls_aes_init(&actx);
|
||||
mbedtls_aes_setkey_dec(&actx, key->data, 128);
|
||||
mbedtls_aes_crypt_cbc(&actx, MBEDTLS_AES_DECRYPT, sizeof(edata), ivect, edata, data);
|
||||
|
||||
@@ -11,190 +11,226 @@
|
||||
#include "mad.h"
|
||||
#include "ui.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
|
||||
#include "pm3_cmd.h"
|
||||
#include "crc.h"
|
||||
#include "util.h"
|
||||
#include "fileutils.h"
|
||||
#include "jansson.h"
|
||||
|
||||
// https://www.nxp.com/docs/en/application-note/AN10787.pdf
|
||||
static madAIDDescr madKnownAIDs[] = {
|
||||
{0x0000, "free"},
|
||||
{0x0001, "defect, e.g. access keys are destroyed or unknown"},
|
||||
{0x0002, "reserved"},
|
||||
{0x0003, "contains additional directory info"},
|
||||
{0x0004, "contains card holder information in ASCII format."},
|
||||
{0x0005, "not applicable (above memory size)"},
|
||||
static json_t *mad_known_aids = NULL;
|
||||
|
||||
{0x03e1, "NDEF"},
|
||||
static const char *holder_info_type[] = {
|
||||
"Surname",
|
||||
"Given name",
|
||||
"Sex",
|
||||
"Other"
|
||||
};
|
||||
|
||||
static madAIDDescr madKnownClusterCodes[] = {
|
||||
{0x00, "cluster: card administration"},
|
||||
{0x01, "cluster: miscellaneous applications"},
|
||||
{0x02, "cluster: miscellaneous applications"},
|
||||
{0x03, "cluster: miscellaneous applications"},
|
||||
{0x04, "cluster: miscellaneous applications"},
|
||||
{0x05, "cluster: miscellaneous applications"},
|
||||
{0x06, "cluster: miscellaneous applications"},
|
||||
{0x07, "cluster: miscellaneous applications"},
|
||||
{0x08, "cluster: airlines"},
|
||||
{0x09, "cluster: ferry traffic"},
|
||||
{0x10, "cluster: railway services"},
|
||||
{0x11, "cluster: miscellaneous applications"},
|
||||
{0x12, "cluster: transport"},
|
||||
{0x14, "cluster: security solutions"},
|
||||
{0x18, "cluster: city traffic"},
|
||||
{0x19, "cluster: Czech Railways"},
|
||||
{0x20, "cluster: bus services"},
|
||||
{0x21, "cluster: multi modal transit"},
|
||||
{0x28, "cluster: taxi"},
|
||||
{0x30, "cluster: road toll"},
|
||||
{0x31, "cluster: generic transport"},
|
||||
{0x38, "cluster: company services"},
|
||||
{0x40, "cluster: city card services"},
|
||||
{0x47, "cluster: access control & security"},
|
||||
{0x48, "cluster: access control & security"},
|
||||
{0x49, "cluster: VIGIK"},
|
||||
{0x4A, "cluster: Ministry of Defence, Netherlands"},
|
||||
{0x4B, "cluster: Bosch Telecom, Germany"},
|
||||
{0x4C, "cluster: European Union Institutions"},
|
||||
{0x50, "cluster: ski ticketing"},
|
||||
{0x51, "cluster: access control & security"},
|
||||
{0x52, "cluster: access control & security"},
|
||||
{0x53, "cluster: access control & security"},
|
||||
{0x54, "cluster: access control & security"},
|
||||
{0x55, "cluster: SOAA standard for offline access standard"},
|
||||
{0x56, "cluster: access control & security"},
|
||||
{0x58, "cluster: academic services"},
|
||||
{0x60, "cluster: food"},
|
||||
{0x68, "cluster: non-food trade"},
|
||||
{0x70, "cluster: hotel"},
|
||||
{0x71, "cluster: loyalty"},
|
||||
{0x75, "cluster: airport services"},
|
||||
{0x78, "cluster: car rental"},
|
||||
{0x79, "cluster: Dutch government"},
|
||||
{0x80, "cluster: administration services"},
|
||||
{0x88, "cluster: electronic purse"},
|
||||
{0x90, "cluster: television"},
|
||||
{0x91, "cluster: cruise ship"},
|
||||
{0x95, "cluster: IOPTA"},
|
||||
{0x97, "cluster: metering"},
|
||||
{0x98, "cluster: telephone"},
|
||||
{0xA0, "cluster: health services"},
|
||||
{0xA8, "cluster: warehouse"},
|
||||
{0xB0, "cluster: electronic trade"},
|
||||
{0xB8, "cluster: banking"},
|
||||
{0xC0, "cluster: entertainment & sports"},
|
||||
{0xC8, "cluster: car parking"},
|
||||
{0xC9, "cluster: fleet management"},
|
||||
{0xD0, "cluster: fuel, gasoline"},
|
||||
{0xD8, "cluster: info services"},
|
||||
{0xE0, "cluster: press"},
|
||||
{0xE1, "cluster: NFC Forum"},
|
||||
{0xE8, "cluster: computer"},
|
||||
{0xF0, "cluster: mail"},
|
||||
{0xF8, "cluster: miscellaneous applications"},
|
||||
static const char *aid_admin[] = {
|
||||
"free",
|
||||
"defect",
|
||||
"reserved",
|
||||
"additional directory info",
|
||||
"card holder info",
|
||||
"not applicable"
|
||||
};
|
||||
|
||||
static const char unknownAID[] = "";
|
||||
static int open_mad_file(json_t **root, bool verbose) {
|
||||
|
||||
static const char *GetAIDDescription(uint16_t AID) {
|
||||
for (int i = 0; i < ARRAYLEN(madKnownAIDs); i++)
|
||||
if (madKnownAIDs[i].AID == AID)
|
||||
return madKnownAIDs[i].Description;
|
||||
char *path;
|
||||
int res = searchFile(&path, RESOURCES_SUBDIR, "mad", ".json", true);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAYLEN(madKnownClusterCodes); i++)
|
||||
if (madKnownClusterCodes[i].AID == (AID >> 8)) // high byte - cluster code
|
||||
return madKnownClusterCodes[i].Description;
|
||||
int retval = PM3_SUCCESS;
|
||||
json_error_t error;
|
||||
|
||||
return unknownAID;
|
||||
*root = json_load_file(path, 0, &error);
|
||||
if (!*root) {
|
||||
PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text);
|
||||
retval = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_is_array(*root)) {
|
||||
PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path);
|
||||
retval = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Loaded file " _YELLOW_("`%s`") " (%s) %zu records.", path, _GREEN_("ok"), json_array_size(*root));
|
||||
out:
|
||||
free(path);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int close_mad_file(json_t *root) {
|
||||
json_decref(root);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static const char *mad_json_get_str(json_t *data, const char *name) {
|
||||
|
||||
json_t *jstr = json_object_get(data, name);
|
||||
if (jstr == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!json_is_string(jstr)) {
|
||||
PrintAndLogEx(WARNING, _YELLOW_("`%s`") " is not a string", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *cstr = json_string_value(jstr);
|
||||
if (strlen(cstr) == 0)
|
||||
return NULL;
|
||||
|
||||
return cstr;
|
||||
}
|
||||
|
||||
static int print_aid_description(json_t *root, uint16_t aid, char *fmt, bool verbose) {
|
||||
char lmad[7] = {0};
|
||||
sprintf(lmad, "0x%04x", aid); // must be lowercase
|
||||
|
||||
json_t *elm = NULL;
|
||||
|
||||
for (uint32_t idx = 0; idx < json_array_size(root); idx++) {
|
||||
json_t *data = json_array_get(root, idx);
|
||||
if (!json_is_object(data)) {
|
||||
PrintAndLogEx(ERR, "data [%d] is not an object\n", idx);
|
||||
continue;
|
||||
}
|
||||
const char *fmad = mad_json_get_str(data, "mad");
|
||||
char lfmad[strlen(fmad) + 1];
|
||||
strcpy(lfmad, fmad);
|
||||
str_lower(lfmad);
|
||||
if (strcmp(lmad, lfmad) == 0) {
|
||||
elm = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (elm == NULL) {
|
||||
PrintAndLogEx(INFO, fmt, " (unknown)");
|
||||
return PM3_ENODATA;
|
||||
}
|
||||
const char *vmad = mad_json_get_str(elm, "mad");
|
||||
const char *application = mad_json_get_str(elm, "application");
|
||||
const char *company = mad_json_get_str(elm, "company");
|
||||
const char *provider = mad_json_get_str(elm, "service_provider");
|
||||
const char *integrator = mad_json_get_str(elm, "system_integrator");
|
||||
char result[4 + strlen(application) + strlen(company)];
|
||||
sprintf(result, " %s [%s]", application, company);
|
||||
PrintAndLogEx(INFO, fmt, result);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, " MAD: %s", vmad);
|
||||
if (application)
|
||||
PrintAndLogEx(SUCCESS, " Application: %s", application);
|
||||
if (company)
|
||||
PrintAndLogEx(SUCCESS, " Company: %s", company);
|
||||
if (provider)
|
||||
PrintAndLogEx(SUCCESS, " Service provider: %s", provider);
|
||||
if (integrator)
|
||||
PrintAndLogEx(SUCCESS, " System integrator: %s", integrator);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int madCRCCheck(uint8_t *sector, bool verbose, int MADver) {
|
||||
if (MADver == 1) {
|
||||
uint8_t crc = CRC8Mad(§or[16 + 1], 15 + 16);
|
||||
if (crc != sector[16]) {
|
||||
PrintAndLogEx(WARNING, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver, crc, sector[16]);
|
||||
return 3;
|
||||
PrintAndLogEx(WARNING, _RED_("Wrong MAD %d CRC") " calculated: 0x%02x != 0x%02x", MADver, crc, sector[16]);
|
||||
return PM3_ESOFT;
|
||||
};
|
||||
} else {
|
||||
uint8_t crc = CRC8Mad(§or[1], 15 + 16 + 16);
|
||||
if (crc != sector[0]) {
|
||||
PrintAndLogEx(WARNING, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver, crc, sector[16]);
|
||||
return 3;
|
||||
PrintAndLogEx(WARNING, _RED_("Wrong MAD %d CRC") " calculated: 0x%02x != 0x%02x", MADver, crc, sector[0]);
|
||||
return PM3_ESOFT;
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint16_t madGetAID(uint8_t *sector, int MADver, int sectorNo) {
|
||||
static uint16_t madGetAID(uint8_t *sector, bool swapmad, int MADver, int sectorNo) {
|
||||
uint16_t mad;
|
||||
if (MADver == 1)
|
||||
return (sector[16 + 2 + (sectorNo - 1) * 2] << 8) + (sector[16 + 2 + (sectorNo - 1) * 2 + 1]);
|
||||
mad = (sector[16 + 2 + (sectorNo - 1) * 2 + 1] << 8) + (sector[16 + 2 + (sectorNo - 1) * 2]);
|
||||
else
|
||||
return (sector[2 + (sectorNo - 1) * 2] << 8) + (sector[2 + (sectorNo - 1) * 2 + 1]);
|
||||
mad = (sector[2 + (sectorNo - 1) * 2 + 1] << 8) + (sector[2 + (sectorNo - 1) * 2]);
|
||||
if (swapmad) {
|
||||
return BSWAP_16(mad);
|
||||
} else {
|
||||
return mad;
|
||||
}
|
||||
}
|
||||
|
||||
int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) {
|
||||
int res = 0;
|
||||
|
||||
if (!sector0)
|
||||
return 1;
|
||||
if (sector0 == NULL)
|
||||
return PM3_EINVARG;
|
||||
|
||||
uint8_t GPB = sector0[3 * 16 + 9];
|
||||
uint8_t GPB = sector0[3 * 16 + 9];
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, "GPB: 0x%02x", GPB);
|
||||
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x"), "GPB", GPB);
|
||||
|
||||
// DA (MAD available)
|
||||
if (!(GPB & 0x80)) {
|
||||
PrintAndLogEx(ERR, "DA=0! MAD not available.");
|
||||
return 1;
|
||||
PrintAndLogEx(ERR, "DA = 0! MAD not available");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint8_t mad_ver = GPB & 0x03;
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("%d"), "MAD version", mad_ver);
|
||||
|
||||
// MAD version
|
||||
if ((mad_ver != 0x01) && (mad_ver != 0x02)) {
|
||||
PrintAndLogEx(ERR, "Wrong MAD version " _RED_("0x%02x"), mad_ver);
|
||||
return PM3_ESOFT;
|
||||
};
|
||||
|
||||
if (haveMAD2)
|
||||
*haveMAD2 = (mad_ver == 2);
|
||||
|
||||
int res = madCRCCheck(sector0, true, 1);
|
||||
|
||||
if (verbose && res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x") " (%s)", "CRC8", sector0[16], _GREEN_("ok"));
|
||||
|
||||
if (mad_ver == 2 && sector10) {
|
||||
int res2 = madCRCCheck(sector10, true, 2);
|
||||
if (res == PM3_SUCCESS)
|
||||
res = res2;
|
||||
|
||||
if (verbose && !res2)
|
||||
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x") " (%s)", "CRC8", sector10[0], _GREEN_("ok"));
|
||||
}
|
||||
|
||||
// MA (multi-application card)
|
||||
if (verbose) {
|
||||
if (GPB & 0x40)
|
||||
PrintAndLogEx(NORMAL, "Multi application card.");
|
||||
PrintAndLogEx(SUCCESS, "Multi application card");
|
||||
else
|
||||
PrintAndLogEx(NORMAL, "Single application card.");
|
||||
PrintAndLogEx(SUCCESS, "Single application card");
|
||||
}
|
||||
|
||||
uint8_t MADVer = GPB & 0x03;
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, "MAD version: %d", MADVer);
|
||||
|
||||
// MAD version
|
||||
if ((MADVer != 0x01) && (MADVer != 0x02)) {
|
||||
PrintAndLogEx(ERR, "Wrong MAD version: 0x%02x", MADVer);
|
||||
return 2;
|
||||
};
|
||||
|
||||
if (haveMAD2)
|
||||
*haveMAD2 = (MADVer == 2);
|
||||
|
||||
res = madCRCCheck(sector0, true, 1);
|
||||
|
||||
if (verbose && !res)
|
||||
PrintAndLogEx(NORMAL, "CRC8-MAD1 OK.");
|
||||
|
||||
if (MADVer == 2 && sector10) {
|
||||
int res2 = madCRCCheck(sector10, true, 2);
|
||||
if (!res)
|
||||
res = res2;
|
||||
|
||||
if (verbose && !res2)
|
||||
PrintAndLogEx(NORMAL, "CRC8-MAD2 OK.");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen) {
|
||||
int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen, bool swapmad) {
|
||||
*madlen = 0;
|
||||
bool haveMAD2 = false;
|
||||
MADCheck(sector0, sector10, false, &haveMAD2);
|
||||
int res = MADCheck(sector0, sector10, false, &haveMAD2);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Not a valid MAD");
|
||||
return res;
|
||||
}
|
||||
|
||||
for (int i = 1; i < 16; i++) {
|
||||
mad[*madlen] = madGetAID(sector0, 1, i);
|
||||
mad[*madlen] = madGetAID(sector0, swapmad, 1, i);
|
||||
(*madlen)++;
|
||||
}
|
||||
|
||||
@@ -204,55 +240,131 @@ int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen
|
||||
(*madlen)++;
|
||||
|
||||
for (int i = 1; i < 24; i++) {
|
||||
mad[*madlen] = madGetAID(sector10, 2, i);
|
||||
mad[*madlen] = madGetAID(sector10, swapmad, 2, i);
|
||||
(*madlen)++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int MADCardHolderInfoDecode(uint8_t *data, size_t datalen, bool verbose) {
|
||||
size_t idx = 0;
|
||||
while (idx < datalen) {
|
||||
uint8_t len = data[idx] & 0x3f;
|
||||
uint8_t type = data[idx] >> 6;
|
||||
idx++;
|
||||
if (len > 0) {
|
||||
PrintAndLogEx(INFO, "%14s " _GREEN_("%.*s"), holder_info_type[type], len, &data[idx]);
|
||||
idx += len;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) {
|
||||
static int MADInfoByteDecode(uint8_t *sector, bool swapmad, int mad_ver, bool verbose) {
|
||||
uint8_t info;
|
||||
if (mad_ver == 1) {
|
||||
info = sector[16 + 1] & 0x3f;
|
||||
if (info >= 0xF) {
|
||||
PrintAndLogEx(WARNING, "Invalid Info byte (MAD1) value " _YELLOW_("0x%02x"), info);
|
||||
if (verbose)
|
||||
// I understand the spec in a way that MAD1 InfoByte should not point into MAD2 sectors, @lukaskuzmiak
|
||||
PrintAndLogEx(WARNING, "MAD1 Info byte points outside of MAD1 sector space (0x%02x), report a bug?", info);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
info = sector[1] & 0x3f;
|
||||
if (info == 0x10 || info >= 0x28) {
|
||||
PrintAndLogEx(WARNING, "Invalid Info byte (MAD2) value " _YELLOW_("0x%02x"), info);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2) {
|
||||
open_mad_file(&mad_known_aids, verbose);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "------------ " _CYAN_("MAD v1 details") " -------------");
|
||||
|
||||
// check MAD1 only
|
||||
MADCheck(sector, NULL, verbose, haveMAD2);
|
||||
|
||||
// info byte
|
||||
uint8_t InfoByte = sector[16 + 1] & 0x3f;
|
||||
if (InfoByte) {
|
||||
PrintAndLogEx(NORMAL, "Card publisher sector: 0x%02x", InfoByte);
|
||||
int ibs = MADInfoByteDecode(sector, swapmad, 1, verbose);
|
||||
|
||||
if (ibs) {
|
||||
PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02x"), ibs);
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, "Card publisher sector not present.");
|
||||
PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs);
|
||||
}
|
||||
if (InfoByte == 0x10 || InfoByte >= 0x28)
|
||||
PrintAndLogEx(WARNING, "Info byte error");
|
||||
|
||||
PrintAndLogEx(NORMAL, "00 MAD1");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "---------------- " _CYAN_("Listing") " ----------------");
|
||||
|
||||
PrintAndLogEx(INFO, " 00 MAD v1");
|
||||
uint32_t prev_aid = 0xFFFFFFFF;
|
||||
for (int i = 1; i < 16; i++) {
|
||||
uint16_t AID = madGetAID(sector, 1, i);
|
||||
PrintAndLogEx(NORMAL, "%02d [%04X] %s", i, AID, GetAIDDescription(AID));
|
||||
};
|
||||
|
||||
return 0;
|
||||
uint16_t aid = madGetAID(sector, swapmad, 1, i);
|
||||
if (aid < 6) {
|
||||
PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (%s)") : " %02d [%04X] (%s)", i, aid, aid_admin[aid]);
|
||||
} else if (prev_aid == aid) {
|
||||
PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (continuation)") : " %02d [%04X] (continuation)", i, aid);
|
||||
} else {
|
||||
char fmt[30];
|
||||
sprintf(fmt, (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [%04X]%s", i, aid, "%s");
|
||||
print_aid_description(mad_known_aids, aid, fmt, verbose);
|
||||
prev_aid = aid;
|
||||
}
|
||||
}
|
||||
close_mad_file(mad_known_aids);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int MAD2DecodeAndPrint(uint8_t *sector, bool verbose) {
|
||||
PrintAndLogEx(NORMAL, "16 MAD2");
|
||||
|
||||
int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
|
||||
open_mad_file(&mad_known_aids, verbose);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "------------ " _CYAN_("MAD v2 details") " -------------");
|
||||
|
||||
int res = madCRCCheck(sector, true, 2);
|
||||
if (verbose) {
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "CRC8 (%s)", _GREEN_("ok"));
|
||||
else
|
||||
PrintAndLogEx(WARNING, "CRC8 (%s)", _RED_("fail"));
|
||||
}
|
||||
|
||||
if (verbose && !res)
|
||||
PrintAndLogEx(NORMAL, "CRC8-MAD2 OK.");
|
||||
int ibs = MADInfoByteDecode(sector, swapmad, 2, verbose);
|
||||
if (ibs) {
|
||||
PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02x"), ibs);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs);
|
||||
}
|
||||
|
||||
uint8_t InfoByte = sector[1] & 0x3f;
|
||||
PrintAndLogEx(NORMAL, "MAD2 Card publisher sector: 0x%02x", InfoByte);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "---------------- " _CYAN_("Listing") " ----------------");
|
||||
|
||||
PrintAndLogEx(INFO, " 16 MAD v2");
|
||||
|
||||
uint32_t prev_aid = 0xFFFFFFFF;
|
||||
for (int i = 1; i < 8 + 8 + 7 + 1; i++) {
|
||||
uint16_t AID = madGetAID(sector, 2, i);
|
||||
PrintAndLogEx(NORMAL, "%02d [%04X] %s", i + 16, AID, GetAIDDescription(AID));
|
||||
};
|
||||
uint16_t aid = madGetAID(sector, swapmad, 2, i);
|
||||
if (aid < 6) {
|
||||
PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (%s)") : " %02d [%04X] (%s)", i + 16, aid, aid_admin[aid]);
|
||||
} else if (prev_aid == aid) {
|
||||
PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (continuation)") : " %02d [%04X] (continuation)", i + 16, aid);
|
||||
} else {
|
||||
char fmt[30];
|
||||
sprintf(fmt, (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [%04X]%s", i + 16, aid, "%s");
|
||||
print_aid_description(mad_known_aids, aid, fmt, verbose);
|
||||
prev_aid = aid;
|
||||
}
|
||||
}
|
||||
close_mad_file(mad_known_aids);
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -13,15 +13,10 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t AID;
|
||||
const char *Description;
|
||||
} madAIDDescr;
|
||||
|
||||
int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2);
|
||||
int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen);
|
||||
int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2);
|
||||
int MAD2DecodeAndPrint(uint8_t *sector, bool verbose);
|
||||
|
||||
int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen, bool swapmad);
|
||||
int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2);
|
||||
int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose);
|
||||
int MADCardHolderInfoDecode(uint8_t *data, size_t dataLen, bool verbose);
|
||||
|
||||
#endif // _MAD_H_
|
||||
|
||||
@@ -45,11 +45,14 @@ uint32_t intersection(uint64_t *listA, uint64_t *listB) {
|
||||
// Darkside attack (hf mf mifare)
|
||||
// if successful it will return a list of keys, not just one.
|
||||
uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys) {
|
||||
struct Crypto1State *states;
|
||||
union {
|
||||
struct Crypto1State *states;
|
||||
uint64_t *keylist;
|
||||
} unionstate;
|
||||
|
||||
uint32_t i, pos;
|
||||
uint8_t ks3x[8], par[8][8];
|
||||
uint64_t key_recovered;
|
||||
uint64_t *keylist;
|
||||
|
||||
// Reset the last three significant bits of the reader nonce
|
||||
nr &= 0xFFFFFF1F;
|
||||
@@ -68,23 +71,21 @@ uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t
|
||||
par[7 - pos][7] = (bt >> 7) & 1;
|
||||
}
|
||||
|
||||
states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0));
|
||||
unionstate.states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0));
|
||||
|
||||
if (!states) {
|
||||
if (!unionstate.states) {
|
||||
*keys = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
keylist = (uint64_t *)states;
|
||||
|
||||
for (i = 0; keylist[i]; i++) {
|
||||
lfsr_rollback_word(states + i, uid ^ nt, 0);
|
||||
crypto1_get_lfsr(states + i, &key_recovered);
|
||||
keylist[i] = key_recovered;
|
||||
for (i = 0; unionstate.keylist[i]; i++) {
|
||||
lfsr_rollback_word(unionstate.states + i, uid ^ nt, 0);
|
||||
crypto1_get_lfsr(unionstate.states + i, &key_recovered);
|
||||
unionstate.keylist[i] = key_recovered;
|
||||
}
|
||||
keylist[i] = -1;
|
||||
unionstate.keylist[i] = -1;
|
||||
|
||||
*keys = keylist;
|
||||
*keys = unionstate.keylist;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,42 +90,42 @@ const char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) {
|
||||
return StaticNone;
|
||||
}
|
||||
/*
|
||||
static int CalculateEncIVCommand(mf4Session_t *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);
|
||||
static int CalculateEncIVCommand(mf4Session_t *mf4session, uint8_t *iv, bool verbose) {
|
||||
memcpy(&iv[0], &mf4session->TI, 4);
|
||||
memcpy(&iv[4], &mf4session->R_Ctr, 2);
|
||||
memcpy(&iv[6], &mf4session->W_Ctr, 2);
|
||||
memcpy(&iv[8], &mf4session->R_Ctr, 2);
|
||||
memcpy(&iv[10], &mf4session->W_Ctr, 2);
|
||||
memcpy(&iv[12], &mf4session->R_Ctr, 2);
|
||||
memcpy(&iv[14], &mf4session->W_Ctr, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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);
|
||||
static int CalculateEncIVResponse(mf4Session *mf4session, uint8_t *iv, bool verbose) {
|
||||
memcpy(&iv[0], &mf4session->R_Ctr, 2);
|
||||
memcpy(&iv[2], &mf4session->W_Ctr, 2);
|
||||
memcpy(&iv[4], &mf4session->R_Ctr, 2);
|
||||
memcpy(&iv[6], &mf4session->W_Ctr, 2);
|
||||
memcpy(&iv[8], &mf4session->R_Ctr, 2);
|
||||
memcpy(&iv[10], &mf4session->W_Ctr, 2);
|
||||
memcpy(&iv[12], &mf4session->TI, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
int CalculateMAC(mf4Session_t *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)
|
||||
int CalculateMAC(mf4Session_t *mf4session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) {
|
||||
if (!mf4session || !mf4session->Authenticated || !mac || !data || !datalen)
|
||||
return 1;
|
||||
|
||||
memset(mac, 0x00, 8);
|
||||
|
||||
uint16_t ctr = session->R_Ctr;
|
||||
uint16_t ctr = mf4session->R_Ctr;
|
||||
switch (mtype) {
|
||||
case mtypWriteCmd:
|
||||
case mtypWriteResp:
|
||||
ctr = session->W_Ctr;
|
||||
ctr = mf4session->W_Ctr;
|
||||
break;
|
||||
case mtypReadCmd:
|
||||
case mtypReadResp:
|
||||
@@ -134,7 +134,7 @@ int CalculateMAC(mf4Session_t *session, MACType_t mtype, uint8_t blockNum, uint8
|
||||
|
||||
uint8_t macdata[2049] = {data[0], (ctr & 0xFF), (ctr >> 8), 0};
|
||||
int macdatalen = datalen;
|
||||
memcpy(&macdata[3], session->TI, 4);
|
||||
memcpy(&macdata[3], mf4session->TI, 4);
|
||||
|
||||
switch (mtype) {
|
||||
case mtypReadCmd:
|
||||
@@ -160,10 +160,10 @@ int CalculateMAC(mf4Session_t *session, MACType_t mtype, uint8_t blockNum, uint8
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, "MAC data[%d]: %s", macdatalen, sprint_hex(macdata, macdatalen));
|
||||
|
||||
return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen);
|
||||
return aes_cmac8(NULL, mf4session->Kmac, macdata, mac, macdatalen);
|
||||
}
|
||||
|
||||
int MifareAuth4(mf4Session_t *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode) {
|
||||
int MifareAuth4(mf4Session_t *mf4session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode) {
|
||||
uint8_t data[257] = {0};
|
||||
int datalen = 0;
|
||||
|
||||
@@ -173,8 +173,8 @@ int MifareAuth4(mf4Session_t *session, uint8_t *keyn, uint8_t *key, bool activat
|
||||
if (silentMode)
|
||||
verbose = false;
|
||||
|
||||
if (session)
|
||||
session->Authenticated = false;
|
||||
if (mf4session)
|
||||
mf4session->Authenticated = false;
|
||||
|
||||
uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00};
|
||||
int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen, silentMode);
|
||||
@@ -284,19 +284,19 @@ int MifareAuth4(mf4Session_t *session, uint8_t *keyn, uint8_t *key, bool activat
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (session) {
|
||||
session->Authenticated = true;
|
||||
session->R_Ctr = 0;
|
||||
session->W_Ctr = 0;
|
||||
session->KeyNum = keyn[1] + (keyn[0] << 8);
|
||||
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);
|
||||
if (mf4session) {
|
||||
mf4session->Authenticated = true;
|
||||
mf4session->R_Ctr = 0;
|
||||
mf4session->W_Ctr = 0;
|
||||
mf4session->KeyNum = keyn[1] + (keyn[0] << 8);
|
||||
memmove(mf4session->RndA, RndA, 16);
|
||||
memmove(mf4session->RndB, RndB, 16);
|
||||
memmove(mf4session->Key, key, 16);
|
||||
memmove(mf4session->TI, raw, 4);
|
||||
memmove(mf4session->PICCap2, &raw[20], 6);
|
||||
memmove(mf4session->PCDCap2, &raw[26], 6);
|
||||
memmove(mf4session->Kenc, kenc, 16);
|
||||
memmove(mf4session->Kmac, kmac, 16);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
@@ -330,39 +330,39 @@ int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int
|
||||
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
}
|
||||
|
||||
int MFPReadBlock(mf4Session_t *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[4 + 8] = {(plain ? (0x37) : (0x33)), blockNum, 0x00, blockCount};
|
||||
if (!plain && session)
|
||||
CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode);
|
||||
if (!plain && mf4session)
|
||||
CalculateMAC(mf4session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, plain ? 4 : sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (session)
|
||||
session->R_Ctr++;
|
||||
if (mf4session)
|
||||
mf4session->R_Ctr++;
|
||||
|
||||
if (session && mac && *dataoutlen > 11)
|
||||
CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode);
|
||||
if (mf4session && mac && *dataoutlen > 11)
|
||||
CalculateMAC(mf4session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MFPWriteBlock(mf4Session_t *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
int MFPWriteBlock(mf4Session_t *mf4session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
|
||||
memmove(&rcmd[3], data, 16);
|
||||
if (session)
|
||||
CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode);
|
||||
if (mf4session)
|
||||
CalculateMAC(mf4session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (session)
|
||||
session->W_Ctr++;
|
||||
if (mf4session)
|
||||
mf4session->W_Ctr++;
|
||||
|
||||
if (session && mac && *dataoutlen > 3)
|
||||
CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode);
|
||||
if (mf4session && mac && *dataoutlen > 3)
|
||||
CalculateMAC(mf4session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,13 +50,13 @@ typedef struct {
|
||||
void mfpSetVerboseMode(bool verbose);
|
||||
const char *mfpGetErrorDescription(uint8_t errorCode);
|
||||
|
||||
int CalculateMAC(mf4Session_t *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose);
|
||||
int MifareAuth4(mf4Session_t *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode);
|
||||
int CalculateMAC(mf4Session_t *mf4session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose);
|
||||
int MifareAuth4(mf4Session_t *mf4session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode);
|
||||
|
||||
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
int MFPReadBlock(mf4Session_t *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
||||
int MFPWriteBlock(mf4Session_t *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
||||
int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
||||
int MFPWriteBlock(mf4Session_t *mf4session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
||||
int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose);
|
||||
|
||||
int MFPGetSignature(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
|
||||
@@ -378,7 +378,7 @@ __attribute__((force_align_arg_pointer))
|
||||
StateList_t *statelist = arg;
|
||||
statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt_enc ^ statelist->uid);
|
||||
|
||||
for (p1 = statelist->head.slhead; * (uint64_t *)p1 != 0; p1++) {};
|
||||
for (p1 = statelist->head.slhead; p1->odd | p1->even; p1++) {};
|
||||
|
||||
statelist->len = p1 - statelist->head.slhead;
|
||||
statelist->tail.sltail = --p1;
|
||||
@@ -492,8 +492,10 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||
}
|
||||
}
|
||||
|
||||
*(uint64_t *)p3 = -1;
|
||||
*(uint64_t *)p4 = -1;
|
||||
p3->odd = -1;
|
||||
p3->even = -1;
|
||||
p4->odd = -1;
|
||||
p4->even = -1;
|
||||
statelists[0].len = p3 - statelists[0].head.slhead;
|
||||
statelists[1].len = p4 - statelists[1].head.slhead;
|
||||
statelists[0].tail.sltail = --p3;
|
||||
@@ -536,10 +538,10 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||
free(statelists[1].head.slhead);
|
||||
num_to_bytes(key64, 6, resultKey);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _YELLOW_("%s") " ]",
|
||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]",
|
||||
package->block,
|
||||
package->keytype ? 'B' : 'A',
|
||||
sprint_hex_inrow(resultKey, 6)
|
||||
sprint_hex(resultKey, 6)
|
||||
);
|
||||
return -5;
|
||||
}
|
||||
@@ -637,7 +639,8 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||
}
|
||||
}
|
||||
|
||||
*(uint64_t *)p3 = -1;
|
||||
p3->odd = -1;
|
||||
p3->even = -1;
|
||||
statelists[0].len = p3 - statelists[0].head.slhead;
|
||||
statelists[0].tail.sltail = --p3;
|
||||
|
||||
@@ -711,10 +714,10 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||
|
||||
num_to_bytes(key64, 6, resultKey);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _YELLOW_("%s") " ]",
|
||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]",
|
||||
package->block,
|
||||
package->keytype ? 'B' : 'A',
|
||||
sprint_hex_inrow(resultKey, 6)
|
||||
sprint_hex(resultKey, 6)
|
||||
);
|
||||
return PM3_SUCCESS;
|
||||
} else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) {
|
||||
@@ -745,7 +748,7 @@ out:
|
||||
int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data) {
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_HF_MIFARE_READSC, sectorNo, keyType, 0, key, 6);
|
||||
SendCommandMIX(CMD_HF_MIFARE_READSC, sectorNo, keyType, 0, key, 6);
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
@@ -862,7 +865,7 @@ int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_
|
||||
|
||||
int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak) {
|
||||
uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF};
|
||||
uint8_t blockD[16] = {0x00};
|
||||
//uint8_t blockD[16] = {0x00};
|
||||
uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
uint8_t params = MAGIC_SINGLE;
|
||||
|
||||
@@ -880,34 +883,38 @@ int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak) {
|
||||
int res;
|
||||
for (int blockNo = 0; blockNo < 4 * 16; blockNo++) {
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
|
||||
PrintAndLogEx(INPLACE, "wipe block %d", blockNo);
|
||||
|
||||
if (blockNo == 0) {
|
||||
res = mfCSetBlock(blockNo, block0, NULL, params);
|
||||
res = mfCSetBlock(blockNo, block0, NULL, (params | MAGIC_WIPE));
|
||||
} else {
|
||||
if (mfIsSectorTrailer(blockNo))
|
||||
res = mfCSetBlock(blockNo, blockK, NULL, params);
|
||||
else
|
||||
res = mfCSetBlock(blockNo, blockD, NULL, params);
|
||||
// else
|
||||
// res = mfCSetBlock(blockNo, blockD, NULL, params);
|
||||
}
|
||||
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
PrintAndLogEx(WARNING, "Retry block[%d]...", blockNo);
|
||||
|
||||
PrintAndLogEx(WARNING, "retry block %d ...", blockNo);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Error setting block[%d]: %d", blockNo, res);
|
||||
PrintAndLogEx(ERR, "error setting block %d (%d)", blockNo, res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
DropField();
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params) {
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_HF_MIFARE_CSETBL, params, blockNo, 0, data, 16);
|
||||
SendCommandMIX(CMD_HF_MIFARE_CSETBL, params, blockNo, 0, data, 16);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||
@@ -941,127 +948,9 @@ int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) {
|
||||
// SNIFFER
|
||||
// [iceman] so many global variables....
|
||||
|
||||
// constants
|
||||
static uint8_t trailerAccessBytes[4] = {0x08, 0x77, 0x8F, 0x00};
|
||||
|
||||
// variables
|
||||
char logHexFileName[FILE_PATH_SIZE] = {0x00};
|
||||
static uint8_t traceCard[4096] = {0x00};
|
||||
static char traceFileName[FILE_PATH_SIZE] = {0x00};
|
||||
static int traceState = TRACE_IDLE;
|
||||
static uint8_t traceCurBlock = 0;
|
||||
static uint8_t traceCurKey = 0;
|
||||
|
||||
struct Crypto1State *traceCrypto1 = NULL;
|
||||
struct Crypto1State *revstate = NULL;
|
||||
|
||||
uint32_t cuid = 0; // uid part used for crypto1.
|
||||
|
||||
int isTraceCardEmpty(void) {
|
||||
return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0));
|
||||
}
|
||||
|
||||
int isBlockEmpty(int blockN) {
|
||||
for (int i = 0; i < 16; i++)
|
||||
if (traceCard[blockN * 16 + i] != 0) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int isBlockTrailer(int blockN) {
|
||||
return ((blockN & 0x03) == 0x03);
|
||||
}
|
||||
|
||||
int loadTraceCard(uint8_t *tuid, uint8_t uidlen) {
|
||||
FILE *f;
|
||||
char buf[64] = {0x00};
|
||||
uint8_t buf8[64] = {0x00};
|
||||
int i, blockNum;
|
||||
uint32_t tmp;
|
||||
|
||||
if (!isTraceCardEmpty())
|
||||
saveTraceCard();
|
||||
|
||||
memset(traceCard, 0x00, 4096);
|
||||
memcpy(traceCard, tuid, uidlen);
|
||||
|
||||
FillFileNameByUID(traceFileName, tuid, ".eml", uidlen);
|
||||
|
||||
f = fopen(traceFileName, "r");
|
||||
if (!f) return PM3_EFILE;
|
||||
|
||||
blockNum = 0;
|
||||
|
||||
while (!feof(f)) {
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (fgets(buf, sizeof(buf), f) == NULL) {
|
||||
PrintAndLogEx(FAILED, "No trace file found or reading error.");
|
||||
fclose(f);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
if (strlen(buf) < 32) {
|
||||
if (feof(f)) break;
|
||||
PrintAndLogEx(FAILED, "File content error. Block data must include 32 HEX symbols");
|
||||
fclose(f);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
sscanf(&buf[i], "%02X", &tmp);
|
||||
buf8[i / 2] = tmp & 0xFF;
|
||||
}
|
||||
|
||||
memcpy(traceCard + blockNum * 16, buf8, 16);
|
||||
|
||||
blockNum++;
|
||||
}
|
||||
fclose(f);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int saveTraceCard(void) {
|
||||
|
||||
if ((!strlen(traceFileName)) || (isTraceCardEmpty())) return PM3_ESOFT;
|
||||
|
||||
FILE *f;
|
||||
f = fopen(traceFileName, "w+");
|
||||
if (!f) return PM3_EFILE;
|
||||
|
||||
// given 4096 tracecard size, these loop will only match a 1024, 1kb card memory
|
||||
// 4086/16 == 256blocks.
|
||||
for (uint16_t i = 0; i < 256; i++) { // blocks
|
||||
for (uint8_t j = 0; j < 16; j++) // bytes
|
||||
fprintf(f, "%02X", *(traceCard + i * 16 + j));
|
||||
|
||||
// no extra line in the end
|
||||
if (i < 255)
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
//
|
||||
int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile) {
|
||||
|
||||
if (traceCrypto1)
|
||||
crypto1_destroy(traceCrypto1);
|
||||
|
||||
traceCrypto1 = NULL;
|
||||
|
||||
if (wantSaveToEmlFile)
|
||||
loadTraceCard(tuid, uidlen);
|
||||
|
||||
traceCard[4] = traceCard[0] ^ traceCard[1] ^ traceCard[2] ^ traceCard[3];
|
||||
traceCard[5] = sak;
|
||||
memcpy(&traceCard[6], atqa, 2);
|
||||
traceCurBlock = 0;
|
||||
cuid = bytes_to_num(tuid + (uidlen - 4), 4);
|
||||
traceState = TRACE_IDLE;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted) {
|
||||
if (len != 1) {
|
||||
for (int i = 0; i < len; i++)
|
||||
@@ -1076,180 +965,6 @@ void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool i
|
||||
}
|
||||
}
|
||||
|
||||
int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) {
|
||||
if (traceState == TRACE_ERROR)
|
||||
return PM3_ESOFT;
|
||||
|
||||
if (len > 255) {
|
||||
traceState = TRACE_ERROR;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint8_t data[255];
|
||||
memset(data, 0x00, sizeof(data));
|
||||
|
||||
memcpy(data, data_src, len);
|
||||
|
||||
if ((traceCrypto1) && ((traceState == TRACE_IDLE) || (traceState > TRACE_AUTH_OK))) {
|
||||
mf_crypto1_decrypt(traceCrypto1, data, len, 0);
|
||||
PrintAndLogEx(NORMAL, "DEC| %s", sprint_hex(data, len));
|
||||
AddLogHex(logHexFileName, "DEC| ", data, len);
|
||||
}
|
||||
|
||||
switch (traceState) {
|
||||
case TRACE_IDLE:
|
||||
// check packet crc16!
|
||||
if ((len >= 4) && (!check_crc(CRC_14443_A, data, len))) {
|
||||
PrintAndLogEx(NORMAL, "DEC| CRC ERROR!!!");
|
||||
AddLogLine(logHexFileName, "DEC| ", "CRC ERROR!!!");
|
||||
traceState = TRACE_ERROR; // do not decrypt the next commands
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// AUTHENTICATION
|
||||
if ((len == 4) && ((data[0] == MIFARE_AUTH_KEYA) || (data[0] == MIFARE_AUTH_KEYB))) {
|
||||
traceState = TRACE_AUTH1;
|
||||
traceCurBlock = data[1];
|
||||
traceCurKey = data[0] == 60 ? 1 : 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// READ
|
||||
if ((len == 4) && ((data[0] == ISO14443A_CMD_READBLOCK))) {
|
||||
traceState = TRACE_READ_DATA;
|
||||
traceCurBlock = data[1];
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// WRITE
|
||||
if ((len == 4) && ((data[0] == ISO14443A_CMD_WRITEBLOCK))) {
|
||||
traceState = TRACE_WRITE_OK;
|
||||
traceCurBlock = data[1];
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// HALT
|
||||
if ((len == 4) && ((data[0] == ISO14443A_CMD_HALT) && (data[1] == 0x00))) {
|
||||
traceState = TRACE_ERROR; // do not decrypt the next commands
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
|
||||
case TRACE_READ_DATA:
|
||||
if (len == 18) {
|
||||
traceState = TRACE_IDLE;
|
||||
|
||||
if (isBlockTrailer(traceCurBlock)) {
|
||||
memcpy(traceCard + traceCurBlock * 16 + 6, data + 6, 4);
|
||||
} else {
|
||||
memcpy(traceCard + traceCurBlock * 16, data, 16);
|
||||
}
|
||||
if (wantSaveToEmlFile) saveTraceCard();
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
traceState = TRACE_ERROR;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
break;
|
||||
case TRACE_WRITE_OK:
|
||||
if ((len == 1) && (data[0] == 0x0a)) {
|
||||
traceState = TRACE_WRITE_DATA;
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
traceState = TRACE_ERROR;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
break;
|
||||
case TRACE_WRITE_DATA:
|
||||
if (len == 18) {
|
||||
traceState = TRACE_IDLE;
|
||||
memcpy(traceCard + traceCurBlock * 16, data, 16);
|
||||
if (wantSaveToEmlFile) saveTraceCard();
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
traceState = TRACE_ERROR;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
break;
|
||||
case TRACE_AUTH1:
|
||||
if (len == 4) {
|
||||
traceState = TRACE_AUTH2;
|
||||
//nt = bytes_to_num(data, 4);
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
traceState = TRACE_ERROR;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
break;
|
||||
case TRACE_AUTH2:
|
||||
if (len == 8) {
|
||||
traceState = TRACE_AUTH_OK;
|
||||
//nr_enc = bytes_to_num(data, 4);
|
||||
//ar_enc = bytes_to_num(data + 4, 4);
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
traceState = TRACE_ERROR;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
break;
|
||||
case TRACE_AUTH_OK:
|
||||
if (len == 4) {
|
||||
uint32_t nt = 0; // tag challenge
|
||||
uint32_t nr_enc = 0; // encrypted reader challenge
|
||||
uint32_t ar_enc = 0; // encrypted reader response
|
||||
uint32_t at_enc = 0; // encrypted tag response
|
||||
traceState = TRACE_IDLE;
|
||||
// encrypted tag response
|
||||
at_enc = bytes_to_num(data, 4);
|
||||
|
||||
// mfkey64 recover key.
|
||||
uint64_t key = 0;
|
||||
uint32_t ks2 = ar_enc ^ prng_successor(nt, 64);
|
||||
uint32_t 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, cuid ^ nt, 0);
|
||||
crypto1_get_lfsr(revstate, &key);
|
||||
PrintAndLogEx(SUCCESS, "found Key: [%012" PRIx64 "]", key);
|
||||
|
||||
//if ( tryMfk64(cuid, nt, nr_enc, ar_enc, at_enc, &key) )
|
||||
AddLogUint64(logHexFileName, "Found Key: ", key);
|
||||
|
||||
int blockShift = ((traceCurBlock & 0xFC) + 3) * 16;
|
||||
if (isBlockEmpty((traceCurBlock & 0xFC) + 3))
|
||||
memcpy(traceCard + blockShift + 6, trailerAccessBytes, 4);
|
||||
|
||||
// keytype A/B
|
||||
if (traceCurKey)
|
||||
num_to_bytes(key, 6, traceCard + blockShift + 10);
|
||||
else
|
||||
num_to_bytes(key, 6, traceCard + blockShift);
|
||||
|
||||
if (wantSaveToEmlFile)
|
||||
saveTraceCard();
|
||||
|
||||
if (traceCrypto1)
|
||||
crypto1_destroy(traceCrypto1);
|
||||
|
||||
// set cryptosystem state
|
||||
traceCrypto1 = lfsr_recovery64(ks2, ks3);
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "[!] nested key recovery not implemented!\n");
|
||||
//at_enc = bytes_to_num(data, 4);
|
||||
crypto1_destroy(traceCrypto1);
|
||||
traceState = TRACE_ERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
traceState = TRACE_ERROR;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len) {
|
||||
PrintAndLogEx(SUCCESS, "\nencrypted data: [%s]", sprint_hex(data, len));
|
||||
struct Crypto1State *s;
|
||||
@@ -1406,7 +1121,7 @@ int detect_classic_static_nonce(void) {
|
||||
}
|
||||
|
||||
/* try to see if card responses to "chinese magic backdoor" commands. */
|
||||
void detect_classic_magic(void) {
|
||||
int detect_classic_magic(void) {
|
||||
|
||||
uint8_t isGeneration = 0;
|
||||
PacketResponseNG resp;
|
||||
@@ -1433,4 +1148,5 @@ void detect_classic_magic(void) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return isGeneration;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ typedef struct {
|
||||
//uint8_t foundKey[2];
|
||||
} icesector_t;
|
||||
|
||||
extern char logHexFileName[FILE_PATH_SIZE];
|
||||
#define KEYS_IN_BLOCK ((PM3_CMD_DATA_SIZE - 4) / 6)
|
||||
#define KEYBLOCK_SIZE (KEYS_IN_BLOCK * 6)
|
||||
#define CANDIDATE_SIZE (0xFFFF * 6)
|
||||
@@ -81,19 +80,11 @@ int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak);
|
||||
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
|
||||
int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
||||
|
||||
int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile);
|
||||
int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile);
|
||||
|
||||
int isTraceCardEmpty(void);
|
||||
int isBlockEmpty(int blockN);
|
||||
int isBlockTrailer(int blockN);
|
||||
int loadTraceCard(uint8_t *tuid, uint8_t uidlen);
|
||||
int saveTraceCard(void);
|
||||
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
|
||||
|
||||
int detect_classic_prng(void);
|
||||
int detect_classic_nackbug(bool verbose);
|
||||
void detect_classic_magic(void);
|
||||
int detect_classic_magic(void);
|
||||
int detect_classic_static_nonce(void);
|
||||
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted);
|
||||
#endif
|
||||
|
||||
@@ -127,6 +127,7 @@ static int ndefDecodeHeader(uint8_t *data, size_t datalen, NDEFHeader_t *header)
|
||||
|
||||
if (header->IDLenPresent) {
|
||||
header->IDLen = (header->ShortRecordBit ? (data[3]) : (data[6]));
|
||||
header->ID = data + header->len + header->TypeLen;
|
||||
} else {
|
||||
header->IDLen = 0;
|
||||
}
|
||||
@@ -136,7 +137,7 @@ static int ndefDecodeHeader(uint8_t *data, size_t datalen, NDEFHeader_t *header)
|
||||
header->RecLen = header->len + header->TypeLen + header->PayloadLen + header->IDLen;
|
||||
|
||||
if (header->RecLen > datalen)
|
||||
return 3;
|
||||
return PM3_ESOFT;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
@@ -436,7 +437,7 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) {
|
||||
size_t indx = 0;
|
||||
|
||||
PrintAndLogEx(INFO, "");
|
||||
PrintAndLogEx(INFO, "NDEF parsing");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("NDEF parsing") " ----------------");
|
||||
while (indx < ndefLen) {
|
||||
|
||||
PrintAndLogEx(INFO, "-----------------------------------------------------");
|
||||
|
||||
Reference in New Issue
Block a user