X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/1604d0a2909a6ae1a5b615d280671d867c1028a4..e938f7101179641c9478e9c914bc1bb3ee171570:/client/cmdhficlass.c?ds=inline diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index b8e1e098..b59c0bdc 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch // Copyright (C) 2011 Gerhard de Koning Gans +// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende // // 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 @@ -13,345 +14,273 @@ #include #include #include +#include #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type -#include "data.h" -//#include "proxusb.h" -#include "proxmark3.h" +#include "comms.h" #include "ui.h" +#include "cliparser/cliparser.h" #include "cmdparser.h" #include "cmdhficlass.h" #include "common.h" #include "util.h" #include "cmdmain.h" +#include "mbedtls/des.h" +#include "loclass/cipherutils.h" +#include "loclass/cipher.h" +#include "loclass/ikeys.h" +#include "loclass/elite_crack.h" +#include "loclass/fileutils.h" +#include "protocols.h" +#include "usb_cmd.h" +#include "cmdhfmfu.h" +#include "util_posix.h" +#include "cmdhf14a.h" // DropField() + + +#define ICLASS_KEYS_MAX 8 +static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } +}; -static int CmdHelp(const char *Cmd); -int xorbits_8(uint8_t val) -{ - uint8_t res = val ^ (val >> 1); //1st pass - res = res ^ (res >> 1); // 2nd pass - res = res ^ (res >> 2); // 3rd pass - res = res ^ (res >> 4); // 4th pass - return res & 1; -} +typedef struct iclass_block { + uint8_t d[8]; +} iclass_block_t; -int CmdHFiClassList(const char *Cmd) -{ - bool ShowWaitCycles = false; - char param = param_getchar(Cmd, 0); +// iclass / picopass chip config structures and shared routines +typedef struct { + uint8_t app_limit; //[8] + uint8_t otp[2]; //[9-10] + uint8_t block_writelock;//[11] + uint8_t chip_config; //[12] + uint8_t mem_config; //[13] + uint8_t eas; //[14] + uint8_t fuses; //[15] +} picopass_conf_block; - if (param != 0) { - PrintAndLog("List data in trace buffer."); - PrintAndLog("Usage: hf iclass list"); - PrintAndLog("h - help"); - PrintAndLog("sample: hf iclass list"); - return 0; - } +typedef struct { + uint8_t csn[8]; + picopass_conf_block conf; + uint8_t epurse[8]; + uint8_t key_d[8]; + uint8_t key_c[8]; + uint8_t app_issuer_area[8]; +} picopass_hdr; - uint8_t got[1920]; - GetFromBigBuf(got,sizeof(got),0); - WaitForResponse(CMD_ACK,NULL); - PrintAndLog("Recorded Activity"); - PrintAndLog(""); - PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); - PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data"); - PrintAndLog("-----------|-----------|-----|--------"); +static void fuse_config(const picopass_hdr *hdr) { + uint8_t fuses = hdr->conf.fuses; - int i; - uint32_t first_timestamp = 0; - uint32_t timestamp; - bool tagToReader; - uint32_t parityBits; - uint8_t len; - uint8_t *frame; - uint32_t EndOfTransmissionTimestamp = 0; + if (fuses & FUSE_FPERS) + PrintAndLog(" Mode: Personalization [Programmable]"); + else + PrintAndLog(" Mode: Application [Locked]"); + if (fuses & FUSE_CODING1) + PrintAndLog("Coding: RFU"); + else { + if (fuses & FUSE_CODING0) + PrintAndLog("Coding: ISO 14443-2 B/ISO 15693"); + else + PrintAndLog("Coding: ISO 14443B only"); + } + if ((fuses & FUSE_CRYPT1) && (fuses & FUSE_CRYPT0)) PrintAndLog(" Crypt: Secured page, keys not locked"); + if ((fuses & FUSE_CRYPT1) && !(fuses & FUSE_CRYPT0)) PrintAndLog(" Crypt: Secured page, keys locked"); + if (!(fuses & FUSE_CRYPT1) && (fuses & FUSE_CRYPT0)) PrintAndLog(" Crypt: Non secured page"); + if (!(fuses & FUSE_CRYPT1) && !(fuses & FUSE_CRYPT0)) PrintAndLog(" Crypt: No auth possible. Read only if RA is enabled"); + + if (fuses & FUSE_RA) + PrintAndLog(" RA: Read access enabled"); + else + PrintAndLog(" RA: Read access not enabled"); +} - for( i=0; i < 1900;) - { - //First 32 bits contain - // isResponse (1 bit) - // timestamp (remaining) - //Then paritybits - //Then length - timestamp = *((uint32_t *)(got+i)); - parityBits = *((uint32_t *)(got+i+4)); - len = got[i+8]; - frame = (got+i+9); - uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff; - - tagToReader = timestamp & 0x80000000; - timestamp &= 0x7fffffff; - - if(i==0) { - first_timestamp = timestamp; - } - // Break and stick with current result if buffer was not completely full - if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break; +static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t *app_areas, uint8_t *kb) { + // mem-bit 5, mem-bit 7, chip-bit 4: defines chip type + if((chip_cfg & 0x10) && !(mem_cfg & 0x80) && !(mem_cfg & 0x20)) { + *kb = 2; + *app_areas = 2; + *max_blk = 31; + } else if((chip_cfg & 0x10) && (mem_cfg & 0x80) && !(mem_cfg & 0x20)) { + *kb = 16; + *app_areas = 2; + *max_blk = 255; //16kb + } else if(!(chip_cfg & 0x10) && !(mem_cfg & 0x80) && !(mem_cfg & 0x20)) { + *kb = 16; + *app_areas = 16; + *max_blk = 255; //16kb + } else if((chip_cfg & 0x10) && (mem_cfg & 0x80) && (mem_cfg & 0x20)) { + *kb = 32; + *app_areas = 3; + *max_blk = 255; //16kb + } else if(!(chip_cfg & 0x10) && !(mem_cfg & 0x80) && (mem_cfg & 0x20)) { + *kb = 32; + *app_areas = 17; + *max_blk = 255; //16kb + } else { + *kb = 32; + *app_areas = 2; + *max_blk = 255; + } +} - char line[1000] = ""; - if(len)//We have some data to display - { - int j,oddparity; +static void mem_app_config(const picopass_hdr *hdr) { + uint8_t mem = hdr->conf.mem_config; + uint8_t chip = hdr->conf.chip_config; + uint8_t applimit = hdr->conf.app_limit; + if (applimit < 6) applimit = 26; + uint8_t kb = 2; + uint8_t app_areas = 2; + uint8_t max_blk = 31; + getMemConfig(mem, chip, &max_blk, &app_areas, &kb); + PrintAndLog(" Mem: %u KBits/%u App Areas (%u * 8 bytes) [%02X]", kb, app_areas, max_blk+1, mem); + PrintAndLog(" AA1: blocks 06-%02X", applimit); + PrintAndLog(" AA2: blocks %02X-%02X", applimit+1, max_blk); +} - for(j = 0; j < len ; j++) - { - oddparity = 0x01 ^ xorbits_8(frame[j] & 0xFF); - if (tagToReader && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } else { - sprintf(line+(j*4), "%02x ", frame[j]); - } - } - }else - { - if (ShowWaitCycles) { - sprintf(line, "fdt (Frame Delay Time): %d", (next_timestamp - timestamp)); - } - } +static void printIclassDumpInfo(uint8_t* iclass_dump) { + fuse_config((picopass_hdr*)iclass_dump); + mem_app_config((picopass_hdr*)iclass_dump); +} - char *crc = ""; - if(len > 2) - { - uint8_t b1, b2; - if(!tagToReader && len == 4) { - // Rough guess that this is a command from the reader - // For iClass the command byte is not part of the CRC - ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2); - } - else { - // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2); - } +static void usage_hf_iclass_chk(void) { + PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag"); + PrintAndLog("Usage: hf iclass chk [h|e|r] "); + PrintAndLog("Options:"); + PrintAndLog("h Show this help"); + PrintAndLog("f Dictionary file with default iclass keys"); + PrintAndLog(" e target Elite / High security key scheme"); + PrintAndLog(" r interpret dictionary file as raw (diversified keys)"); + PrintAndLog("Samples:"); + PrintAndLog(" hf iclass chk f default_iclass_keys.dic"); + PrintAndLog(" hf iclass chk f default_iclass_keys.dic e"); +} - if (b1 != frame[len-2] || b2 != frame[len-1]) { - crc = (tagToReader & (len < 8)) ? "" : " !crc"; - } - } - i += (len + 9); - EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff; +static int CmdHFiClassList(const char *Cmd) { + PrintAndLog("Deprecated command, use 'hf list iclass' instead"); + return 0; +} + - // Not implemented for iclass on the ARM-side - //if (!ShowWaitCycles) i += 9; +static int CmdHFiClassSnoop(const char *Cmd) { - PrintAndLog(" %9d | %9d | %s | %s %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (len?(tagToReader ? "Tag" : "Rdr"):" "), - line, crc); + CLIParserInit("hf iclass snoop", "\nSnoop a communication between an iClass Reader and an iClass Tag.", NULL); + void* argtable[] = { + arg_param_begin, + arg_lit0("j", "jam", "Jam (prevent) e-purse Updates"), + arg_param_end + }; + if (CLIParserParseString(Cmd, argtable, arg_getsize(argtable), true)){ + CLIParserFree(); + return 0; } - return 0; -} -int CmdHFiClassListOld(const char *Cmd) -{ - uint8_t got[1920]; - GetFromBigBuf(got,sizeof(got),0); - - PrintAndLog("recorded activity:"); - PrintAndLog(" ETU :rssi: who bytes"); - PrintAndLog("---------+----+----+-----------"); - - int i = 0; - int prev = -1; - - for (;;) { - if(i >= 1900) { - break; - } - - bool isResponse; - int timestamp = *((uint32_t *)(got+i)); - if (timestamp & 0x80000000) { - timestamp &= 0x7fffffff; - isResponse = 1; - } else { - isResponse = 0; - } - - - int metric = 0; - - int parityBits = *((uint32_t *)(got+i+4)); - // 4 bytes of additional information... - // maximum of 32 additional parity bit information - // - // TODO: - // at each quarter bit period we can send power level (16 levels) - // or each half bit period in 256 levels. - - - int len = got[i+8]; - - if (len > 100) { - break; - } - if (i + len >= 1900) { - break; - } - - uint8_t *frame = (got+i+9); - - // Break and stick with current result if buffer was not completely full - if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; } - - char line[1000] = ""; - int j; - for (j = 0; j < len; j++) { - int oddparity = 0x01; - int k; - - for (k=0;k<8;k++) { - oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); - } - - //if((parityBits >> (len - j - 1)) & 0x01) { - if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } - else { - sprintf(line+(j*4), "%02x ", frame[j]); - } - } - - char *crc; - crc = ""; - if (len > 2) { - uint8_t b1, b2; - for (j = 0; j < (len - 1); j++) { - // gives problems... search for the reason.. - /*if(frame[j] == 0xAA) { - switch(frame[j+1]) { - case 0x01: - crc = "[1] Two drops close after each other"; - break; - case 0x02: - crc = "[2] Potential SOC with a drop in second half of bitperiod"; - break; - case 0x03: - crc = "[3] Segment Z after segment X is not possible"; - break; - case 0x04: - crc = "[4] Parity bit of a fully received byte was wrong"; - break; - default: - crc = "[?] Unknown error"; - break; - } - break; - }*/ - } - - if (strlen(crc)==0) { - if(!isResponse && len == 4) { - // Rough guess that this is a command from the reader - // For iClass the command byte is not part of the CRC - ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2); + bool jam_epurse_update = arg_get_lit(1); + + const uint8_t update_epurse_sequence[2] = {0x87, 0x02}; + + UsbCommand c = {CMD_SNOOP_ICLASS, {0}}; + if (jam_epurse_update) { + c.arg[0] = sizeof(update_epurse_sequence); + memcpy(c.d.asBytes, update_epurse_sequence, sizeof(update_epurse_sequence)); } - else { - // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2); - } - //printf("%1x %1x",(unsigned)b1,(unsigned)b2); - if (b1 != frame[len-2] || b2 != frame[len-1]) { - crc = (isResponse & (len < 8)) ? "" : " !crc"; - } else { - crc = ""; - } - } - } else { - crc = ""; // SHORT - } - - char metricString[100]; - if (isResponse) { - sprintf(metricString, "%3d", metric); - } else { - strcpy(metricString, " "); - } - - PrintAndLog(" +%7d: %s: %s %s %s", - (prev < 0 ? 0 : (timestamp - prev)), - metricString, - (isResponse ? "TAG" : " "), line, crc); - - prev = timestamp; - i += (len + 9); - } - return 0; -} - -/*void iso14a_set_timeout(uint32_t timeout) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}}; SendCommand(&c); -}*/ -int CmdHFiClassSnoop(const char *Cmd) -{ - UsbCommand c = {CMD_SNOOP_ICLASS}; - SendCommand(&c); - return 0; + return 0; } -int CmdHFiClassSim(const char *Cmd) -{ - uint8_t simType = 0; - uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - if (strlen(Cmd)<1) { - PrintAndLog("Usage: hf iclass sim [0 ] | x"); +static void usage_hf_iclass_sim(void) { + PrintAndLog("Usage: hf iclass sim