//----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch // Copyright (C) 2011 Gerhard de Koning Gans // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende // Copyright (C) 2019 piwi // // 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. //----------------------------------------------------------------------------- // High frequency iClass commands //----------------------------------------------------------------------------- #include #include #include #include #include #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type #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 } }; // 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; 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; static void fuse_config(const picopass_hdr *hdr) { uint8_t fuses = hdr->conf.fuses; 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"); } 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; } } 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); } static void printIclassDumpInfo(uint8_t* iclass_dump) { fuse_config((picopass_hdr*)iclass_dump); mem_app_config((picopass_hdr*)iclass_dump); } 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"); } static int CmdHFiClassList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list iclass' instead"); return 0; } static int CmdHFiClassSnoop(const char *Cmd) { 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; } 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)); } SendCommand(&c); return 0; } static void usage_hf_iclass_sim(void) { PrintAndLog("Usage: hf iclass sim