X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/3a05a1e73940bfa13ce5f732fd5d14ee333c6977..refs/pull/531/head:/client/mifarehost.c?ds=sidebyside diff --git a/client/mifarehost.c b/client/mifarehost.c index 8a840d47..67277b59 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -228,17 +228,46 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t key *key = -1; - UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType&0xff)<<8)), clear_trace, keycnt}}; + UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType & 0xff) << 8)), clear_trace, keycnt}}; memcpy(c.d.asBytes, keyBlock, 6 * keycnt); SendCommand(&c); UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1; + if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1; if ((resp.arg[0] & 0xff) != 0x01) return 2; *key = bytes_to_num(resp.d.asBytes, 6); return 0; } +int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint8_t timeout14a, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector){ + + uint8_t keyPtr = 0; + + if (e_sector == NULL) + return -1; + + UsbCommand c = {CMD_MIFARE_CHKKEYS, {((sectorCnt & 0xff) | ((keyType & 0xff) << 8)), (clear_trace | 0x02)|((timeout14a & 0xff) << 8), keycnt}}; + memcpy(c.d.asBytes, keyBlock, 6 * keycnt); + SendCommand(&c); + + UsbCommand resp; + if (!WaitForResponseTimeoutW(CMD_ACK, &resp, MAX(3000, 1000 + 13 * sectorCnt * keycnt * (keyType == 2 ? 2 : 1)), false)) return 1; // timeout: 13 ms / fail auth + if ((resp.arg[0] & 0xff) != 0x01) return 2; + + bool foundAKey = false; + for(int sec = 0; sec < sectorCnt; sec++){ + for(int keyAB = 0; keyAB < 2; keyAB++){ + keyPtr = *(resp.d.asBytes + keyAB * 40 + sec); + if (keyPtr){ + e_sector[sec].foundKey[keyAB] = true; + e_sector[sec].Key[keyAB] = bytes_to_num(keyBlock + (keyPtr - 1) * 6, 6); + foundAKey = true; + } + } + } + return foundAKey ? 0 : 3; +} + // Compare 16 Bits out of cryptostate int Compare16Bits(const void * a, const void * b) { if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0; @@ -511,36 +540,12 @@ int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID) { return 0; } -int mfCIdentify() -{ - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; +int mfCIdentify() { + UsbCommand c = {CMD_MIFARE_CIDENT, {0, 0, 0}}; SendCommand(&c); - UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - - if(select_status != 0) { - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT; - c.arg[1] = 2; - c.arg[2] = 0; - memcpy(c.d.asBytes, rats, 2); - SendCommand(&c); - WaitForResponse(CMD_ACK,&resp); - } - - c.cmd = CMD_MIFARE_CIDENT; - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - WaitForResponse(CMD_ACK,&resp); - uint8_t isGeneration = resp.arg[0] & 0xff; switch( isGeneration ){ case 1: PrintAndLog("Chinese magic backdoor commands (GEN 1a) detected"); break; @@ -548,13 +553,6 @@ int mfCIdentify() default: PrintAndLog("No chinese magic backdoor command detected"); break; } - // disconnect - c.cmd = CMD_READER_ISO_14443a; - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - return (int) isGeneration; } @@ -905,3 +903,72 @@ int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, return 0; } +/** validate_prng_nonce + * Determine if nonce is deterministic. ie: Suspectable to Darkside attack. + * returns + * true = weak prng + * false = hardend prng + */ +bool validate_prng_nonce(uint32_t nonce) { + uint16_t *dist = 0; + uint16_t x, i; + + dist = malloc(2 << 16); + if(!dist) + return -1; + + // init prng table: + for (x = i = 1; i; ++i) { + dist[(x & 0xff) << 8 | x >> 8] = i; + x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; + } + + uint32_t res = (65535 - dist[nonce >> 16] + dist[nonce & 0xffff]) % 65535; + + free(dist); + return (res == 16); +} + +/* Detect Tag Prng, +* function performs a partial AUTH, where it tries to authenticate against block0, key A, but only collects tag nonce. +* the tag nonce is check to see if it has a predictable PRNG. +* @returns +* TRUE if tag uses WEAK prng (ie Now the NACK bug also needs to be present for Darkside attack) +* FALSE is tag uses HARDEND prng (ie hardnested attack possible, with known key) +*/ +int DetectClassicPrng(void){ + + UsbCommand resp, respA; + uint8_t cmd[] = {0x60, 0x00}; // MIFARE_AUTH_KEYA + uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS; + + UsbCommand c = {CMD_READER_ISO_14443a, {flags, sizeof(cmd), 0}}; + memcpy(c.d.asBytes, cmd, sizeof(cmd)); + + clearCommandBuffer(); + SendCommand(&c); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLog("PRNG UID: Reply timeout."); + return -1; + } + + // if select tag failed. + if (resp.arg[0] == 0) { + PrintAndLog("PRNG error: selecting tag failed, can't detect prng."); + return -1; + } + + if (!WaitForResponseTimeout(CMD_ACK, &respA, 5000)) { + PrintAndLog("PRNG data: Reply timeout."); + return -1; + } + + // check respA + if (respA.arg[0] != 4) { + PrintAndLog("PRNG data error: Wrong length: %d", respA.arg[0]); + return -1; + } + + uint32_t nonce = bytes_to_num(respA.d.asBytes, respA.arg[0]); + return validate_prng_nonce(nonce); +}