From a1529b44ca77236cc15fd099e39a2fa6fd0e9b3b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 19 Jul 2020 20:45:47 +0200 Subject: [PATCH] fix auth and --- armsrc/appmain.c | 6 + armsrc/iclass.c | 55 ++------ armsrc/iso15693.c | 228 +++++++++++++++++------------- client/src/cmdhficlass.c | 293 +++++++++++++++++++++++++-------------- client/src/cmdhficlass.h | 13 -- common/cardhelper.c | 11 ++ common/cardhelper.h | 1 + include/pm3_cmd.h | 17 +++ 8 files changed, 367 insertions(+), 257 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 094982a3c..7f4f24c43 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -960,6 +960,7 @@ static void PacketReceived(PacketCommandNG *packet) { case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type SniffHitag2(); // SniffHitag2(packet->oldarg[0]); + reply_ng(CMD_LF_HITAG_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content @@ -1027,6 +1028,7 @@ static void PacketReceived(PacketCommandNG *packet) { } PACKED; struct p *payload = (struct p *) packet->data.asBytes; SniffIso15693(payload->jam_search_len, payload->jam_search_string); + reply_ng(CMD_HF_ISO15693_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_ISO15693_COMMAND: { @@ -1089,6 +1091,7 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_HF_ISO14443B_SNIFF: { SniffIso14443b(); + reply_ng(CMD_HF_ISO14443B_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_ISO14443B_SIMULATE: { @@ -1113,6 +1116,7 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_HF_FELICA_SNIFF: { felica_sniff(packet->oldarg[0], packet->oldarg[1]); + reply_ng(CMD_HF_FELICA_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_FELICALITE_DUMP: { @@ -1124,6 +1128,7 @@ static void PacketReceived(PacketCommandNG *packet) { #ifdef WITH_ISO14443a case CMD_HF_ISO14443A_SNIFF: { SniffIso14443a(packet->data.asBytes[0]); + reply_ng(CMD_HF_ISO14443A_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_ISO14443A_READER: { @@ -1380,6 +1385,7 @@ static void PacketReceived(PacketCommandNG *packet) { } PACKED; struct p *payload = (struct p *) packet->data.asBytes; SniffIClass(payload->jam_search_len, payload->jam_search_string); + reply_ng(CMD_HF_ICLASS_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_ICLASS_SIMULATE: { diff --git a/armsrc/iclass.c b/armsrc/iclass.c index d8892a74c..fa161b813 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -38,7 +38,7 @@ // The length of a received command will in most cases be no more than 18 bytes. // we expect max 34 bytes as tag answer (response to READ4) #ifndef ICLASS_BUFFER_SIZE -#define ICLASS_BUFFER_SIZE 34 +#define ICLASS_BUFFER_SIZE 34 + 2 #endif // iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after @@ -481,7 +481,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t cmd, options, block; int len = 0; - bool exit_loop = 0; + bool exit_loop = false; while (exit_loop == false) { WDT_HIT(); @@ -863,12 +863,11 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; static uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; - static uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; + uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used // bit 7: parity. - if (use_credit_key) read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; @@ -878,7 +877,6 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t int len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time); if (len < 0) return false; - // send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -936,7 +934,7 @@ void ReaderIClass(uint8_t flags) { uint8_t card_data[6 * 8] = {0xFF}; // uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; memset(resp, 0xFF, sizeof(resp)); // bool flag_readonce = flags & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully @@ -1162,21 +1160,9 @@ void iClass_Authentication(uint8_t *bytes) { bool iclass_auth(uint8_t *bytes, bool send_reply, uint8_t *dataout) { - struct p { - uint8_t key[8]; - bool use_raw; - bool use_elite; - bool use_credit_key; - } PACKED; - struct p *payload = (struct p *)bytes; - - // device response message - struct { - bool isOK; - uint8_t div_key[8]; - uint8_t mac[4]; - } PACKED packet; - + iclass_auth_req_t *payload = (iclass_auth_req_t *)bytes; + iclass_auth_resp_t packet; + Iso15693InitReader(); uint8_t card_data[3 * 8] = {0xFF}; @@ -1208,7 +1194,7 @@ bool iclass_auth(uint8_t *bytes, bool send_reply, uint8_t *dataout) { check[7] = packet.mac[2]; check[8] = packet.mac[3]; - uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; packet.isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); if (send_reply) @@ -1236,12 +1222,12 @@ typedef struct iclass_premac { void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { uint8_t i = 0, isOK = 0; - uint8_t lastChunk = ((arg0 >> 8) & 0xFF); +// uint8_t lastChunk = ((arg0 >> 8) & 0xFF); bool use_credit_key = ((arg0 >> 16) & 0xFF); uint8_t keyCount = arg1 & 0xFF; uint8_t check[9] = { ICLASS_CMD_CHECK }; - uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; if (use_credit_key) @@ -1260,8 +1246,8 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { Iso15693InitReader(); - uint32_t start_time = 0; - uint32_t eof_time = 0; + uint32_t start_time = 0, eof_time = 0; + if (select_iclass_tag(card_data, use_credit_key, &eof_time) == false) goto out; @@ -1305,15 +1291,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { out: // send keyindex. reply_mix(CMD_HF_ICLASS_CHKKEYS, isOK, i, 0, 0, 0); - - if (isOK >= 1 || lastChunk) { - LED_A_OFF(); - } - switch_off(); - - LED_B_OFF(); - LED_C_OFF(); } // Tries to read block. @@ -1338,8 +1316,8 @@ void iClass_ReadBlk(uint8_t blockno) { LED_A_ON(); result.isOK = iclass_readblock(blockno, result.blockdata); - switch_off(); reply_ng(CMD_HF_ICLASS_READBL, PM3_SUCCESS, (uint8_t *)&result, sizeof(result)); + switch_off(); } // Dump command seems to dump a block related portion of card memory. @@ -1372,11 +1350,6 @@ void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { switch_off(); - // return pointer to dump memory in arg3 - // iceman: why not return | dataout - getbigbuf ? Should give exact location. -// Dbprintf("ICE:: dataout, %u max trace %u, bb start %u, data-bb %u ", dataout, BigBuf_max_traceLen(), BigBuf_get_addr(), dataout - BigBuf_get_addr() ); -// Dbprintf("ICE:: bb size %u, malloced %u (255*8)", BigBuf_get_size(), BigBuf_get_size() - (dataout - BigBuf_get_addr()) ); -// reply_mix(CMD_ACK, isOK, blkcnt, BigBuf_max_traceLen(), 0, 0); struct p { bool isOK; uint8_t block_cnt; @@ -1384,7 +1357,7 @@ void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { } PACKED payload; payload.isOK = isOK; payload.block_cnt = blkcnt; - payload.bb_offset = BigBuf_max_traceLen(); + payload.bb_offset = dataout - BigBuf_get_addr(); reply_ng(CMD_HF_ICLASS_DUMP, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); BigBuf_free(); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 36530f72b..df576d3b3 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -91,7 +91,6 @@ /////////////////////////////////////////////////////////////////////// // buffers -//#define ISO15693_DMA_BUFFER_SIZE 256 // must be a power of 2 #define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet #define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet @@ -106,7 +105,6 @@ #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) static void BuildIdentifyRequest(uint8_t *cmd); -static void BuildInventoryResponse(uint8_t *uid); // --------------------------- // Signal Processing @@ -255,12 +253,13 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { *start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time } - while (GetCountSspClk() < *start_time) - /* wait */ ; + // wait + while (GetCountSspClk() < *start_time) ; LED_B_ON(); for (int c = 0; c < len; c++) { volatile uint8_t data = cmd[c]; + for (uint8_t i = 0; i < 8; i++) { uint16_t send_word = (data & 0x80) ? 0xffff : 0x0000; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; @@ -294,8 +293,8 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, } } - while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) - /* wait */ ; + // wait + while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) ; uint8_t shift_delay = modulation_start_time & 0x00000007; @@ -304,9 +303,12 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, LED_C_ON(); uint8_t bits_to_shift = 0x00; uint8_t bits_to_send = 0x00; + for (size_t c = 0; c < len; c++) { for (int i = (c == 0 ? 4 : 7); i >= 0; i--) { + uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; + for (int j = 0; j < (slow ? 4 : 1); ) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; @@ -380,7 +382,7 @@ typedef struct DecodeTag { //----------------------------------------------------------------------------- static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { switch (DecodeTag->state) { - case STATE_TAG_SOF_LOW: + case STATE_TAG_SOF_LOW: { // waiting for a rising edge if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) { if (DecodeTag->posCount > 10) { @@ -395,8 +397,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De DecodeTag->previous_amplitude = amplitude; } break; - - case STATE_TAG_SOF_RISING_EDGE: + } + case STATE_TAG_SOF_RISING_EDGE: { if (amplitude > DecodeTag->threshold_sof + DecodeTag->previous_amplitude) { // edge still rising if (amplitude > DecodeTag->threshold_sof + DecodeTag->threshold_sof) { // steeper edge, take this as time reference DecodeTag->posCount = 1; @@ -411,8 +413,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De // DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_SOF_HIGH; break; - - case STATE_TAG_SOF_HIGH: + } + case STATE_TAG_SOF_HIGH: { // waiting for 10 times high. Take average over the last 8 if (amplitude > DecodeTag->threshold_sof) { DecodeTag->posCount++; @@ -429,8 +431,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De DecodeTag->state = STATE_TAG_SOF_LOW; } break; - - case STATE_TAG_SOF_HIGH_END: + } + case STATE_TAG_SOF_HIGH_END: { // check for falling edge if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) { DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) @@ -458,8 +460,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De } } break; - - case STATE_TAG_RECEIVING_DATA: + } + case STATE_TAG_RECEIVING_DATA: { // FpgaDisableTracing(); // DEBUGGING // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", // amplitude, @@ -547,8 +549,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De } DecodeTag->posCount++; break; - - case STATE_TAG_EOF: + } + case STATE_TAG_EOF: { if (DecodeTag->posCount == 1) { DecodeTag->sum1 = 0; DecodeTag->sum2 = 0; @@ -571,8 +573,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De } DecodeTag->posCount++; break; - - case STATE_TAG_EOF_TAIL: + } + case STATE_TAG_EOF_TAIL: { if (DecodeTag->posCount == 1) { DecodeTag->sum1 = 0; DecodeTag->sum2 = 0; @@ -595,6 +597,7 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De } DecodeTag->posCount++; break; + } } return false; @@ -690,20 +693,22 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo FpgaDisableSscDma(); + uint32_t sof_time = *eof_time - (DecodeTag.len * 8 * 8 * 16) // time for byte transfers - (32 * 16) // time for SOF transfer - (DecodeTag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d", + Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d, maxlen = %u", samples, ret, DecodeTag.state, DecodeTag.lastBit, DecodeTag.len, DecodeTag.bitCount, - DecodeTag.posCount + DecodeTag.posCount, + DecodeTag.max_len ); Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); } @@ -890,11 +895,11 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: DecodeReader->posCount++; if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit?1:0; + DecodeReader->sum1 = bit ? 1 : 0; } else if (DecodeReader->posCount <= 4) { if (bit) DecodeReader->sum1++; } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit?1:0; + DecodeReader->sum2 = bit ? 1 : 0; } else { if (bit) DecodeReader->sum2++; } @@ -935,11 +940,11 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: DecodeReader->posCount++; if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit?1:0; + DecodeReader->sum1 = bit ? 1 : 0; } else if (DecodeReader->posCount <= 4) { if (bit) DecodeReader->sum1++; } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit?1:0; + DecodeReader->sum2 = bit ? 1 : 0; } else if (bit) { DecodeReader->sum2++; } @@ -976,20 +981,20 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR case STATE_READER_RECEIVE_JAMMING: DecodeReader->posCount++; if (DecodeReader->Coding == CODING_1_OUT_OF_4) { - if (DecodeReader->posCount == 7*16) { // 7 bits jammed + if (DecodeReader->posCount == 7 * 16) { // 7 bits jammed FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming // FpgaDisableTracing(); LED_D_OFF(); - } else if (DecodeReader->posCount == 8*16) { + } else if (DecodeReader->posCount == 8 * 16) { DecodeReader->posCount = 0; DecodeReader->output[DecodeReader->byteCount++] = 0x00; DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; } } else { - if (DecodeReader->posCount == 7*256) { // 7 bits jammend + if (DecodeReader->posCount == 7 * 256) { // 7 bits jammend FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming LED_D_OFF(); - } else if (DecodeReader->posCount == 8*256) { + } else if (DecodeReader->posCount == 8 * 256) { DecodeReader->posCount = 0; DecodeReader->output[DecodeReader->byteCount++] = 0x00; DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; @@ -1083,8 +1088,11 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo FpgaDisableSscDma(); - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", + samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, + DecodeReader.bitCount, DecodeReader.posCount); + } if (DecodeReader.byteCount > 0) { uint32_t sof_time = *eof_time @@ -1154,11 +1162,11 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { int samples = 0; DecodeTag_t DecodeTag = {0}; - uint8_t response[ISO15693_MAX_RESPONSE_LENGTH]; + uint8_t response[ISO15693_MAX_RESPONSE_LENGTH] = {0}; DecodeTagInit(&DecodeTag, response, sizeof(response)); DecodeReader_t DecodeReader = {0}; - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH] = {0}; DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd), jam_search_len, jam_search_string); // Print some debug information about the buffer sizes @@ -1166,7 +1174,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { Dbprintf("Sniffing buffers initialized:"); Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); - Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); + Dbprintf(" Tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE * sizeof(uint16_t)); } @@ -1184,9 +1192,9 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { FpgaSetupSscDma((uint8_t*)dma->buf, DMA_BUFFER_SIZE); uint16_t *upTo = dma->buf; - bool TagIsActive = false; - bool ReaderIsActive = false; - bool ExpectTagAnswer = false; + bool tag_is_active = false; + bool reader_is_active = false; + bool expect_tag_answer = false; uint32_t dma_start_time = 0; uint16_t max_behindBy = 0; @@ -1225,7 +1233,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { } // no need to try decoding reader data if the tag is sending - if (TagIsActive == false) { + if (tag_is_active == false) { if (Handle15693SampleFromReader(sniffdata & 0x02, &DecodeReader)) { @@ -1242,8 +1250,8 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // And also reset the demod code, which might have been // false-triggered by the commands from the reader. DecodeTagReset(&DecodeTag); - ReaderIsActive = false; - ExpectTagAnswer = true; + reader_is_active = false; + expect_tag_answer = true; } else if (Handle15693SampleFromReader(sniffdata & 0x01, &DecodeReader)) { @@ -1261,15 +1269,15 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // And also reset the demod code, which might have been // false-triggered by the commands from the reader. DecodeTagReset(&DecodeTag); - ReaderIsActive = false; - ExpectTagAnswer = true; + reader_is_active = false; + expect_tag_answer = true; } else { - ReaderIsActive = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); + reader_is_active = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); } } - if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + if (!reader_is_active && expect_tag_answer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet if (Handle15693SamplesFromTag(sniffdata >> 2, &DecodeTag)) { uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF @@ -1285,19 +1293,18 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // And ready to receive another response. DecodeTagReset(&DecodeTag); DecodeReaderReset(&DecodeReader); - ExpectTagAnswer = false; - TagIsActive = false; + expect_tag_answer = false; + tag_is_active = false; } else { - TagIsActive = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); + tag_is_active = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); } } } - - FpgaDisableSscDma(); + switch_off(); DbpString("Sniff statistics:"); - Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", ExpectTagAnswer, TagIsActive, ReaderIsActive); + Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", expect_tag_answer, tag_is_active, reader_is_active); Dbprintf(" DecodeTag State: %d", DecodeTag.state); Dbprintf(" DecodeTag byteCnt: %d", DecodeTag.len); Dbprintf(" DecodeTag posCount: %d", DecodeTag.posCount); @@ -1305,18 +1312,18 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { Dbprintf(" DecodeReader byteCnt: %d", DecodeReader.byteCount); Dbprintf(" DecodeReader posCount: %d", DecodeReader.posCount); Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); - Dbprintf(" Max behindBy: %d", max_behindBy); + Dbprintf(" Max behindBy: %d", max_behindBy); } // Initialize Proxmark3 as ISO15693 reader void Iso15693InitReader(void) { - + + LEDsoff(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Start from off (no field generated) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - SpinDelay(50); + SpinDelay(10); // switch field on FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); @@ -1329,7 +1336,7 @@ void Iso15693InitReader(void) { set_tracing(true); // give tags some time to energize - SpinDelay(200); + SpinDelay(250); StartCountSspClk(); } @@ -1354,31 +1361,6 @@ static void BuildIdentifyRequest(uint8_t *cmd) { AddCrc15(cmd, 3); } -// uid is in transmission order (which is reverse of display order) - -// When SIM: now the VICC>VCD responses when we are simulating a tag -static void BuildInventoryResponse(uint8_t *uid) { - - uint8_t cmd[CMD_INV_RESP] = {0}; - - cmd[0] = 0; // No error, no protocol format extension - cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported - - // 64-bit UID - cmd[2] = uid[7]; - cmd[3] = uid[6]; - cmd[4] = uid[5]; - cmd[5] = uid[4]; - cmd[6] = uid[3]; - cmd[7] = uid[2]; - cmd[8] = uid[1]; - cmd[9] = uid[0]; - - // CRC - AddCrc15(cmd, 10); - CodeIso15693AsTag(cmd, CMD_INV_RESP); -} - // Universal Method for sending to and recv bytes from a tag // init ... should we initialize the reader? // speed ... 0 low speed, 1 hi speed @@ -1403,7 +1385,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, &start_time); - uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // substract the 4 padding bits after EOF + uint32_t end_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF LogTrace(send, sendlen, (start_time * 4), (end_time * 4), NULL, true); int res = 0; @@ -1573,9 +1555,9 @@ void Iso15693InitTag(void) { FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + clear_trace(); set_tracing(true); - // turn on clock StartCountSspClk(); } @@ -1583,44 +1565,90 @@ void Iso15693InitTag(void) { // all demodulation performed in arm rather than host. - greg void SimTagIso15693(uint8_t *uid) { + // free eventually allocated BigBuf memory + BigBuf_free_keep_EM(); + Iso15693InitTag(); LED_A_ON(); Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]); - uint8_t buf[ISO15_MAX_FRAME]; - memset(buf, 0x00, sizeof(buf)); - LED_C_ON(); - // Build a suitable reponse to the reader INVENTORY cocmmand - // not so obvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. - BuildInventoryResponse(uid); + // Build INVENTORY command + uint8_t resp_inv[CMD_INV_RESP] = {0}; + + resp_inv[0] = 0; // No error, no protocol format extension + resp_inv[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported + + // 64-bit UID + resp_inv[2] = uid[7]; + resp_inv[3] = uid[6]; + resp_inv[4] = uid[5]; + resp_inv[5] = uid[4]; + resp_inv[6] = uid[3]; + resp_inv[7] = uid[2]; + resp_inv[8] = uid[1]; + resp_inv[9] = uid[0]; + + // CRC + AddCrc15(resp_inv, 10); + CodeIso15693AsTag(resp_inv, CMD_INV_RESP); tosend_t *ts = get_tosend(); - while (!BUTTON_PRESS()) { + enum { NO_FIELD, IDLE, ACTIVATED, SELECTED, HALTED } chip_state = NO_FIELD; + + bool button_pressed = false; + int vHf = 0; // in mV + + bool exit_loop = false; + while (exit_loop == false) { WDT_HIT(); + // find reader field + if (chip_state == NO_FIELD) { + +#if defined RDV4 + vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; +#else + vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; +#endif + if (vHf > MF_MINFIELDV) { + chip_state = IDLE; + LED_A_ON(); + } else { + continue; + } + } + // Listen to reader uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; - uint32_t eof_time = 0, start_time = 0; - int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); - - if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { // TODO: check more flags - bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); - start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - TransmitTo15693Reader(ts->buf, ts->max, &start_time, 0, slow); + uint32_t reader_eof_time = 0; + int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &reader_eof_time); + if (cmd_len < 0) { + Dbprintf("button pressed, exiting"); + button_pressed = true; + exit_loop = true; + break; } - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf(" %d bytes read from reader:", cmd_len); - Dbhexdump(cmd_len, cmd, false); + // TODO: check more flags + if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { + bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); + uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; + TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); + LogTrace(resp_inv, CMD_INV_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); + + chip_state = SELECTED; } } - + switch_off(); + + if (button_pressed) + DbpString("button pressed"); } // Since there is no standardized way of reading the AFI out of a tag, we will brute force it diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 80f6dfab5..d063f1607 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -47,7 +47,7 @@ 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 }, }; static int usage_hf_iclass_sim(void) { @@ -379,6 +379,28 @@ static inline uint32_t leadingzeros(uint64_t a) { #endif } +// iclass card descriptors +const char * card_types[] = { + "PicoPass 16K / 16", // 000 + "PicoPass 32K with current book 16K / 16", // 001 + "Unknown Card Type!", // 010 + "Unknown Card Type!", // 011 + "PicoPass 2K", // 100 + "Unknown Card Type!", // 101 + "PicoPass 16K / 2", // 110 + "PicoPass 32K with current book 16K / 2", // 111 +}; + +uint8_t card_app2_limit[] = { + 0xff, + 0xff, + 0xff, + 0xff, + 0x1f, + 0xff, + 0xff, + 0xff, +}; static uint8_t isset(uint8_t val, uint8_t mask) { return (val & mask); @@ -434,7 +456,7 @@ static void fuse_config(const picopass_hdr *hdr) { ); } -static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t *app_areas, uint8_t *kb) { +static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb) { // mem-bit 5, mem-bit 7, chip-bit 4: defines chip type uint8_t k16 = isset(mem_cfg, 0x80); //uint8_t k2 = isset(mem_cfg, 0x08); @@ -443,47 +465,54 @@ static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, ui if (isset(chip_cfg, 0x10) && !k16 && !book) { *kb = 2; *app_areas = 2; - *max_blk = 31; } else if (isset(chip_cfg, 0x10) && k16 && !book) { *kb = 16; *app_areas = 2; - *max_blk = 255; //16kb } else if (notset(chip_cfg, 0x10) && !k16 && !book) { *kb = 16; *app_areas = 16; - *max_blk = 255; //16kb } else if (isset(chip_cfg, 0x10) && k16 && book) { *kb = 32; *app_areas = 3; - *max_blk = 255; //16kb } else if (notset(chip_cfg, 0x10) && !k16 && book) { *kb = 32; *app_areas = 17; - *max_blk = 255; //16kb } else { *kb = 32; *app_areas = 2; - *max_blk = 255; } } +static uint8_t get_mem_config(const picopass_hdr *hdr) { + uint8_t mem = hdr->conf.mem_config; + uint8_t chip = hdr->conf.chip_config; + // three configuration bits that decides sizes + uint8_t type = (chip & 0x10) >> 2; + type |= (mem & 0x80) >> 6; + type |= (mem & 0x20) >> 5; + return type; +} + 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; uint8_t kb = 2; uint8_t app_areas = 2; - uint8_t max_blk = 31; - getMemConfig(mem, chip, &max_blk, &app_areas, &kb); + getMemConfig(mem, chip, &app_areas, &kb); - if (applimit < 6) applimit = 26; - if (kb == 2 && (applimit > 0x1f)) applimit = 26; + // three configuration bits that decides sizes + uint8_t type = (chip & 0x10) >> 2; + type |= (mem & 0x80) >> 6; + type |= (mem & 0x20) >> 5; + + uint8_t app1_limit = hdr->conf.app_limit - 5; // minus header blocks + uint8_t app2_limit = card_app2_limit[type]; PrintAndLogEx(INFO, "------ " _CYAN_("Memory") " ------"); - PrintAndLogEx(INFO, " %u KBits/%u App Areas (%u bytes), max blocks 0x%02X (%02d)", kb, app_areas, max_blk * 8, mem, mem); - PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", applimit - 5 , applimit, applimit); - PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", max_blk - applimit, applimit + 1, max_blk, applimit + 1, max_blk); + PrintAndLogEx(INFO, " %u KBits/%u App Areas (%u bytes)", kb, app_areas, app2_limit * 8); + PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit , app1_limit + 5, app1_limit + 5); + PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit); PrintAndLogEx(INFO, "------ " _CYAN_("KeyAccess") " ------"); PrintAndLogEx(INFO, " Kd = Debit key (AA1), Kc = Credit key (AA2)"); @@ -552,7 +581,15 @@ static int CmdHFiClassSniff(const char *Cmd) { payload.jam_search_len = sizeof(update_epurse_sequence); memcpy(payload.jam_search_string, update_epurse_sequence, sizeof(payload.jam_search_string)); } + + PacketResponseNG resp; + clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_SNIFF, (uint8_t *)&payload, sizeof(payload)); + + WaitForResponse(CMD_HF_ICLASS_SNIFF, &resp); + + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass list") "` to look at the collected trace"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save h") "` to save tracelog for later analysing"); return PM3_SUCCESS; } @@ -956,6 +993,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { } if (have_file) { + picopass_hdr *hdr = (picopass_hdr *)decrypted; uint8_t mem = hdr->conf.mem_config; @@ -963,10 +1001,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { uint8_t applimit = hdr->conf.app_limit; uint8_t kb = 2; uint8_t app_areas = 2; - uint8_t max_blk = 31; - getMemConfig(mem, chip, &max_blk, &app_areas, &kb); - - + getMemConfig(mem, chip, &app_areas, &kb); BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03); @@ -976,7 +1011,8 @@ static int CmdHFiClassDecrypt(const char *Cmd) { PrintAndLogEx(WARNING, "Actual file len " _YELLOW_("%zu") " vs HID app-limit len " _YELLOW_("%u"), decryptedlen, applimit * 8); PrintAndLogEx(INFO, "Setting limit to " _GREEN_("%u"), limit * 8); } - uint8_t numblocks4userid = GetNumberBlocksForUserId(decrypted + (6 * 8)); + + //uint8_t numblocks4userid = GetNumberBlocksForUserId(decrypted + (6 * 8)); for (uint16_t blocknum = 0; blocknum < limit; ++blocknum) { @@ -987,7 +1023,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { continue; // Decrypted block 7,8,9 if configured. - if (blocknum > 6 && blocknum <= 6 + numblocks4userid && memcmp(enc_data, empty, 8) != 0) { + if (blocknum > 6 && blocknum <= 9 && memcmp(enc_data, empty, 8) != 0) { if (use_sc) { Decrypt(enc_data, decrypted + idx); } else { @@ -996,13 +1032,14 @@ static int CmdHFiClassDecrypt(const char *Cmd) { } } - //Use the first block (CSN) for filename + // use the first block (CSN) for filename char *fptr = calloc(50, sizeof(uint8_t)); - if (!fptr) { + if (fptr == false) { PrintAndLogEx(WARNING, "Failed to allocate memory"); free(decrypted); return PM3_EMALLOC; } + strcat(fptr, "hf-iclass-"); FillFileNameByUID(fptr, hdr->csn, "-dump-decrypted", sizeof(hdr->csn)); @@ -1013,6 +1050,8 @@ static int CmdHFiClassDecrypt(const char *Cmd) { PrintAndLogEx(INFO, "Following output skips CSN / block0"); printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen); + PrintAndLogEx(NORMAL, ""); + // decode block 6 if (memcmp(decrypted + (8 * 6), empty, 8) != 0) { if (use_sc) { @@ -1029,7 +1068,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { mid = bytes_to_num(decrypted + (8 * 7), 4); bot = bytes_to_num(decrypted + (8 * 7) + 4, 4); - PrintAndLogEx(INFO, "Block 7 binary"); + PrintAndLogEx(INFO, "Block 7 decoder"); char hexstr[8 + 1] = {0}; hex_to_buffer((uint8_t *)hexstr, decrypted + (8 * 7), 8, sizeof(hexstr) - 1, 0, 0, true); @@ -1039,15 +1078,36 @@ static int CmdHFiClassDecrypt(const char *Cmd) { uint8_t i = 0; while (i < strlen(binstr) && binstr[i++] == '0'); - PrintAndLogEx(SUCCESS, "%s", binstr + i); + PrintAndLogEx(SUCCESS, "Binary..................... " _GREEN_("%s"), binstr + i); PrintAndLogEx(INFO, "Wiegand decode"); wiegand_message_t packed = initialize_message_object(top, mid, bot); HIDTryUnpack(&packed, true); - PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + } else { PrintAndLogEx(INFO, "No credential found."); } + + // decode block 9 + if (memcmp(decrypted + (8 * 9), empty, 8) != 0) { + + uint8_t usr_blk_len = GetNumberBlocksForUserId(decrypted + (8 * 6)); + if (usr_blk_len < 3) { + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Block 9 decoder"); + uint8_t pinsize = 10; + if (use_sc) { + pinsize = GetPinSize(decrypted + (8 * 6)); + } + uint64_t pin = bytes_to_num(decrypted + (8 * 9), 5); + char tmp[17] = {0}; + sprintf(tmp, "%."PRIu64, BCD2DEC(pin)); + PrintAndLogEx(INFO, "PIN........................ " _GREEN_("%.*s"), pinsize, tmp); + } + } + + PrintAndLogEx(INFO, "-----------------------------------------------------------------"); free(decrypted); free(fptr); @@ -1178,7 +1238,7 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u .use_credit_key = use_credit_key }; memcpy(payload.key, KEY, 8); - + SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t*)&payload, sizeof(payload)); PacketResponseNG resp; clearCommandBuffer(); @@ -1205,7 +1265,9 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u if (MAC) memcpy(MAC, packet->mac, sizeof(packet->mac)); - if (verbose) PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); + if (verbose) + PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); + return true; } @@ -1214,15 +1276,11 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t c_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t blockno = 0; - uint8_t numblks = 0; - uint8_t maxBlk = 31; - uint8_t app_areas = 1; - uint8_t kb = 2; uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t CreditKEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t keyNbr = 0; uint8_t dataLen = 0; + uint8_t app_limit1, app_limit2 = 0; uint8_t fileNameLen = 0; char filename[FILE_PATH_SIZE] = {0}; char tempStr[50] = {0}; @@ -1329,6 +1387,7 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t readStatus = resp.oldarg[0] & 0xff; uint8_t *data = resp.data.asBytes; + picopass_hdr *hdr = (picopass_hdr *)data; if (readStatus == 0) { PrintAndLogEx(FAILED, "no tag found"); @@ -1338,11 +1397,14 @@ static int CmdHFiClassDump(const char *Cmd) { if (readStatus & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC)) { memcpy(tag_data, data, 8 * 3); - blockno += 2; // 2 to force re-read of block 2 later. (seems to respond differently..) - numblks = data[8]; - getMemConfig(data[13], data[12], &maxBlk, &app_areas, &kb); - // large memory - not able to dump pages currently - if (numblks > maxBlk) numblks = maxBlk; + + uint8_t type = get_mem_config(hdr); + app_limit1 = hdr->conf.app_limit; + app_limit2 = card_app2_limit[type]; + } else { + PrintAndLogEx(FAILED, "failed to read block 0,1,2"); + DropField(); + return PM3_ESOFT; } // authenticate debit key and get div_key - later store in dump block 3 @@ -1356,8 +1418,8 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t start_blockno; uint8_t numblks; } PACKED payload; - payload.start_blockno = blockno; - payload.numblks = numblks - blockno + 1; + payload.start_blockno = 5; + payload.numblks = app_limit1 - 5; clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); @@ -1397,20 +1459,24 @@ static int CmdHFiClassDump(const char *Cmd) { return PM3_ESOFT; } + uint16_t offset = (5 * 8); uint32_t startindex = packet->bb_offset; - if (blocks_read * 8 > sizeof(tag_data) - (blockno * 8)) { + if (blocks_read * 8 > sizeof(tag_data) - offset) { PrintAndLogEx(FAILED, "data exceeded buffer size!"); - blocks_read = (sizeof(tag_data) / 8) - blockno; + blocks_read = (sizeof(tag_data) / 8) - 5; } // response ok - now get bigbuf content of the dump - if (!GetFromDevice(BIG_BUF, tag_data + (blockno * 8), blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { + if (!GetFromDevice(BIG_BUF, tag_data + offset, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } + + PrintAndLogEx(INFO, "BB start index :: %u", startindex); + PrintAndLogEx(INFO, "BB :: %s", sprint_hex(tag_data + (5*8), 32)); - size_t gotBytes = blocks_read * 8 + blockno * 8; + offset += (blocks_read * 8); // try AA2 Kc, Credit if (have_credit_key) { @@ -1424,46 +1490,44 @@ static int CmdHFiClassDump(const char *Cmd) { return PM3_ESOFT; } - // do we still need to read more block? (aa2 enabled?) - if (maxBlk > blockno + numblks + 1) { + payload.start_blockno = app_limit1; + payload.numblks = app_limit2 - app_limit1 - 5; - payload.start_blockno = blockno + blocks_read; - payload.numblks = maxBlk - (blockno + blocks_read); + clearCommandBuffer(); + SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); - - if (!WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) { - PrintAndLogEx(WARNING, "command execute timeout 2"); - return PM3_ETIMEOUT; - } - - if (resp.status != PM3_SUCCESS) { - PrintAndLogEx(ERR, "failed to communicate with card"); - return resp.status; - } - - packet = (struct p_resp *)resp.data.asBytes; - if (packet->isOK == false) { - PrintAndLogEx(WARNING, "read block failed using credit key"); - return PM3_ESOFT; - } - - blocks_read = packet->block_cnt; - startindex = packet->bb_offset; - - if (blocks_read * 8 > sizeof(tag_data) - gotBytes) { - PrintAndLogEx(FAILED, "data exceeded buffer size!"); - blocks_read = (sizeof(tag_data) - gotBytes) / 8; - } - // get dumped data from bigbuf - if (!GetFromDevice(BIG_BUF, tag_data + gotBytes, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { - PrintAndLogEx(WARNING, "command execution time out"); - return PM3_ETIMEOUT; - } - - gotBytes += blocks_read * 8; + if (!WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) { + PrintAndLogEx(WARNING, "command execute timeout 2"); + return PM3_ETIMEOUT; } + + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to communicate with card"); + return resp.status; + } + + packet = (struct p_resp *)resp.data.asBytes; + if (packet->isOK == false) { + PrintAndLogEx(WARNING, "read block failed using credit key"); + return PM3_ESOFT; + } + + // + blocks_read = packet->block_cnt; + startindex = packet->bb_offset; + + if (blocks_read * 8 > sizeof(tag_data) - offset) { + PrintAndLogEx(FAILED, "data exceeded buffer size!"); + blocks_read = (sizeof(tag_data) - offset) / 8; + } + + // get dumped data from bigbuf + if (!GetFromDevice(BIG_BUF, tag_data + offset, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "command execution time out"); + return PM3_ETIMEOUT; + } + + offset += blocks_read * 8; } DropField(); @@ -1480,7 +1544,7 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "------+--+-------------------------+----------"); PrintAndLogEx(INFO, " CSN |00| " _GREEN_("%s") "|", sprint_hex(tag_data, 8)); - printIclassDumpContents(tag_data, 1, (gotBytes / 8), gotBytes); + printIclassDumpContents(tag_data, 1, (offset / 8), offset); if (filename[0] == 0) { //Use the first block (CSN) for filename @@ -1489,10 +1553,10 @@ static int CmdHFiClassDump(const char *Cmd) { } // save the dump to .bin file - PrintAndLogEx(SUCCESS, "saving dump file - %zu blocks read", gotBytes / 8); - saveFile(filename, ".bin", tag_data, gotBytes); - saveFileEML(filename, tag_data, gotBytes, 8); - saveFileJSON(filename, jsfIclass, tag_data, gotBytes, NULL); + PrintAndLogEx(SUCCESS, "saving dump file - %zu blocks read", offset / 8); + saveFile(filename, ".bin", tag_data, offset); + saveFileEML(filename, tag_data, offset, 8); + saveFileJSON(filename, jsfIclass, tag_data, offset, NULL); return PM3_SUCCESS; } @@ -1825,25 +1889,22 @@ static int CmdHFiClassCloneTag(const char *Cmd) { static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth) { - // return data. - struct p { - bool isOK; - uint8_t blockdata[8]; - } PACKED; - struct p *result = NULL; - // block 0,1 should always be able to read, and block 5 on some cards. if (auth || blockno >= 2) { uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (select_and_auth(KEY, MAC, div_key, (keyType == 0x18), elite, rawkey, verbose) == false) { + if (verbose) PrintAndLogEx(FAILED, "select/auth failed"); + DropField(); return PM3_ESOFT; } } else { uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (select_only(CSN, CCNR, (keyType == 0x18), verbose) == false) { - return PM3_ESOFT; + if (verbose) PrintAndLogEx(FAILED, "select only failed"); + DropField(); + return PM3_ESOFT; } } @@ -1851,22 +1912,29 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_READBL, (uint8_t *)&blockno, sizeof(uint8_t)); - if (WaitForResponseTimeout(CMD_HF_ICLASS_READBL, &resp, 2000) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_READBL, &resp, 2000) == false) { if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); DropField(); return PM3_ETIMEOUT; } + DropField(); + if (resp.status != PM3_SUCCESS) { if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); return PM3_EWRONGANSWER; } - result = (struct p *)resp.data.asBytes; - if (result->isOK == false) - return PM3_ESOFT; + // return data. + struct p { + bool isOK; + uint8_t blockdata[8]; + } PACKED; - DropField(); + struct p *result = (struct p *)resp.data.asBytes; + if (result->isOK == false) { + return PM3_ESOFT; + } PrintAndLogEx(SUCCESS, " block %02X : " _GREEN_("%s"), blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); @@ -1943,6 +2011,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { bool auth = false; bool verbose = false; uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': @@ -2000,10 +2069,10 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { if (got_blockno == false) errors = true; - if (errors || cmdp < 4) return usage_hf_iclass_readblock(); + if (errors) return usage_hf_iclass_readblock(); - if (!auth) - PrintAndLogEx(FAILED, "warning: no authentication used with read, only a few specific blocks can be read accurately without authentication."); + if (auth == false) + PrintAndLogEx(WARNING, "warning: no authentication used with read, only a few specific blocks can be read accurately without authentication."); return iclass_read_block(KEY, blockno, keyType, elite, rawkey, verbose, auth); } @@ -2993,6 +3062,20 @@ int CmdHFiClass(const char *Cmd) { return CmdsParse(CommandTable, Cmd); } + +//static void test_credential_type(void) { + // need AA1 key + // Block 5 -> tells if its a legacy or SIO, also tells which key to use. + + // tech | blocks used | desc | num of payloads + // -------+-----------------------+-----------------------------------+------ + // legacy | 6,7,8,9 | AA!, Access control payload | 1 + // SE | 6,7,8,9,10,11,12 | AA1, Secure identity object (SIO) | 1 + // SR | 6,7,8,9, | AA1, Access control payload | 2 + // | 10,11,12,13,14,15,16 | AA1, Secure identity object (SIO) | + // SEOS | | | +//} + int readIclass(bool loop, bool verbose) { bool tagFound = false; @@ -3079,6 +3162,10 @@ int readIclass(bool loop, bool verbose) { } } + uint8_t cardtype = get_mem_config(hdr); + PrintAndLogEx(SUCCESS, "%s", card_types[cardtype]); + + if (tagFound && !loop) { PrintAndLogEx(NORMAL, ""); DropField(); diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index 19b994d0c..53880d647 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -27,19 +27,6 @@ typedef struct iclass_prekey { uint8_t key[8]; } iclass_prekey_t; -typedef struct { - uint8_t key[8]; - bool use_raw; - bool use_elite; - bool use_credit_key; -} PACKED iclass_auth_req_t; - -typedef struct { - bool isOK; - uint8_t div_key[8]; - uint8_t mac[4]; -} PACKED iclass_auth_resp_t; - int CmdHFiClass(const char *Cmd); int readIclass(bool loop, bool verbose); diff --git a/common/cardhelper.c b/common/cardhelper.c index fbdaf2002..e34780896 100644 --- a/common/cardhelper.c +++ b/common/cardhelper.c @@ -19,6 +19,7 @@ #define CARD_INS_ENCRYPT 0x02 #define CARD_INS_DECODE 0x06 #define CARD_INS_NUMBLOCKS 0x07 +#define CARD_INS_PINSIZE 0x08 static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // look for CryptoHelper @@ -91,3 +92,13 @@ uint8_t GetNumberBlocksForUserId(uint8_t *src) { ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); return resp[8]; } + +// Call with block6 +uint8_t GetPinSize(uint8_t *src) { + int resp_len = 0; + uint8_t resp[254] = {0}; + uint8_t c[] = {0x96, CARD_INS_PINSIZE, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + memcpy(c + 5, src, 8); + ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); + return resp[8]; +} diff --git a/common/cardhelper.h b/common/cardhelper.h index eaf7ff38f..d55ae6701 100644 --- a/common/cardhelper.h +++ b/common/cardhelper.h @@ -19,4 +19,5 @@ bool Encrypt(uint8_t *src, uint8_t *dest); bool Decrypt(uint8_t *src, uint8_t *dest); void DecodeBlock6(uint8_t *src); uint8_t GetNumberBlocksForUserId(uint8_t *src); +uint8_t GetPinSize(uint8_t *src); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 3568bd50a..766e78c54 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -289,6 +289,23 @@ typedef struct { const char *value; } PACKED ecdsa_publickey_t; + +// iCLASS auth request data structure +typedef struct { + uint8_t key[8]; + bool use_raw; + bool use_elite; + bool use_credit_key; +} PACKED iclass_auth_req_t; + +// iCLASS auth response data structure +typedef struct { + bool isOK; + uint8_t div_key[8]; + uint8_t mac[4]; +} PACKED iclass_auth_resp_t; + + // For the bootloader #define CMD_DEVICE_INFO 0x0000 //#define CMD_SETUP_WRITE 0x0001