X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/902cb3c00b49535f0de9a3b6d5ba0c54260ccac1..c338502409b4bf3c90734429f00f0689ff5dd01d:/armsrc/iso14443a.c?ds=inline diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index d2ebb0c6..bbe748b0 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -898,13 +898,21 @@ static int GetIso14443aCommandFromReader(uint8_t *received, int *len, int maxLen } } } + static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, int correctionNeeded); +int EmSend4bitEx(uint8_t resp, int correctionNeeded); +int EmSend4bit(uint8_t resp); +int EmSendCmdExPar(uint8_t *resp, int respLen, int correctionNeeded, uint32_t par); +int EmSendCmdExPar(uint8_t *resp, int respLen, int correctionNeeded, uint32_t par); +int EmSendCmdEx(uint8_t *resp, int respLen, int correctionNeeded); +int EmSendCmd(uint8_t *resp, int respLen); +int EmSendCmdPar(uint8_t *resp, int respLen, uint32_t par); //----------------------------------------------------------------------------- // Main loop of simulated tag: receive commands from reader, decide what // response to send, and send it. //----------------------------------------------------------------------------- -void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) +void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) { // Enable and clear the trace tracing = TRUE; @@ -985,7 +993,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) uint8_t response6[] = { 0x03, 0x3B, 0x00, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS ComputeCrc14443(CRC_14443_A, response6, 3, &response6[3], &response6[4]); - uint8_t *resp; + uint8_t *resp = NULL; int respLen; // Longest possible response will be 16 bytes + 2 CRC = 18 bytes @@ -1024,7 +1032,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) // Response to a read request - not implemented atm uint8_t *resp4 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + (166*4)); - int resp4Len; +// int resp4Len; // Authenticate response - nonce uint8_t *resp5 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + (166*5)); @@ -1048,7 +1056,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) int cmdsRecvd = 0; uint8_t* respdata = NULL; int respsize = 0; - uint8_t nack = 0x04; +// uint8_t nack = 0x04; memset(receivedCmd, 0x44, RECV_CMD_SIZE); @@ -1077,7 +1085,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) // Strange answer is an example of rare message size (3 bits) CodeStrangeAnswerAsTag(); - memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax; + memcpy(resp4, ToSend, ToSendMax);// resp4Len = ToSendMax; // Authentication answer (random nonce) CodeIso14443aAsTag(response5, sizeof(response5)); @@ -1100,6 +1108,11 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) DbpString("button press"); break; } + + if (tracing) { + LogTrace(receivedCmd,len, 0, Uart.parityBits, TRUE); + } + // doob - added loads of debug strings so we can see what the reader is saying to us during the sim as hi14alist is not populated // Okay, look at the command now. lastorder = order; @@ -1128,12 +1141,15 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) respdata = response3a; respsize = sizeof(response3a); } else if(receivedCmd[0] == 0x30) { // Received a (plain) READ - resp = resp4; respLen = resp4Len; order = 4; // Do nothing +// resp = resp4; respLen = resp4Len; order = 4; // Do nothing +// respdata = &nack; +// respsize = sizeof(nack); // 4-bit answer + EmSendCmdEx(data+(4*receivedCmd[0]),16,false); Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]); - respdata = &nack; - respsize = sizeof(nack); // 4-bit answer + // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below + respLen = 0; } else if(receivedCmd[0] == 0x50) { // Received a HALT - DbpString("Reader requested we HALT!:"); +// DbpString("Reader requested we HALT!:"); // Do not respond resp = resp1; respLen = 0; order = 0; respdata = NULL; @@ -1147,16 +1163,19 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) respdata = response6; respsize = sizeof(response6); } else { - // Never seen this command before - Dbprintf("Received (len=%d): %02x %02x %02x %02x %02x %02x %02x %02x %02x", - len, - receivedCmd[0], receivedCmd[1], receivedCmd[2], - receivedCmd[3], receivedCmd[4], receivedCmd[5], - receivedCmd[6], receivedCmd[7], receivedCmd[8]); - // Do not respond - resp = resp1; respLen = 0; order = 0; - respdata = NULL; - respsize = 0; + if (order == 7 && len ==8) { + uint32_t nr = bytes_to_num(receivedCmd,4); + uint32_t ar = bytes_to_num(receivedCmd+4,4); + Dbprintf("Auth attempt {nr}{ar}: %08x %08x",nr,ar); + } else { + // Never seen this command before + Dbprintf("Received unknown command (len=%d):",len); + Dbhexdump(len,receivedCmd,false); + } + // Do not respond + resp = resp1; respLen = 0; order = 0; + respdata = NULL; + respsize = 0; } // Count number of wakeups received after a halt @@ -1183,7 +1202,6 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd) } if (tracing) { - LogTrace(receivedCmd,len, 0, Uart.parityBits, TRUE); if (respdata != NULL) { LogTrace(respdata,respsize, 0, SwapBits(GetParity(respdata,respsize),respsize), FALSE); } @@ -1244,68 +1262,9 @@ static void TransmitFor14443a(const uint8_t *cmd, int len, int *samples, int *wa } //----------------------------------------------------------------------------- -// Code a 7-bit command without parity bit -// This is especially for 0x26 and 0x52 (REQA and WUPA) -//----------------------------------------------------------------------------- -void ShortFrameFromReader(const uint8_t bt) -{ - int j; - int last; - uint8_t b; - - ToSendReset(); - - // Start of Communication (Seq. Z) - ToSend[++ToSendMax] = SEC_Z; - last = 0; - - b = bt; - for(j = 0; j < 7; j++) { - if(b & 1) { - // Sequence X - ToSend[++ToSendMax] = SEC_X; - last = 1; - } else { - if(last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - } - else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; - } - } - b >>= 1; - } - - // End of Communication - if(last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - } - else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; - } - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - - // Just to be sure! - ToSend[++ToSendMax] = SEC_Y; - ToSend[++ToSendMax] = SEC_Y; - ToSend[++ToSendMax] = SEC_Y; - - // Convert from last character reference to length - ToSendMax++; -} - -//----------------------------------------------------------------------------- -// Prepare reader command to send to FPGA -// +// Prepare reader command (in bits, support short frames) to send to FPGA //----------------------------------------------------------------------------- -void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) +void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, int bits, uint32_t dwParity) { int i, j; int last; @@ -1317,12 +1276,14 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) ToSend[++ToSendMax] = SEC_Z; last = 0; + size_t bytecount = nbytes(bits); // Generate send structure for the data bits - for (i = 0; i < len; i++) { + for (i = 0; i < bytecount; i++) { // Get the current byte to send b = cmd[i]; + size_t bitsleft = MIN((bits-(i*8)),8); - for (j = 0; j < 8; j++) { + for (j = 0; j < bitsleft; j++) { if (b & 1) { // Sequence X ToSend[++ToSendMax] = SEC_X; @@ -1340,19 +1301,22 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) b >>= 1; } - // Get the parity bit - if ((dwParity >> i) & 0x01) { - // Sequence X - ToSend[++ToSendMax] = SEC_X; - last = 1; - } else { - if (last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; + // Only transmit (last) parity bit if we transmitted a complete byte + if (j == 8) { + // Get the parity bit + if ((dwParity >> i) & 0x01) { + // Sequence X + ToSend[++ToSendMax] = SEC_X; + last = 1; } else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; + if (last == 0) { + // Sequence Z + ToSend[++ToSendMax] = SEC_Z; + } else { + // Sequence Y + ToSend[++ToSendMax] = SEC_Y; + last = 0; + } } } } @@ -1378,6 +1342,14 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) ToSendMax++; } +//----------------------------------------------------------------------------- +// Prepare reader command to send to FPGA +//----------------------------------------------------------------------------- +void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) +{ + CodeIso14443aBitsAsReaderPar(cmd,len*8,dwParity); +} + //----------------------------------------------------------------------------- // Wait for commands from reader // Stop when button is pressed (return 1) or field was gone (return 2) @@ -1575,43 +1547,33 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, int maxLen, int } } -void ReaderTransmitShort(const uint8_t* bt) +void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par) { int wait = 0; int samples = 0; - - ShortFrameFromReader(*bt); - - // Select the card - TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); - - // Store reader command in buffer - if (tracing) LogTrace(bt,1,0,GetParity(bt,1),TRUE); -} - -void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par) -{ - int wait = 0; - int samples = 0; - + // This is tied to other size changes // uint8_t* frame_addr = ((uint8_t*)BigBuf) + 2024; - CodeIso14443aAsReaderPar(frame,len,par); - + CodeIso14443aBitsAsReaderPar(frame,bits,par); + // Select the card TransmitFor14443a(ToSend, ToSendMax, &samples, &wait); if(trigger) LED_A_ON(); - + // Store reader command in buffer - if (tracing) LogTrace(frame,len,0,par,TRUE); + if (tracing) LogTrace(frame,nbytes(bits),0,par,TRUE); } +void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par) +{ + ReaderTransmitBitsPar(frame,len*8,par); +} void ReaderTransmit(uint8_t* frame, int len) { // Generate parity and redirect - ReaderTransmitPar(frame,len,GetParity(frame,len)); + ReaderTransmitBitsPar(frame,len*8,GetParity(frame,len)); } int ReaderReceive(uint8_t* receivedAnswer) @@ -1636,86 +1598,107 @@ int ReaderReceivePar(uint8_t* receivedAnswer, uint32_t * parptr) /* performs iso14443a anticolision procedure * fills the uid pointer unless NULL * fills resp_data unless NULL */ -int iso14443a_select_card(uint8_t * uid_ptr, iso14a_card_select_t * resp_data, uint32_t * cuid_ptr) { - uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP - uint8_t sel_all[] = { 0x93,0x20 }; - uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 - - uint8_t* resp = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes - - uint8_t sak = 0x04; // cascade uid - int cascade_level = 0; - - int len; - - // clear uid - memset(uid_ptr, 0, 12); - - // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitShort(wupa); - // Receive the ATQA - if(!ReaderReceive(resp)) return 0; +int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { + uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP + uint8_t sel_all[] = { 0x93,0x20 }; + uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 + uint8_t* resp = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes + byte_t uid_resp[4]; + size_t uid_resp_len; + + uint8_t sak = 0x04; // cascade uid + int cascade_level = 0; + int len; + + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field + ReaderTransmitBitsPar(wupa,7,0); + // Receive the ATQA + if(!ReaderReceive(resp)) return 0; // Dbprintf("atqa: %02x %02x",resp[0],resp[1]); - if(resp_data) - memcpy(resp_data->atqa, resp, 2); + if(p_hi14a_card) { + memcpy(p_hi14a_card->atqa, resp, 2); + p_hi14a_card->uidlen = 0; + memset(p_hi14a_card->uid,0,10); + } - // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in - // which case we need to make a cascade 2 request and select - this is a long UID - // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. - for(; sak & 0x04; cascade_level++) - { - // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) - sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; - - // SELECT_ALL - ReaderTransmit(sel_all,sizeof(sel_all)); - if (!ReaderReceive(resp)) return 0; -// Dbprintf("uid: %02x %02x %02x %02x",resp[0],resp[1],resp[2],resp[3]); + // clear uid + if (uid_ptr) { + memset(uid_ptr,0,8); + } - if(uid_ptr) memcpy(uid_ptr + cascade_level*4, resp, 4); - + // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in + // which case we need to make a cascade 2 request and select - this is a long UID + // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. + for(; sak & 0x04; cascade_level++) { + // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) + sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; + + // SELECT_ALL + ReaderTransmit(sel_all,sizeof(sel_all)); + if (!ReaderReceive(resp)) return 0; + + // First backup the current uid + memcpy(uid_resp,resp,4); + uid_resp_len = 4; + // Dbprintf("uid: %02x %02x %02x %02x",uid_resp[0],uid_resp[1],uid_resp[2],uid_resp[3]); + // calculate crypto UID - if(cuid_ptr) *cuid_ptr = bytes_to_num(resp, 4); + if(cuid_ptr) { + *cuid_ptr = bytes_to_num(uid_resp, 4); + } - // Construct SELECT UID command + // Construct SELECT UID command memcpy(sel_uid+2,resp,5); - AppendCrc14443a(sel_uid,7); - ReaderTransmit(sel_uid,sizeof(sel_uid)); + AppendCrc14443a(sel_uid,7); + ReaderTransmit(sel_uid,sizeof(sel_uid)); + + // Receive the SAK + if (!ReaderReceive(resp)) return 0; + sak = resp[0]; + + // Test if more parts of the uid are comming + if ((sak & 0x04) && uid_resp[0] == 0x88) { + // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: + // http://www.nxp.com/documents/application_note/AN10927.pdf + memcpy(uid_resp, uid_resp + 1, 3); + uid_resp_len = 3; + } + + if(uid_ptr) { + memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len); + } + + if(p_hi14a_card) { + memcpy(p_hi14a_card->uid + (cascade_level*3), uid_resp, uid_resp_len); + p_hi14a_card->uidlen += uid_resp_len; + } + } - // Receive the SAK - if (!ReaderReceive(resp)) return 0; - sak = resp[0]; - } - if(resp_data) { - resp_data->sak = sak; - resp_data->ats_len = 0; - } - //-- this byte not UID, it CT. http://www.nxp.com/documents/application_note/AN10927.pdf page 3 - if (uid_ptr[0] == 0x88) { - memcpy(uid_ptr, uid_ptr + 1, 7); - uid_ptr[7] = 0; - } + if(p_hi14a_card) { + p_hi14a_card->sak = sak; + p_hi14a_card->ats_len = 0; + } - if( (sak & 0x20) == 0) - return 2; // non iso14443a compliant tag + if( (sak & 0x20) == 0) { + return 2; // non iso14443a compliant tag + } - // Request for answer to select - if(resp_data) { // JCOP cards - if reader sent RATS then there is no MIFARE session at all!!! - AppendCrc14443a(rats, 2); - ReaderTransmit(rats, sizeof(rats)); - - if (!(len = ReaderReceive(resp))) return 0; - - memcpy(resp_data->ats, resp, sizeof(resp_data->ats)); - resp_data->ats_len = len; - } - - // reset the PCB block number - iso14_pcb_blocknum = 0; + // Request for answer to select + AppendCrc14443a(rats, 2); + ReaderTransmit(rats, sizeof(rats)); + + if (!(len = ReaderReceive(resp))) return 0; + + if(p_hi14a_card) { + memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); + p_hi14a_card->ats_len = len; + } - return 1; + // reset the PCB block number + iso14_pcb_blocknum = 0; + return 1; } void iso14443a_setup() { @@ -1774,18 +1757,20 @@ void ReaderIso14443a(UsbCommand * c) iso14a_command_t param = c->arg[0]; uint8_t * cmd = c->d.asBytes; size_t len = c->arg[1]; - uint32_t arg0; - byte_t buf[48]; + uint32_t arg0 = 0; + byte_t buf[USB_CMD_DATA_SIZE]; iso14a_clear_trace(); iso14a_set_tracing(true); - if(param & ISO14A_REQUEST_TRIGGER) iso14a_set_trigger(1); + if(param & ISO14A_REQUEST_TRIGGER) { + iso14a_set_trigger(1); + } if(param & ISO14A_CONNECT) { iso14443a_setup(); - arg0 = iso14443a_select_card(buf, (iso14a_card_select_t *)(buf+12), NULL); - cmd_send(CMD_ACK,arg0,0,0,buf,48); + arg0 = iso14443a_select_card(NULL,(iso14a_card_select_t*)buf,NULL); + cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(iso14a_card_select_t)); // UsbSendPacket((void *)ack, sizeof(UsbCommand)); } @@ -1799,7 +1784,7 @@ void ReaderIso14443a(UsbCommand * c) if(param & ISO14A_APDU) { arg0 = iso14_apdu(cmd, len, buf); - cmd_send(CMD_ACK,arg0,0,0,buf,48); + cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf)); // UsbSendPacket((void *)ack, sizeof(UsbCommand)); } @@ -1811,13 +1796,16 @@ void ReaderIso14443a(UsbCommand * c) ReaderTransmit(cmd,len); arg0 = ReaderReceive(buf); // UsbSendPacket((void *)ack, sizeof(UsbCommand)); - cmd_send(CMD_ACK,arg0,0,0,buf,48); + cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf)); } - if(param & ISO14A_REQUEST_TRIGGER) iso14a_set_trigger(0); + if(param & ISO14A_REQUEST_TRIGGER) { + iso14a_set_trigger(0); + } - if(param & ISO14A_NO_DISCONNECT) + if(param & ISO14A_NO_DISCONNECT) { return; + } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); @@ -2527,4 +2515,4 @@ done: Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.byteCnt=%x Uart.byteCntMax=%x", maxDataLen, Uart.state, Uart.byteCnt, Uart.byteCntMax); LEDsoff(); -} \ No newline at end of file +}