From: pwpiwi Date: Wed, 24 Jun 2015 05:47:45 +0000 (+0200) Subject: Merge pull request #109 from pwpiwi/image_shrink X-Git-Tag: v2.2.0~10 X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/2da2e9283771f20e4fb809709ea1c97c0636e455?hp=97a0f5f4aa89ddd940f9fc15779534ebb9ac630a Merge pull request #109 from pwpiwi/image_shrink Compress FPGA configs and initialized data --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 85e7f915..b416e26a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,20 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [Unreleased][unreleased] + +### Added +- Add PACE replay functionality (frederikmoellers) + +### Fixed +- t55xx write timing (marshmellow) + + +## [2.1.0][2015-06-23] + ### Changed +- Added ultralight/ntag tag type detection to `hf 14a read` (marshmellow) +- Improved ultralight dump command to auto detect tag type, take authentication, and dump full memory (or subset specified) of known tag types (iceman1001 / marshmellow) +- Combined ultralight read/write commands and added authentication (iceman1001) - Improved LF manchester and biphase demodulation and ask clock detection especially for reads with heavy clipping. (marshmellow) - Iclass read, `hf iclass read` now also reads tag config and prints configuration. (holiman) - *bootrom* needs to be flashed, due to new address boundaries between os and fpga, after a size optimization (piwi) @@ -11,8 +24,12 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Fixed - Fixed EM4x50 read/demod of the tags broadcasted memory blocks. 'lf em4x em4x50read' (not page read) (marshmellow) - Fixed issue #19, problems with LF T55xx commands (iceman1001, marshmellow) +- Fixed various problems with iso14443b, issue #103 (piwi, marshmellow) ### Added +- Added `hf search` - currently tests for 14443a tags, iclass tags, and 15693 tags (marshmellow) +- Added `hf mfu info` Ultralight/NTAG info command - reads tag configuration and info, allows authentication if needed (iceman1001, marshmellow) +- Added Mifare Ultralight C and Ultralight EV1/NTAG authentication. (iceman1001) - Added changelog ## [2.0.0] - 2015-03-25 diff --git a/COMPILING.txt b/COMPILING.txt index c894f0ff..1cc34a0f 100644 --- a/COMPILING.txt +++ b/COMPILING.txt @@ -81,7 +81,31 @@ Download the ProxSpace environment archive and extract it to C:\ = Mac OS X = ============ -macport stuff should do ;) +Tested on OSX 10.10 Yosemite + +1 - Install Xcode and Xcode Command Line Tools + +2 - Install Homebrew and dependencies + brew install readline + brew instal libusb + +3 - Download DevKitARM for OSX + http://sourceforge.net/projects/devkitpro/files/devkitARM/devkitARM_r44/ + Unpack devkitARM_r44-osx.tar.bz2 to proxmark3 directory. + +4 - Edit proxmark3/client/Makefile adding path to readline + + LDLIBS = -L/usr/local/Cellar/readline/6.3.8/lib/ -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lm + CFLAGS = -std=c99 -I/usr/local/Cellar/readline/6.3.8/include/ -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 + + Replace path /usr/local/Cellar/readline/6.3.8 with your actuall readline path. See homebrew manuals. + +5 - Set Environment + + export DEVKITPRO=$HOME/proxmark3/ + export DEVKITARM=$DEVKITPRO/devkitARM + export PATH=${PATH}:${DEVKITARM}/bin + ============ = Linux = diff --git a/armsrc/Makefile b/armsrc/Makefile index 78d67934..f21f106c 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -18,7 +18,7 @@ APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ SRC_LF = lfops.c hitag2.c lfsampling.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c -SRC_ISO14443b = iso14443.c +SRC_ISO14443b = iso14443b.c SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c diff --git a/armsrc/aes.c b/armsrc/aes.c index 3df006bb..a199d04b 100644 --- a/armsrc/aes.c +++ b/armsrc/aes.c @@ -1,4 +1,3 @@ -#include "stdio.h" #include "aes.h" static const unsigned int Te0[256] = { @@ -1138,6 +1137,9 @@ int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsig ////////////////////////////////////////////////////////////////////////////// #ifndef EMBEDDED + +#include + int main() { AesCtx ctx; diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 26399046..0cbfa249 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -250,55 +250,6 @@ void MeasureAntennaTuningHf(void) } -void SimulateTagHfListen(void) -{ - // ToDo: historically this used the free buffer, which was 2744 Bytes long. - // There might be a better size to be defined: - #define HF_14B_SNOOP_BUFFER_SIZE 2744 - uint8_t *dest = BigBuf_malloc(HF_14B_SNOOP_BUFFER_SIZE); - uint8_t v = 0; - int i; - int p = 0; - - // We're using this mode just so that I can test it out; the simulated - // tag mode would work just as well and be simpler. - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); - - // We need to listen to the high-frequency, peak-detected path. - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - FpgaSetupSsc(); - - i = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xff; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint8_t r = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - v <<= 1; - if(r & 1) { - v |= 1; - } - p++; - - if(p >= 8) { - dest[i] = v; - v = 0; - p = 0; - i++; - - if(i >= HF_14B_SNOOP_BUFFER_SIZE) { - break; - } - } - } - } - DbpString("simulate tag (now type bitsamples)"); -} - void ReadMem(int addr) { const uint8_t *data = ((uint8_t *)addr); @@ -787,20 +738,17 @@ void UsbPacketReceived(uint8_t *packet, int len) #endif #ifdef WITH_ISO14443b - case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443: - AcquireRawAdcSamplesIso14443(c->arg[0]); - break; case CMD_READ_SRI512_TAG: - ReadSTMemoryIso14443(0x0F); + ReadSTMemoryIso14443b(0x0F); break; case CMD_READ_SRIX4K_TAG: - ReadSTMemoryIso14443(0x7F); + ReadSTMemoryIso14443b(0x7F); break; - case CMD_SNOOP_ISO_14443: - SnoopIso14443(); + case CMD_SNOOP_ISO_14443B: + SnoopIso14443b(); break; - case CMD_SIMULATE_TAG_ISO_14443: - SimulateIso14443Tag(); + case CMD_SIMULATE_TAG_ISO_14443B: + SimulateIso14443bTag(); break; case CMD_ISO_14443B_COMMAND: SendRawCommand14443B(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); @@ -821,6 +769,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_EPA_PACE_COLLECT_NONCE: EPA_PACE_Collect_Nonce(c); break; + case CMD_EPA_PACE_REPLAY: + EPA_PACE_Replay(c); + break; case CMD_READER_MIFARE: ReaderMifare(c->arg[0]); @@ -846,11 +797,11 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFARE_WRITEBL: MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; - case CMD_MIFAREU_WRITEBL_COMPAT: - MifareUWriteBlock(c->arg[0], c->d.asBytes); - break; + //case CMD_MIFAREU_WRITEBL_COMPAT: + //MifareUWriteBlockCompat(c->arg[0], c->d.asBytes); + //break; case CMD_MIFAREU_WRITEBL: - MifareUWriteBlock_Special(c->arg[0], c->d.asBytes); + MifareUWriteBlock(c->arg[0], c->arg[1], c->d.asBytes); break; case CMD_MIFARE_NESTED: MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); @@ -916,10 +867,6 @@ void UsbPacketReceived(uint8_t *packet, int len) break; #endif - case CMD_SIMULATE_TAG_HF_LISTEN: - SimulateTagHfListen(); - break; - case CMD_BUFF_CLEAR: BigBuf_Clear(); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 98be05a3..bb094b33 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -88,10 +88,10 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode); void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode); /// iso14443.h -void SimulateIso14443Tag(void); -void AcquireRawAdcSamplesIso14443(uint32_t parameter); -void ReadSTMemoryIso14443(uint32_t); -void RAMFUNC SnoopIso14443(void); +void SimulateIso14443bTag(void); +void AcquireRawAdcSamplesIso14443b(uint32_t parameter); +void ReadSTMemoryIso14443b(uint32_t); +void RAMFUNC SnoopIso14443b(void); void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); /// iso14443a.h @@ -107,6 +107,7 @@ void RAMFUNC SniffMifare(uint8_t param); /// epa.h void EPA_PACE_Collect_Nonce(UsbCommand * c); +void EPA_PACE_Replay(UsbCommand *c); // mifarecmd.h void ReaderMifare(bool first_try); @@ -117,8 +118,8 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *datain); void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); -void MifareUWriteBlock(uint8_t arg0,uint8_t *datain); -void MifareUWriteBlock_Special(uint8_t arg0,uint8_t *datain); +//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); +void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); diff --git a/armsrc/epa.c b/armsrc/epa.c index 0006d59d..6bd8692e 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -5,7 +5,7 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// Routines to support the German eletronic "Personalausweis" (ID card) +// Routines to support the German electronic "Personalausweis" (ID card) // Note that the functions which do not implement USB commands do NOT initialize // the card (with iso14443a_select_card etc.). If You want to use these // functions, You need to do the setup before calling them! @@ -74,6 +74,32 @@ static const uint8_t oid_pace_start[] = { 0x04 // id-PACE }; +// APDUs for replaying: +// MSE: Set AT (initiate PACE) +static uint8_t apdu_replay_mse_set_at_pace[41]; +// General Authenticate (Get Nonce) +static uint8_t apdu_replay_general_authenticate_pace_get_nonce[8]; +// General Authenticate (Map Nonce) +static uint8_t apdu_replay_general_authenticate_pace_map_nonce[75]; +// General Authenticate (Mutual Authenticate) +static uint8_t apdu_replay_general_authenticate_pace_mutual_authenticate[75]; +// General Authenticate (Perform Key Agreement) +static uint8_t apdu_replay_general_authenticate_pace_perform_key_agreement[18]; +// pointers to the APDUs (for iterations) +static struct { + uint8_t len; + uint8_t *data; +} const apdus_replay[] = { + {sizeof(apdu_replay_mse_set_at_pace), apdu_replay_mse_set_at_pace}, + {sizeof(apdu_replay_general_authenticate_pace_get_nonce), apdu_replay_general_authenticate_pace_get_nonce}, + {sizeof(apdu_replay_general_authenticate_pace_map_nonce), apdu_replay_general_authenticate_pace_map_nonce}, + {sizeof(apdu_replay_general_authenticate_pace_mutual_authenticate), apdu_replay_general_authenticate_pace_mutual_authenticate}, + {sizeof(apdu_replay_general_authenticate_pace_perform_key_agreement), apdu_replay_general_authenticate_pace_perform_key_agreement} +}; + +// lengths of the replay APDUs +static uint8_t apdu_lengths_replay[5]; + //----------------------------------------------------------------------------- // Closes the communication channel and turns off the field //----------------------------------------------------------------------------- @@ -101,7 +127,7 @@ size_t EPA_Parse_CardAccess(uint8_t *data, pace_version_info_t *pace_info) { size_t index = 0; - + while (index <= length - 2) { // determine type of element // SET or SEQUENCE @@ -158,7 +184,7 @@ size_t EPA_Parse_CardAccess(uint8_t *data, index += 2 + data[index + 1]; } } - + // TODO: We should check whether we reached the end in error, but for that // we need a better parser (e.g. with states like IN_SET or IN_PACE_INFO) return 0; @@ -176,7 +202,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) // we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame) uint8_t response_apdu[262]; int rapdu_length = 0; - + // select the file EF.CardAccess rapdu_length = iso14_apdu((uint8_t *)apdu_select_binary_cardaccess, sizeof(apdu_select_binary_cardaccess), @@ -188,7 +214,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) Dbprintf("epa - no select cardaccess"); return -1; } - + // read the file rapdu_length = iso14_apdu((uint8_t *)apdu_read_binary, sizeof(apdu_read_binary), @@ -200,7 +226,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) Dbprintf("epa - no read cardaccess"); return -1; } - + // copy the content into the buffer // length of data available: apdu_length - 4 (ISO frame) - 2 (SW) size_t to_copy = rapdu_length - 6; @@ -215,16 +241,11 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) //----------------------------------------------------------------------------- static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) { -// // step in which the failure occured -// ack->arg[0] = step; -// // last return code -// ack->arg[1] = func_return; - // power down the field EPA_Finish(); - + // send the USB packet - cmd_send(CMD_ACK,step,func_return,0,0,0); + cmd_send(CMD_ACK,step,func_return,0,0,0); } //----------------------------------------------------------------------------- @@ -246,10 +267,6 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) // return value of a function int func_return = 0; -// // initialize ack with 0s -// memset(ack->arg, 0, 12); -// memset(ack->d.asBytes, 0, 48); - // set up communication func_return = EPA_Setup(); if (func_return != 0) { @@ -277,11 +294,11 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) EPA_PACE_Collect_Nonce_Abort(3, func_return); return; } - + // initiate the PACE protocol // use the CAN for the password since that doesn't change func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2); - + // now get the nonce uint8_t nonce[256] = {0}; uint8_t requested_size = (uint8_t)c->arg[0]; @@ -292,14 +309,12 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) EPA_PACE_Collect_Nonce_Abort(4, func_return); return; } - - // all done, return + + // all done, return EPA_Finish(); - + // save received information -// ack->arg[1] = func_return; -// memcpy(ack->d.asBytes, nonce, func_return); - cmd_send(CMD_ACK,0,func_return,0,nonce,func_return); + cmd_send(CMD_ACK,0,func_return,0,nonce,func_return); } //----------------------------------------------------------------------------- @@ -320,7 +335,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) sizeof(apdu_general_authenticate_pace_get_nonce)); // append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU apdu[sizeof(apdu_general_authenticate_pace_get_nonce)] = requested_length + 4; - + // send it uint8_t response_apdu[262]; int send_return = iso14_apdu(apdu, @@ -333,7 +348,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) { return -1; } - + // if there is no nonce in the RAPDU, return here if (send_return < 10) { @@ -348,7 +363,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) } // copy the nonce memcpy(nonce, response_apdu + 6, nonce_length); - + return nonce_length; } @@ -407,13 +422,79 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) return 0; } +//----------------------------------------------------------------------------- +// Perform the PACE protocol by replaying given APDUs +//----------------------------------------------------------------------------- +void EPA_PACE_Replay(UsbCommand *c) +{ + uint32_t timings[sizeof(apdu_lengths_replay) / sizeof(apdu_lengths_replay[0])] = {0}; + + // if an APDU has been passed, save it + if (c->arg[0] != 0) { + // make sure it's not too big + if(c->arg[2] > apdus_replay[c->arg[0] - 1].len) + { + cmd_send(CMD_ACK, 1, 0, 0, NULL, 0); + } + memcpy(apdus_replay[c->arg[0] - 1].data + c->arg[1], + c->d.asBytes, + c->arg[2]); + // save/update APDU length + if (c->arg[1] == 0) { + apdu_lengths_replay[c->arg[0] - 1] = c->arg[2]; + } else { + apdu_lengths_replay[c->arg[0] - 1] += c->arg[2]; + } + cmd_send(CMD_ACK, 0, 0, 0, NULL, 0); + return; + } + + // return value of a function + int func_return; + + // set up communication + func_return = EPA_Setup(); + if (func_return != 0) { + EPA_Finish(); + cmd_send(CMD_ACK, 2, func_return, 0, NULL, 0); + return; + } + + // increase the timeout (at least some cards really do need this!)///////////// + // iso14a_set_timeout(0x0003FFFF); + + // response APDU + uint8_t response_apdu[300] = {0}; + + // now replay the data and measure the timings + for (int i = 0; i < sizeof(apdu_lengths_replay); i++) { + StartCountUS(); + func_return = iso14_apdu(apdus_replay[i].data, + apdu_lengths_replay[i], + response_apdu); + timings[i] = GetCountUS(); + // every step but the last one should succeed + if (i < sizeof(apdu_lengths_replay) - 1 + && (func_return < 6 + || response_apdu[func_return - 4] != 0x90 + || response_apdu[func_return - 3] != 0x00)) + { + EPA_Finish(); + cmd_send(CMD_ACK, 3 + i, func_return, 0, timings, 20); + return; + } + } + EPA_Finish(); + cmd_send(CMD_ACK,0,0,0,timings,20); + return; +} + //----------------------------------------------------------------------------- // Set up a communication channel (Card Select, PPS) // Returns 0 on success or a non-zero error code on failure //----------------------------------------------------------------------------- int EPA_Setup() { - int return_code = 0; uint8_t uid[10]; uint8_t pps_response[3]; @@ -422,20 +503,16 @@ int EPA_Setup() // power up the field iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - // select the card return_code = iso14443a_select_card(uid, &card_select_info, NULL); if (return_code != 1) { - Dbprintf("Epa: Can't select card"); return 1; } - // send the PPS request ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); return_code = ReaderReceive(pps_response, pps_response_par); if (return_code != 3 || pps_response[0] != 0xD0) { return return_code == 0 ? 2 : return_code; } - return 0; -} \ No newline at end of file +} diff --git a/armsrc/epa.h b/armsrc/epa.h index 730652b7..0c580205 100644 --- a/armsrc/epa.h +++ b/armsrc/epa.h @@ -19,7 +19,7 @@ typedef struct { uint8_t parameter_id; } pace_version_info_t; -// note: EPA_PACE_GetNonce is declared in apps.h +// note: EPA_PACE_Collect_Nonce is declared in apps.h // general functions void EPA_Finish(); @@ -33,4 +33,4 @@ int EPA_Setup(); int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password); int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce); -#endif /* __EPA_H */ \ No newline at end of file +#endif /* __EPA_H */ diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c deleted file mode 100644 index c7f49f14..00000000 --- a/armsrc/iso14443.c +++ /dev/null @@ -1,1250 +0,0 @@ -//----------------------------------------------------------------------------- -// Jonathan Westhues, split Nov 2006 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to support ISO 14443. This includes both the reader software and -// the `fake tag' modes. At the moment only the Type B modulation is -// supported. -//----------------------------------------------------------------------------- - -#include "proxmark3.h" -#include "apps.h" -#include "util.h" -#include "string.h" - -#include "iso14443crc.h" - -//static void GetSamplesFor14443(int weTx, int n); - -/*#define DEMOD_TRACE_SIZE 4096 -#define READER_TAG_BUFFER_SIZE 2048 -#define TAG_READER_BUFFER_SIZE 2048 -#define DEMOD_DMA_BUFFER_SIZE 1024 -*/ -//============================================================================= -// An ISO 14443 Type B tag. We listen for commands from the reader, using -// a UART kind of thing that's implemented in software. When we get a -// frame (i.e., a group of bytes between SOF and EOF), we check the CRC. -// If it's good, then we can do something appropriate with it, and send -// a response. -//============================================================================= - -//----------------------------------------------------------------------------- -// Code up a string of octets at layer 2 (including CRC, we don't generate -// that here) so that they can be transmitted to the reader. Doesn't transmit -// them yet, just leaves them ready to send in ToSend[]. -//----------------------------------------------------------------------------- -static void CodeIso14443bAsTag(const uint8_t *cmd, int len) -{ - int i; - - ToSendReset(); - - // Transmit a burst of ones, as the initial thing that lets the - // reader get phase sync. This (TR1) must be > 80/fs, per spec, - // but tag that I've tried (a Paypass) exceeds that by a fair bit, - // so I will too. - for(i = 0; i < 20; i++) { - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - // Send SOF. - for(i = 0; i < 10; i++) { - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - } - for(i = 0; i < 2; i++) { - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - for(i = 0; i < len; i++) { - int j; - uint8_t b = cmd[i]; - - // Start bit - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - - // Data bits - for(j = 0; j < 8; j++) { - if(b & 1) { - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } else { - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - } - b >>= 1; - } - - // Stop bit - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - // Send SOF. - for(i = 0; i < 10; i++) { - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - } - for(i = 0; i < 10; i++) { - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - // Convert from last byte pos to length - ToSendMax++; - - // Add a few more for slop - ToSendMax += 2; -} - -//----------------------------------------------------------------------------- -// The software UART that receives commands from the reader, and its state -// variables. -//----------------------------------------------------------------------------- -static struct { - enum { - STATE_UNSYNCD, - STATE_GOT_FALLING_EDGE_OF_SOF, - STATE_AWAITING_START_BIT, - STATE_RECEIVING_DATA, - STATE_ERROR_WAIT - } state; - uint16_t shiftReg; - int bitCnt; - int byteCnt; - int byteCntMax; - int posCnt; - uint8_t *output; -} Uart; - -/* Receive & handle a bit coming from the reader. - * - * LED handling: - * LED A -> ON once we have received the SOF and are expecting the rest. - * LED A -> OFF once we have received EOF or are in error state or unsynced - * - * Returns: true if we received a EOF - * false if we are still waiting for some more - */ -static int Handle14443UartBit(int bit) -{ - switch(Uart.state) { - case STATE_UNSYNCD: - LED_A_OFF(); - if(!bit) { - // we went low, so this could be the beginning - // of an SOF - Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF; - Uart.posCnt = 0; - Uart.bitCnt = 0; - } - break; - - case STATE_GOT_FALLING_EDGE_OF_SOF: - Uart.posCnt++; - if(Uart.posCnt == 2) { - if(bit) { - if(Uart.bitCnt >= 10) { - // we've seen enough consecutive - // zeros that it's a valid SOF - Uart.posCnt = 0; - Uart.byteCnt = 0; - Uart.state = STATE_AWAITING_START_BIT; - LED_A_ON(); // Indicate we got a valid SOF - } else { - // didn't stay down long enough - // before going high, error - Uart.state = STATE_ERROR_WAIT; - } - } else { - // do nothing, keep waiting - } - Uart.bitCnt++; - } - if(Uart.posCnt >= 4) Uart.posCnt = 0; - if(Uart.bitCnt > 14) { - // Give up if we see too many zeros without - // a one, too. - Uart.state = STATE_ERROR_WAIT; - } - break; - - case STATE_AWAITING_START_BIT: - Uart.posCnt++; - if(bit) { - if(Uart.posCnt > 25) { - // stayed high for too long between - // characters, error - Uart.state = STATE_ERROR_WAIT; - } - } else { - // falling edge, this starts the data byte - Uart.posCnt = 0; - Uart.bitCnt = 0; - Uart.shiftReg = 0; - Uart.state = STATE_RECEIVING_DATA; - LED_A_ON(); // Indicate we're receiving - } - break; - - case STATE_RECEIVING_DATA: - Uart.posCnt++; - if(Uart.posCnt == 2) { - // time to sample a bit - Uart.shiftReg >>= 1; - if(bit) { - Uart.shiftReg |= 0x200; - } - Uart.bitCnt++; - } - if(Uart.posCnt >= 4) { - Uart.posCnt = 0; - } - if(Uart.bitCnt == 10) { - if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001)) - { - // this is a data byte, with correct - // start and stop bits - Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff; - Uart.byteCnt++; - - if(Uart.byteCnt >= Uart.byteCntMax) { - // Buffer overflowed, give up - Uart.posCnt = 0; - Uart.state = STATE_ERROR_WAIT; - } else { - // so get the next byte now - Uart.posCnt = 0; - Uart.state = STATE_AWAITING_START_BIT; - } - } else if(Uart.shiftReg == 0x000) { - // this is an EOF byte - LED_A_OFF(); // Finished receiving - return TRUE; - } else { - // this is an error - Uart.posCnt = 0; - Uart.state = STATE_ERROR_WAIT; - } - } - break; - - case STATE_ERROR_WAIT: - // We're all screwed up, so wait a little while - // for whatever went wrong to finish, and then - // start over. - Uart.posCnt++; - if(Uart.posCnt > 10) { - Uart.state = STATE_UNSYNCD; - } - break; - - default: - Uart.state = STATE_UNSYNCD; - break; - } - - // This row make the error blew circular buffer in hf 14b snoop - //if (Uart.state == STATE_ERROR_WAIT) LED_A_OFF(); // Error - - return FALSE; -} - -//----------------------------------------------------------------------------- -// Receive a command (from the reader to us, where we are the simulated tag), -// and store it in the given buffer, up to the given maximum length. Keeps -// spinning, waiting for a well-framed command, until either we get one -// (returns TRUE) or someone presses the pushbutton on the board (FALSE). -// -// Assume that we're called with the SSC (to the FPGA) and ADC path set -// correctly. -//----------------------------------------------------------------------------- -static int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen) -{ - uint8_t mask; - int i, bit; - - // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen - // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); - - - // Now run a `software UART' on the stream of incoming samples. - Uart.output = received; - Uart.byteCntMax = maxLen; - Uart.state = STATE_UNSYNCD; - - for(;;) { - WDT_HIT(); - - if(BUTTON_PRESS()) return FALSE; - - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - mask = 0x80; - for(i = 0; i < 8; i++, mask >>= 1) { - bit = (b & mask); - if(Handle14443UartBit(bit)) { - *len = Uart.byteCnt; - return TRUE; - } - } - } - } -} - -//----------------------------------------------------------------------------- -// Main loop of simulated tag: receive commands from reader, decide what -// response to send, and send it. -//----------------------------------------------------------------------------- -void SimulateIso14443Tag(void) -{ - static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; - static const uint8_t response1[] = { - 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22, - 0x00, 0x21, 0x85, 0x5e, 0xd7 - }; - - uint8_t *resp; - int respLen; - - uint8_t *resp1 = BigBuf_get_addr() + 800; - int resp1Len; - - uint8_t *receivedCmd = BigBuf_get_addr(); - int len; - - int i; - - int cmdsRecvd = 0; - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - memset(receivedCmd, 0x44, 400); - - CodeIso14443bAsTag(response1, sizeof(response1)); - memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax; - - // We need to listen to the high-frequency, peak-detected path. - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - cmdsRecvd = 0; - - for(;;) { - uint8_t b1, b2; - - if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) { - Dbprintf("button pressed, received %d commands", cmdsRecvd); - break; - } - - // Good, look at the command now. - - if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) { - resp = resp1; respLen = resp1Len; - } else { - Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd); - // And print whether the CRC fails, just for good measure - ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2); - if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) { - // Not so good, try again. - DbpString("+++CRC fail"); - } else { - DbpString("CRC passes"); - } - break; - } - - memset(receivedCmd, 0x44, 32); - - cmdsRecvd++; - - if(cmdsRecvd > 0x30) { - DbpString("many commands later..."); - break; - } - - if(respLen <= 0) continue; - - // Modulate BPSK - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); - AT91C_BASE_SSC->SSC_THR = 0xff; - FpgaSetupSsc(); - - // Transmit the response. - i = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - uint8_t b = resp[i]; - - AT91C_BASE_SSC->SSC_THR = b; - - i++; - if(i > respLen) { - break; - } - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - (void)b; - } - } - } -} - -//============================================================================= -// An ISO 14443 Type B reader. We take layer two commands, code them -// appropriately, and then send them to the tag. We then listen for the -// tag's response, which we leave in the buffer to be demodulated on the -// PC side. -//============================================================================= - -static struct { - enum { - DEMOD_UNSYNCD, - DEMOD_PHASE_REF_TRAINING, - DEMOD_AWAITING_FALLING_EDGE_OF_SOF, - DEMOD_GOT_FALLING_EDGE_OF_SOF, - DEMOD_AWAITING_START_BIT, - DEMOD_RECEIVING_DATA, - DEMOD_ERROR_WAIT - } state; - int bitCount; - int posCount; - int thisBit; - int metric; - int metricN; - uint16_t shiftReg; - uint8_t *output; - int len; - int sumI; - int sumQ; -} Demod; - -/* - * Handles reception of a bit from the tag - * - * LED handling: - * LED C -> ON once we have received the SOF and are expecting the rest. - * LED C -> OFF once we have received EOF or are unsynced - * - * Returns: true if we received a EOF - * false if we are still waiting for some more - * - */ -static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) -{ - int v; - - // The soft decision on the bit uses an estimate of just the - // quadrant of the reference angle, not the exact angle. -#define MAKE_SOFT_DECISION() { \ - if(Demod.sumI > 0) { \ - v = ci; \ - } else { \ - v = -ci; \ - } \ - if(Demod.sumQ > 0) { \ - v += cq; \ - } else { \ - v -= cq; \ - } \ - } - - switch(Demod.state) { - case DEMOD_UNSYNCD: - v = ci; - if(v < 0) v = -v; - if(cq > 0) { - v += cq; - } else { - v -= cq; - } - if(v > 40) { - Demod.posCount = 0; - Demod.state = DEMOD_PHASE_REF_TRAINING; - Demod.sumI = 0; - Demod.sumQ = 0; - } - break; - - case DEMOD_PHASE_REF_TRAINING: - if(Demod.posCount < 8) { - Demod.sumI += ci; - Demod.sumQ += cq; - } else if(Demod.posCount > 100) { - // error, waited too long - Demod.state = DEMOD_UNSYNCD; - } else { - MAKE_SOFT_DECISION(); - if(v < 0) { - Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; - Demod.posCount = 0; - } - } - Demod.posCount++; - break; - - case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: - MAKE_SOFT_DECISION(); - if(v < 0) { - Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; - Demod.posCount = 0; - } else { - if(Demod.posCount > 100) { - Demod.state = DEMOD_UNSYNCD; - } - } - Demod.posCount++; - break; - - case DEMOD_GOT_FALLING_EDGE_OF_SOF: - MAKE_SOFT_DECISION(); - if(v > 0) { - if(Demod.posCount < 12) { - Demod.state = DEMOD_UNSYNCD; - } else { - LED_C_ON(); // Got SOF - Demod.state = DEMOD_AWAITING_START_BIT; - Demod.posCount = 0; - Demod.len = 0; - Demod.metricN = 0; - Demod.metric = 0; - } - } else { - if(Demod.posCount > 100) { - Demod.state = DEMOD_UNSYNCD; - } - } - Demod.posCount++; - break; - - case DEMOD_AWAITING_START_BIT: - MAKE_SOFT_DECISION(); - if(v > 0) { - if(Demod.posCount > 10) { - Demod.state = DEMOD_UNSYNCD; - } - } else { - Demod.bitCount = 0; - Demod.posCount = 1; - Demod.thisBit = v; - Demod.shiftReg = 0; - Demod.state = DEMOD_RECEIVING_DATA; - } - break; - - case DEMOD_RECEIVING_DATA: - MAKE_SOFT_DECISION(); - if(Demod.posCount == 0) { - Demod.thisBit = v; - Demod.posCount = 1; - } else { - Demod.thisBit += v; - - if(Demod.thisBit > 0) { - Demod.metric += Demod.thisBit; - } else { - Demod.metric -= Demod.thisBit; - } - (Demod.metricN)++; - - Demod.shiftReg >>= 1; - if(Demod.thisBit > 0) { - Demod.shiftReg |= 0x200; - } - - Demod.bitCount++; - if(Demod.bitCount == 10) { - uint16_t s = Demod.shiftReg; - if((s & 0x200) && !(s & 0x001)) { - uint8_t b = (s >> 1); - Demod.output[Demod.len] = b; - Demod.len++; - Demod.state = DEMOD_AWAITING_START_BIT; - } else if(s == 0x000) { - // This is EOF - LED_C_OFF(); - Demod.state = DEMOD_UNSYNCD; - return TRUE; - } else { - Demod.state = DEMOD_UNSYNCD; - } - } - Demod.posCount = 0; - } - break; - - default: - Demod.state = DEMOD_UNSYNCD; - break; - } - - if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized... - return FALSE; -} -static void DemodReset() -{ - // Clear out the state of the "UART" that receives from the tag. - Demod.len = 0; - Demod.state = DEMOD_UNSYNCD; - memset(Demod.output, 0x00, MAX_FRAME_SIZE); -} -static void DemodInit(uint8_t *data) -{ - Demod.output = data; - DemodReset(); -} - -static void UartReset() -{ - Uart.byteCntMax = MAX_FRAME_SIZE; - Uart.state = STATE_UNSYNCD; - Uart.byteCnt = 0; - Uart.bitCnt = 0; -} -static void UartInit(uint8_t *data) -{ - Uart.output = data; - UartReset(); -} - -/* - * Demodulate the samples we received from the tag, also log to tracebuffer - * weTx: set to 'TRUE' if we behave like a reader - * set to 'FALSE' if we behave like a snooper - * quiet: set to 'TRUE' to disable debug output - */ -static void GetSamplesFor14443Demod(int weTx, int n, int quiet) -{ - int max = 0; - int gotFrame = FALSE; - int lastRxCounter, ci, cq, samples = 0; - - // Allocate memory from BigBuf for some buffers - // free all previous allocations first - BigBuf_free(); - - // The command (reader -> tag) that we're receiving. - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - - // The response (tag -> reader) that we're receiving. - uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); - - // The DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - - // Set up the demodulator for tag -> reader responses. - DemodInit(receivedResponse); - // Set up the demodulator for the reader -> tag commands - UartInit(receivedCmd); - - // Setup and start DMA. - FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE); - - uint8_t *upTo= dmaBuf; - lastRxCounter = DMA_BUFFER_SIZE; - - // Signal field is ON with the appropriate LED: - if (weTx) LED_D_ON(); else LED_D_OFF(); - // And put the FPGA in the appropriate mode - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | - (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP)); - - for(;;) { - int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; - if(behindBy > max) max = behindBy; - - while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1)) - > 2) - { - ci = upTo[0]; - cq = upTo[1]; - upTo += 2; - if(upTo - dmaBuf > DMA_BUFFER_SIZE) { - upTo -= DMA_BUFFER_SIZE; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; - } - lastRxCounter -= 2; - if(lastRxCounter <= 0) { - lastRxCounter += DMA_BUFFER_SIZE; - } - - samples += 2; - - Handle14443UartBit(1); - Handle14443UartBit(1); - - if(Handle14443SamplesDemod(ci, cq)) { - gotFrame = 1; - } - } - - if(samples > 2000) { - break; - } - } - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; - if (!quiet) Dbprintf("%x %x %x", max, gotFrame, Demod.len); - //Tracing - if (tracing && Demod.len > 0) { - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Demod.output , Demod.len, parity); - LogTrace(Demod.output,Demod.len, 0, 0, parity, FALSE); - } -} - -//----------------------------------------------------------------------------- -// Read the tag's response. We just receive a stream of slightly-processed -// samples from the FPGA, which we will later do some signal processing on, -// to get the bits. -//----------------------------------------------------------------------------- -/*static void GetSamplesFor14443(int weTx, int n) -{ - uint8_t *dest = (uint8_t *)BigBuf; - int c; - - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | - (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP)); - - c = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - int8_t b; - b = (int8_t)AT91C_BASE_SSC->SSC_RHR; - - dest[c++] = (uint8_t)b; - - if(c >= n) { - break; - } - } - } -}*/ - -//----------------------------------------------------------------------------- -// Transmit the command (to the tag) that was placed in ToSend[]. -//----------------------------------------------------------------------------- -static void TransmitFor14443(void) -{ - int c; - - FpgaSetupSsc(); - - while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xff; - } - - // Signal field is ON with the appropriate Red LED - LED_D_ON(); - // Signal we are transmitting with the Green LED - LED_B_ON(); - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); - - for(c = 0; c < 10;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xff; - c++; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } - WDT_HIT(); - } - - c = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ToSend[c]; - c++; - if(c >= ToSendMax) { - break; - } - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } - WDT_HIT(); - } - LED_B_OFF(); // Finished sending -} - -//----------------------------------------------------------------------------- -// Code a layer 2 command (string of octets, including CRC) into ToSend[], -// so that it is ready to transmit to the tag using TransmitFor14443(). -//----------------------------------------------------------------------------- -static void CodeIso14443bAsReader(const uint8_t *cmd, int len) -{ - int i, j; - uint8_t b; - - ToSendReset(); - - // Establish initial reference level - for(i = 0; i < 40; i++) { - ToSendStuffBit(1); - } - // Send SOF - for(i = 0; i < 10; i++) { - ToSendStuffBit(0); - } - - for(i = 0; i < len; i++) { - // Stop bits/EGT - ToSendStuffBit(1); - ToSendStuffBit(1); - // Start bit - ToSendStuffBit(0); - // Data bits - b = cmd[i]; - for(j = 0; j < 8; j++) { - if(b & 1) { - ToSendStuffBit(1); - } else { - ToSendStuffBit(0); - } - b >>= 1; - } - } - // Send EOF - ToSendStuffBit(1); - for(i = 0; i < 10; i++) { - ToSendStuffBit(0); - } - for(i = 0; i < 8; i++) { - ToSendStuffBit(1); - } - - // And then a little more, to make sure that the last character makes - // it out before we switch to rx mode. - for(i = 0; i < 24; i++) { - ToSendStuffBit(1); - } - - // Convert from last character reference to length - ToSendMax++; -} - -//----------------------------------------------------------------------------- -// Read an ISO 14443 tag. We send it some set of commands, and record the -// responses. -// The command name is misleading, it actually decodes the reponse in HEX -// into the output buffer (read the result using hexsamples, not hisamples) -// -// obsolete function only for test -//----------------------------------------------------------------------------- -void AcquireRawAdcSamplesIso14443(uint32_t parameter) -{ - uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; - - SendRawCommand14443B(sizeof(cmd1),1,1,cmd1); -} - -/** - Convenience function to encode, transmit and trace iso 14443b comms - **/ -static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) -{ - CodeIso14443bAsReader(cmd, len); - TransmitFor14443(); - if (tracing) { - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(cmd, len, parity); - LogTrace(cmd,len, 0, 0, parity, TRUE); - } -} - -//----------------------------------------------------------------------------- -// Read a SRI512 ISO 14443 tag. -// -// SRI512 tags are just simple memory tags, here we're looking at making a dump -// of the contents of the memory. No anticollision algorithm is done, we assume -// we have a single tag in the field. -// -// I tried to be systematic and check every answer of the tag, every CRC, etc... -//----------------------------------------------------------------------------- -void ReadSTMemoryIso14443(uint32_t dwLast) -{ - clear_trace(); - set_tracing(TRUE); - - uint8_t i = 0x00; - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Make sure that we start from off, since the tags are stateful; - // confusing things will happen if we don't reset them between reads. - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - // Now give it time to spin up. - // Signal field is on with the appropriate LED - LED_D_ON(); - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); - SpinDelay(200); - - // First command: wake up the tag using the INITIATE command - uint8_t cmd1[] = { 0x06, 0x00, 0x97, 0x5b}; - - CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); -// LED_A_ON(); - GetSamplesFor14443Demod(TRUE, 2000,TRUE); -// LED_A_OFF(); - - if (Demod.len == 0) { - DbpString("No response from tag"); - return; - } else { - Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x", - Demod.output[0], Demod.output[1],Demod.output[2]); - } - // There is a response, SELECT the uid - DbpString("Now SELECT tag:"); - cmd1[0] = 0x0E; // 0x0E is SELECT - cmd1[1] = Demod.output[0]; - ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); - CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - -// LED_A_ON(); - GetSamplesFor14443Demod(TRUE, 2000,TRUE); -// LED_A_OFF(); - if (Demod.len != 3) { - Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); - return; - } - // Check the CRC of the answer: - ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]); - if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) { - DbpString("CRC Error reading select response."); - return; - } - // Check response from the tag: should be the same UID as the command we just sent: - if (cmd1[1] != Demod.output[0]) { - Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]); - return; - } - // Tag is now selected, - // First get the tag's UID: - cmd1[0] = 0x0B; - ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]); - CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one - -// LED_A_ON(); - GetSamplesFor14443Demod(TRUE, 2000,TRUE); -// LED_A_OFF(); - if (Demod.len != 10) { - Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); - return; - } - // The check the CRC of the answer (use cmd1 as temporary variable): - ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]); - if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) { - Dbprintf("CRC Error reading block! - Below: expected, got %x %x", - (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); - // Do not return;, let's go on... (we should retry, maybe ?) - } - Dbprintf("Tag UID (64 bits): %08x %08x", - (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], - (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); - - // Now loop to read all 16 blocks, address from 0 to last block - Dbprintf("Tag memory dump, block 0 to %d",dwLast); - cmd1[0] = 0x08; - i = 0x00; - dwLast++; - for (;;) { - if (i == dwLast) { - DbpString("System area block (0xff):"); - i = 0xff; - } - cmd1[1] = i; - ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); - CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - -// LED_A_ON(); - GetSamplesFor14443Demod(TRUE, 2000,TRUE); -// LED_A_OFF(); - if (Demod.len != 6) { // Check if we got an answer from the tag - DbpString("Expected 6 bytes from tag, got less..."); - return; - } - // The check the CRC of the answer (use cmd1 as temporary variable): - ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]); - if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { - Dbprintf("CRC Error reading block! - Below: expected, got %x %x", - (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); - // Do not return;, let's go on... (we should retry, maybe ?) - } - // Now print out the memory location: - Dbprintf("Address=%x, Contents=%x, CRC=%x", i, - (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], - (Demod.output[4]<<8)+Demod.output[5]); - if (i == 0xff) { - break; - } - i++; - } -} - - -//============================================================================= -// Finally, the `sniffer' combines elements from both the reader and -// simulated tag, to show both sides of the conversation. -//============================================================================= - -//----------------------------------------------------------------------------- -// Record the sequence of commands sent by the reader to the tag, with -// triggering so that we start recording at the point that the tag is moved -// near the reader. -//----------------------------------------------------------------------------- -/* - * Memory usage for this function, (within BigBuf) - * 0-4095 : Demodulated samples receive (4096 bytes) - DEMOD_TRACE_SIZE - * 4096-6143 : Last Received command, 2048 bytes (reader->tag) - READER_TAG_BUFFER_SIZE - * 6144-8191 : Last Received command, 2048 bytes(tag->reader) - TAG_READER_BUFFER_SIZE - * 8192-9215 : DMA Buffer, 1024 bytes (samples) - DEMOD_DMA_BUFFER_SIZE - */ -void RAMFUNC SnoopIso14443(void) -{ - // We won't start recording the frames that we acquire until we trigger; - // a good trigger condition to get started is probably when we see a - // response from the tag. - int triggered = TRUE; - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - BigBuf_free(); - - clear_trace(); - set_tracing(TRUE); - - // The DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - int lastRxCounter; - uint8_t *upTo; - int ci, cq; - int maxBehindBy = 0; - - // Count of samples received so far, so that we can include timing - // information in the trace buffer. - int samples = 0; - - DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); - UartInit(BigBuf_malloc(MAX_FRAME_SIZE)); - - // Print some debug information about the buffer sizes - Dbprintf("Snooping buffers initialized:"); - Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); - Dbprintf(" Reader -> tag: %i bytes", MAX_FRAME_SIZE); - Dbprintf(" tag -> Reader: %i bytes", MAX_FRAME_SIZE); - Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE); - - // Signal field is off with the appropriate LED - LED_D_OFF(); - - // And put the FPGA in the appropriate mode - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | - FPGA_HF_READER_RX_XCORR_SNOOP); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Setup for the DMA. - FpgaSetupSsc(); - upTo = dmaBuf; - lastRxCounter = DMA_BUFFER_SIZE; - FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); - uint8_t parity[MAX_PARITY_SIZE]; - LED_A_ON(); - - // And now we loop, receiving samples. - for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & - (DMA_BUFFER_SIZE-1); - if(behindBy > maxBehindBy) { - maxBehindBy = behindBy; - if(behindBy > (9*DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not? - Dbprintf("blew circular buffer! behindBy=0x%x", behindBy); - break; - } - } - if(behindBy < 2) continue; - - ci = upTo[0]; - cq = upTo[1]; - upTo += 2; - lastRxCounter -= 2; - if(upTo - dmaBuf > DMA_BUFFER_SIZE) { - upTo -= DMA_BUFFER_SIZE; - lastRxCounter += DMA_BUFFER_SIZE; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; - } - - samples += 2; - - if(Handle14443UartBit(ci & 1)) { - if(triggered && tracing) { - GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE); - } - if(Uart.byteCnt==0) Dbprintf("[1] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); - - /* And ready to receive another command. */ - UartReset(); - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - DemodReset(); - } - if(Handle14443UartBit(cq & 1)) { - if(triggered && tracing) { - GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE); - } - if(Uart.byteCnt==0) Dbprintf("[2] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); - - /* And ready to receive another command. */ - UartReset(); - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - DemodReset(); - } - - if(Handle14443SamplesDemod(ci, cq)) { - - //Use samples as a time measurement - if(tracing) - { - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output,Demod.len,samples, samples,parity,FALSE); - } - triggered = TRUE; - LED_A_OFF(); - LED_B_ON(); - - // And ready to receive another response. - DemodReset(); - } - WDT_HIT(); - - if(!tracing) { - DbpString("Reached trace limit"); - break; - } - - if(BUTTON_PRESS()) { - DbpString("cancelled"); - break; - } - } - FpgaDisableSscDma(); - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; - DbpString("Snoop statistics:"); - Dbprintf(" Max behind by: %i", maxBehindBy); - Dbprintf(" Uart State: %x", Uart.state); - Dbprintf(" Uart ByteCnt: %i", Uart.byteCnt); - Dbprintf(" Uart ByteCntMax: %i", Uart.byteCntMax); - Dbprintf(" Trace length: %i", BigBuf_get_traceLen()); -} - -/* - * Send raw command to tag ISO14443B - * @Input - * datalen len of buffer data - * recv bool when true wait for data from tag and send to client - * powerfield bool leave the field on when true - * data buffer with byte to send - * - * @Output - * none - * - */ - -void SendRawCommand14443B(uint32_t datalen, uint32_t recv,uint8_t powerfield, uint8_t data[]) -{ - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - if(!powerfield) - { - // Make sure that we start from off, since the tags are stateful; - // confusing things will happen if we don't reset them between reads. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelay(200); - } - - if(!GETBIT(GPIO_LED_D)) - { - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - // Now give it time to spin up. - // Signal field is on with the appropriate LED - LED_D_ON(); - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); - SpinDelay(200); - } - - CodeAndTransmit14443bAsReader(data, datalen); - - if(recv) - { - uint16_t iLen = MIN(Demod.len,USB_CMD_DATA_SIZE); - GetSamplesFor14443Demod(TRUE, 2000, TRUE); - cmd_send(CMD_ACK,iLen,0,0,Demod.output,iLen); - } - if(!powerfield) - { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - } -} - diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 64bbcbf5..cf64da2f 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2510,13 +2510,13 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * || receivedCmd[0] == 0xB0) { // transfer if (receivedCmd[1] >= 16 * 4) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]); + if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]); break; } if (receivedCmd[1] / 4 != cardAUTHSC) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC); + if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC); break; } } diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c new file mode 100644 index 00000000..416c31f9 --- /dev/null +++ b/armsrc/iso14443b.c @@ -0,0 +1,1218 @@ +//----------------------------------------------------------------------------- +// Jonathan Westhues, split Nov 2006 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support ISO 14443B. This includes both the reader software and +// the `fake tag' modes. +//----------------------------------------------------------------------------- + +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" + +#include "iso14443crc.h" + +#define RECEIVE_SAMPLES_TIMEOUT 2000 +#define ISO14443B_DMA_BUFFER_SIZE 256 + +//============================================================================= +// An ISO 14443 Type B tag. We listen for commands from the reader, using +// a UART kind of thing that's implemented in software. When we get a +// frame (i.e., a group of bytes between SOF and EOF), we check the CRC. +// If it's good, then we can do something appropriate with it, and send +// a response. +//============================================================================= + +//----------------------------------------------------------------------------- +// Code up a string of octets at layer 2 (including CRC, we don't generate +// that here) so that they can be transmitted to the reader. Doesn't transmit +// them yet, just leaves them ready to send in ToSend[]. +//----------------------------------------------------------------------------- +static void CodeIso14443bAsTag(const uint8_t *cmd, int len) +{ + int i; + + ToSendReset(); + + // Transmit a burst of ones, as the initial thing that lets the + // reader get phase sync. This (TR1) must be > 80/fs, per spec, + // but tag that I've tried (a Paypass) exceeds that by a fair bit, + // so I will too. + for(i = 0; i < 20; i++) { + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + // Send SOF. + for(i = 0; i < 10; i++) { + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + } + for(i = 0; i < 2; i++) { + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + for(i = 0; i < len; i++) { + int j; + uint8_t b = cmd[i]; + + // Start bit + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + + // Data bits + for(j = 0; j < 8; j++) { + if(b & 1) { + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } else { + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + } + b >>= 1; + } + + // Stop bit + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + // Send EOF. + for(i = 0; i < 10; i++) { + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + } + for(i = 0; i < 2; i++) { + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + // Convert from last byte pos to length + ToSendMax++; +} + +//----------------------------------------------------------------------------- +// The software UART that receives commands from the reader, and its state +// variables. +//----------------------------------------------------------------------------- +static struct { + enum { + STATE_UNSYNCD, + STATE_GOT_FALLING_EDGE_OF_SOF, + STATE_AWAITING_START_BIT, + STATE_RECEIVING_DATA + } state; + uint16_t shiftReg; + int bitCnt; + int byteCnt; + int byteCntMax; + int posCnt; + uint8_t *output; +} Uart; + +/* Receive & handle a bit coming from the reader. + * + * This function is called 4 times per bit (every 2 subcarrier cycles). + * Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 2,36us + * + * LED handling: + * LED A -> ON once we have received the SOF and are expecting the rest. + * LED A -> OFF once we have received EOF or are in error state or unsynced + * + * Returns: true if we received a EOF + * false if we are still waiting for some more + */ +static RAMFUNC int Handle14443bUartBit(uint8_t bit) +{ + switch(Uart.state) { + case STATE_UNSYNCD: + if(!bit) { + // we went low, so this could be the beginning + // of an SOF + Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF; + Uart.posCnt = 0; + Uart.bitCnt = 0; + } + break; + + case STATE_GOT_FALLING_EDGE_OF_SOF: + Uart.posCnt++; + if(Uart.posCnt == 2) { // sample every 4 1/fs in the middle of a bit + if(bit) { + if(Uart.bitCnt > 9) { + // we've seen enough consecutive + // zeros that it's a valid SOF + Uart.posCnt = 0; + Uart.byteCnt = 0; + Uart.state = STATE_AWAITING_START_BIT; + LED_A_ON(); // Indicate we got a valid SOF + } else { + // didn't stay down long enough + // before going high, error + Uart.state = STATE_UNSYNCD; + } + } else { + // do nothing, keep waiting + } + Uart.bitCnt++; + } + if(Uart.posCnt >= 4) Uart.posCnt = 0; + if(Uart.bitCnt > 12) { + // Give up if we see too many zeros without + // a one, too. + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; + } + break; + + case STATE_AWAITING_START_BIT: + Uart.posCnt++; + if(bit) { + if(Uart.posCnt > 50/2) { // max 57us between characters = 49 1/fs, max 3 etus after low phase of SOF = 24 1/fs + // stayed high for too long between + // characters, error + Uart.state = STATE_UNSYNCD; + } + } else { + // falling edge, this starts the data byte + Uart.posCnt = 0; + Uart.bitCnt = 0; + Uart.shiftReg = 0; + Uart.state = STATE_RECEIVING_DATA; + } + break; + + case STATE_RECEIVING_DATA: + Uart.posCnt++; + if(Uart.posCnt == 2) { + // time to sample a bit + Uart.shiftReg >>= 1; + if(bit) { + Uart.shiftReg |= 0x200; + } + Uart.bitCnt++; + } + if(Uart.posCnt >= 4) { + Uart.posCnt = 0; + } + if(Uart.bitCnt == 10) { + if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001)) + { + // this is a data byte, with correct + // start and stop bits + Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff; + Uart.byteCnt++; + + if(Uart.byteCnt >= Uart.byteCntMax) { + // Buffer overflowed, give up + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; + } else { + // so get the next byte now + Uart.posCnt = 0; + Uart.state = STATE_AWAITING_START_BIT; + } + } else if (Uart.shiftReg == 0x000) { + // this is an EOF byte + LED_A_OFF(); // Finished receiving + Uart.state = STATE_UNSYNCD; + if (Uart.byteCnt != 0) { + return TRUE; + } + } else { + // this is an error + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; + } + } + break; + + default: + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; + break; + } + + return FALSE; +} + + +static void UartReset() +{ + Uart.byteCntMax = MAX_FRAME_SIZE; + Uart.state = STATE_UNSYNCD; + Uart.byteCnt = 0; + Uart.bitCnt = 0; +} + + +static void UartInit(uint8_t *data) +{ + Uart.output = data; + UartReset(); +} + + +//----------------------------------------------------------------------------- +// Receive a command (from the reader to us, where we are the simulated tag), +// and store it in the given buffer, up to the given maximum length. Keeps +// spinning, waiting for a well-framed command, until either we get one +// (returns TRUE) or someone presses the pushbutton on the board (FALSE). +// +// Assume that we're called with the SSC (to the FPGA) and ADC path set +// correctly. +//----------------------------------------------------------------------------- +static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) +{ + // Set FPGA mode to "simulated ISO 14443B tag", no modulation (listen + // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + + // Now run a `software UART' on the stream of incoming samples. + UartInit(received); + + for(;;) { + WDT_HIT(); + + if(BUTTON_PRESS()) return FALSE; + + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + for(uint8_t mask = 0x80; mask != 0x00; mask >>= 1) { + if(Handle14443bUartBit(b & mask)) { + *len = Uart.byteCnt; + return TRUE; + } + } + } + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// Main loop of simulated tag: receive commands from reader, decide what +// response to send, and send it. +//----------------------------------------------------------------------------- +void SimulateIso14443bTag(void) +{ + // the only commands we understand is REQB, AFI=0, Select All, N=0: + static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; + // ... and REQB, AFI=0, Normal Request, N=0: + static const uint8_t cmd2[] = { 0x05, 0x00, 0x00, 0x71, 0xFF }; + + // ... and we always respond with ATQB, PUPI = 820de174, Application Data = 0x20381922, + // supports only 106kBit/s in both directions, max frame size = 32Bytes, + // supports ISO14443-4, FWI=8 (77ms), NAD supported, CID not supported: + static const uint8_t response1[] = { + 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22, + 0x00, 0x21, 0x85, 0x5e, 0xd7 + }; + + clear_trace(); + set_tracing(TRUE); + + const uint8_t *resp; + uint8_t *respCode; + uint16_t respLen, respCodeLen; + + // allocate command receive buffer + BigBuf_free(); + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); + + uint16_t len; + uint16_t cmdsRecvd = 0; + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + // prepare the (only one) tag answer: + CodeIso14443bAsTag(response1, sizeof(response1)); + uint8_t *resp1Code = BigBuf_malloc(ToSendMax); + memcpy(resp1Code, ToSend, ToSendMax); + uint16_t resp1CodeLen = ToSendMax; + + // We need to listen to the high-frequency, peak-detected path. + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + cmdsRecvd = 0; + + for(;;) { + + if(!GetIso14443bCommandFromReader(receivedCmd, &len)) { + Dbprintf("button pressed, received %d commands", cmdsRecvd); + break; + } + + if (tracing) { + uint8_t parity[MAX_PARITY_SIZE]; + LogTrace(receivedCmd, len, 0, 0, parity, TRUE); + } + + // Good, look at the command now. + if ( (len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0) + || (len == sizeof(cmd2) && memcmp(receivedCmd, cmd2, len) == 0) ) { + resp = response1; + respLen = sizeof(response1); + respCode = resp1Code; + respCodeLen = resp1CodeLen; + } else { + Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd); + // And print whether the CRC fails, just for good measure + uint8_t b1, b2; + ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2); + if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) { + // Not so good, try again. + DbpString("+++CRC fail"); + } else { + DbpString("CRC passes"); + } + break; + } + + cmdsRecvd++; + + if(cmdsRecvd > 0x30) { + DbpString("many commands later..."); + break; + } + + if(respCodeLen <= 0) continue; + + // Modulate BPSK + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); + AT91C_BASE_SSC->SSC_THR = 0xff; + FpgaSetupSsc(); + + // Transmit the response. + uint16_t i = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + uint8_t b = respCode[i]; + + AT91C_BASE_SSC->SSC_THR = b; + + i++; + if(i > respCodeLen) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; + } + } + + // trace the response: + if (tracing) { + uint8_t parity[MAX_PARITY_SIZE]; + LogTrace(resp, respLen, 0, 0, parity, FALSE); + } + + } +} + +//============================================================================= +// An ISO 14443 Type B reader. We take layer two commands, code them +// appropriately, and then send them to the tag. We then listen for the +// tag's response, which we leave in the buffer to be demodulated on the +// PC side. +//============================================================================= + +static struct { + enum { + DEMOD_UNSYNCD, + DEMOD_PHASE_REF_TRAINING, + DEMOD_AWAITING_FALLING_EDGE_OF_SOF, + DEMOD_GOT_FALLING_EDGE_OF_SOF, + DEMOD_AWAITING_START_BIT, + DEMOD_RECEIVING_DATA + } state; + int bitCount; + int posCount; + int thisBit; +/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. + int metric; + int metricN; +*/ + uint16_t shiftReg; + uint8_t *output; + int len; + int sumI; + int sumQ; +} Demod; + +/* + * Handles reception of a bit from the tag + * + * This function is called 2 times per bit (every 4 subcarrier cycles). + * Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 4,72us + * + * LED handling: + * LED C -> ON once we have received the SOF and are expecting the rest. + * LED C -> OFF once we have received EOF or are unsynced + * + * Returns: true if we received a EOF + * false if we are still waiting for some more + * + */ +static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) +{ + int v; + +// The soft decision on the bit uses an estimate of just the +// quadrant of the reference angle, not the exact angle. +#define MAKE_SOFT_DECISION() { \ + if(Demod.sumI > 0) { \ + v = ci; \ + } else { \ + v = -ci; \ + } \ + if(Demod.sumQ > 0) { \ + v += cq; \ + } else { \ + v -= cq; \ + } \ + } + +#define SUBCARRIER_DETECT_THRESHOLD 8 + +// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(cq) +/* #define CHECK_FOR_SUBCARRIER() { \ + v = ci; \ + if(v < 0) v = -v; \ + if(cq > 0) { \ + v += cq; \ + } else { \ + v -= cq; \ + } \ + } + */ +// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) +#define CHECK_FOR_SUBCARRIER() { \ + if(ci < 0) { \ + if(cq < 0) { /* ci < 0, cq < 0 */ \ + if (cq < ci) { \ + v = -cq - (ci >> 1); \ + } else { \ + v = -ci - (cq >> 1); \ + } \ + } else { /* ci < 0, cq >= 0 */ \ + if (cq < -ci) { \ + v = -ci + (cq >> 1); \ + } else { \ + v = cq - (ci >> 1); \ + } \ + } \ + } else { \ + if(cq < 0) { /* ci >= 0, cq < 0 */ \ + if (-cq < ci) { \ + v = ci - (cq >> 1); \ + } else { \ + v = -cq + (ci >> 1); \ + } \ + } else { /* ci >= 0, cq >= 0 */ \ + if (cq < ci) { \ + v = ci + (cq >> 1); \ + } else { \ + v = cq + (ci >> 1); \ + } \ + } \ + } \ + } + + switch(Demod.state) { + case DEMOD_UNSYNCD: + CHECK_FOR_SUBCARRIER(); + if(v > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected + Demod.state = DEMOD_PHASE_REF_TRAINING; + Demod.sumI = ci; + Demod.sumQ = cq; + Demod.posCount = 1; + } + break; + + case DEMOD_PHASE_REF_TRAINING: + if(Demod.posCount < 8) { + CHECK_FOR_SUBCARRIER(); + if (v > SUBCARRIER_DETECT_THRESHOLD) { + // set the reference phase (will code a logic '1') by averaging over 32 1/fs. + // note: synchronization time > 80 1/fs + Demod.sumI += ci; + Demod.sumQ += cq; + Demod.posCount++; + } else { // subcarrier lost + Demod.state = DEMOD_UNSYNCD; + } + } else { + Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; + } + break; + + case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: + MAKE_SOFT_DECISION(); + if(v < 0) { // logic '0' detected + Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; + Demod.posCount = 0; // start of SOF sequence + } else { + if(Demod.posCount > 200/4) { // maximum length of TR1 = 200 1/fs + Demod.state = DEMOD_UNSYNCD; + } + } + Demod.posCount++; + break; + + case DEMOD_GOT_FALLING_EDGE_OF_SOF: + Demod.posCount++; + MAKE_SOFT_DECISION(); + if(v > 0) { + if(Demod.posCount < 9*2) { // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges + Demod.state = DEMOD_UNSYNCD; + } else { + LED_C_ON(); // Got SOF + Demod.state = DEMOD_AWAITING_START_BIT; + Demod.posCount = 0; + Demod.len = 0; +/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. + Demod.metricN = 0; + Demod.metric = 0; +*/ + } + } else { + if(Demod.posCount > 12*2) { // low phase of SOF too long (> 12 etu) + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } + } + break; + + case DEMOD_AWAITING_START_BIT: + Demod.posCount++; + MAKE_SOFT_DECISION(); + if(v > 0) { + if(Demod.posCount > 3*2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } + } else { // start bit detected + Demod.bitCount = 0; + Demod.posCount = 1; // this was the first half + Demod.thisBit = v; + Demod.shiftReg = 0; + Demod.state = DEMOD_RECEIVING_DATA; + } + break; + + case DEMOD_RECEIVING_DATA: + MAKE_SOFT_DECISION(); + if(Demod.posCount == 0) { // first half of bit + Demod.thisBit = v; + Demod.posCount = 1; + } else { // second half of bit + Demod.thisBit += v; + +/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. + if(Demod.thisBit > 0) { + Demod.metric += Demod.thisBit; + } else { + Demod.metric -= Demod.thisBit; + } + (Demod.metricN)++; +*/ + + Demod.shiftReg >>= 1; + if(Demod.thisBit > 0) { // logic '1' + Demod.shiftReg |= 0x200; + } + + Demod.bitCount++; + if(Demod.bitCount == 10) { + uint16_t s = Demod.shiftReg; + if((s & 0x200) && !(s & 0x001)) { // stop bit == '1', start bit == '0' + uint8_t b = (s >> 1); + Demod.output[Demod.len] = b; + Demod.len++; + Demod.state = DEMOD_AWAITING_START_BIT; + } else { + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + if(s == 0x000) { + // This is EOF (start, stop and all data bits == '0' + return TRUE; + } + } + } + Demod.posCount = 0; + } + break; + + default: + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + break; + } + + return FALSE; +} + + +static void DemodReset() +{ + // Clear out the state of the "UART" that receives from the tag. + Demod.len = 0; + Demod.state = DEMOD_UNSYNCD; + Demod.posCount = 0; + memset(Demod.output, 0x00, MAX_FRAME_SIZE); +} + + +static void DemodInit(uint8_t *data) +{ + Demod.output = data; + DemodReset(); +} + + +/* + * Demodulate the samples we received from the tag, also log to tracebuffer + * quiet: set to 'TRUE' to disable debug output + */ +static void GetSamplesFor14443bDemod(int n, bool quiet) +{ + int max = 0; + bool gotFrame = FALSE; + int lastRxCounter, ci, cq, samples = 0; + + // Allocate memory from BigBuf for some buffers + // free all previous allocations first + BigBuf_free(); + + // The response (tag -> reader) that we're receiving. + uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); + + // The DMA buffer, used to stream samples from the FPGA + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); + + // Set up the demodulator for tag -> reader responses. + DemodInit(receivedResponse); + + // Setup and start DMA. + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); + + int8_t *upTo = dmaBuf; + lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + + // Signal field is ON with the appropriate LED: + LED_D_ON(); + // And put the FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + + for(;;) { + int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; + if(behindBy > max) max = behindBy; + + while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1)) > 2) { + ci = upTo[0]; + cq = upTo[1]; + upTo += 2; + if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { + upTo = dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; + } + lastRxCounter -= 2; + if(lastRxCounter <= 0) { + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; + } + + samples += 2; + + if(Handle14443bSamplesDemod(ci, cq)) { + gotFrame = TRUE; + break; + } + } + + if(samples > n || gotFrame) { + break; + } + } + + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; + + if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", max, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ); + //Tracing + if (tracing && Demod.len > 0) { + uint8_t parity[MAX_PARITY_SIZE]; + LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE); + } +} + + +//----------------------------------------------------------------------------- +// Transmit the command (to the tag) that was placed in ToSend[]. +//----------------------------------------------------------------------------- +static void TransmitFor14443b(void) +{ + int c; + + FpgaSetupSsc(); + + while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xff; + } + + // Signal field is ON with the appropriate Red LED + LED_D_ON(); + // Signal we are transmitting with the Green LED + LED_B_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + + for(c = 0; c < 10;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xff; + c++; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = ToSend[c]; + c++; + if(c >= ToSendMax) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + LED_B_OFF(); // Finished sending +} + + +//----------------------------------------------------------------------------- +// Code a layer 2 command (string of octets, including CRC) into ToSend[], +// so that it is ready to transmit to the tag using TransmitFor14443b(). +//----------------------------------------------------------------------------- +static void CodeIso14443bAsReader(const uint8_t *cmd, int len) +{ + int i, j; + uint8_t b; + + ToSendReset(); + + // Establish initial reference level + for(i = 0; i < 40; i++) { + ToSendStuffBit(1); + } + // Send SOF + for(i = 0; i < 10; i++) { + ToSendStuffBit(0); + } + + for(i = 0; i < len; i++) { + // Stop bits/EGT + ToSendStuffBit(1); + ToSendStuffBit(1); + // Start bit + ToSendStuffBit(0); + // Data bits + b = cmd[i]; + for(j = 0; j < 8; j++) { + if(b & 1) { + ToSendStuffBit(1); + } else { + ToSendStuffBit(0); + } + b >>= 1; + } + } + // Send EOF + ToSendStuffBit(1); + for(i = 0; i < 10; i++) { + ToSendStuffBit(0); + } + for(i = 0; i < 8; i++) { + ToSendStuffBit(1); + } + + // And then a little more, to make sure that the last character makes + // it out before we switch to rx mode. + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } + + // Convert from last character reference to length + ToSendMax++; +} + + +/** + Convenience function to encode, transmit and trace iso 14443b comms + **/ +static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) +{ + CodeIso14443bAsReader(cmd, len); + TransmitFor14443b(); + if (tracing) { + uint8_t parity[MAX_PARITY_SIZE]; + LogTrace(cmd,len, 0, 0, parity, TRUE); + } +} + + +//----------------------------------------------------------------------------- +// Read a SRI512 ISO 14443B tag. +// +// SRI512 tags are just simple memory tags, here we're looking at making a dump +// of the contents of the memory. No anticollision algorithm is done, we assume +// we have a single tag in the field. +// +// I tried to be systematic and check every answer of the tag, every CRC, etc... +//----------------------------------------------------------------------------- +void ReadSTMemoryIso14443b(uint32_t dwLast) +{ + clear_trace(); + set_tracing(TRUE); + + uint8_t i = 0x00; + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Make sure that we start from off, since the tags are stateful; + // confusing things will happen if we don't reset them between reads. + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + SpinDelay(200); + + // First command: wake up the tag using the INITIATE command + uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b}; + CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + + if (Demod.len == 0) { + DbpString("No response from tag"); + return; + } else { + Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x", + Demod.output[0], Demod.output[1], Demod.output[2]); + } + + // There is a response, SELECT the uid + DbpString("Now SELECT tag:"); + cmd1[0] = 0x0E; // 0x0E is SELECT + cmd1[1] = Demod.output[0]; + ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); + CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + if (Demod.len != 3) { + Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); + return; + } + // Check the CRC of the answer: + ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]); + if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) { + DbpString("CRC Error reading select response."); + return; + } + // Check response from the tag: should be the same UID as the command we just sent: + if (cmd1[1] != Demod.output[0]) { + Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]); + return; + } + + // Tag is now selected, + // First get the tag's UID: + cmd1[0] = 0x0B; + ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]); + CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + if (Demod.len != 10) { + Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); + return; + } + // The check the CRC of the answer (use cmd1 as temporary variable): + ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]); + if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) { + Dbprintf("CRC Error reading block! Expected: %04x got: %04x", + (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); + // Do not return;, let's go on... (we should retry, maybe ?) + } + Dbprintf("Tag UID (64 bits): %08x %08x", + (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], + (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); + + // Now loop to read all 16 blocks, address from 0 to last block + Dbprintf("Tag memory dump, block 0 to %d", dwLast); + cmd1[0] = 0x08; + i = 0x00; + dwLast++; + for (;;) { + if (i == dwLast) { + DbpString("System area block (0xff):"); + i = 0xff; + } + cmd1[1] = i; + ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); + CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + if (Demod.len != 6) { // Check if we got an answer from the tag + DbpString("Expected 6 bytes from tag, got less..."); + return; + } + // The check the CRC of the answer (use cmd1 as temporary variable): + ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]); + if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { + Dbprintf("CRC Error reading block! Expected: %04x got: %04x", + (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); + // Do not return;, let's go on... (we should retry, maybe ?) + } + // Now print out the memory location: + Dbprintf("Address=%02x, Contents=%08x, CRC=%04x", i, + (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], + (Demod.output[4]<<8)+Demod.output[5]); + if (i == 0xff) { + break; + } + i++; + } +} + + +//============================================================================= +// Finally, the `sniffer' combines elements from both the reader and +// simulated tag, to show both sides of the conversation. +//============================================================================= + +//----------------------------------------------------------------------------- +// Record the sequence of commands sent by the reader to the tag, with +// triggering so that we start recording at the point that the tag is moved +// near the reader. +//----------------------------------------------------------------------------- +/* + * Memory usage for this function, (within BigBuf) + * Last Received command (reader->tag) - MAX_FRAME_SIZE + * Last Received command (tag->reader) - MAX_FRAME_SIZE + * DMA Buffer - ISO14443B_DMA_BUFFER_SIZE + * Demodulated samples received - all the rest + */ +void RAMFUNC SnoopIso14443b(void) +{ + // We won't start recording the frames that we acquire until we trigger; + // a good trigger condition to get started is probably when we see a + // response from the tag. + int triggered = TRUE; // TODO: set and evaluate trigger condition + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + BigBuf_free(); + + clear_trace(); + set_tracing(TRUE); + + // The DMA buffer, used to stream samples from the FPGA + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); + int lastRxCounter; + int8_t *upTo; + int ci, cq; + int maxBehindBy = 0; + + // Count of samples received so far, so that we can include timing + // information in the trace buffer. + int samples = 0; + + DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); + UartInit(BigBuf_malloc(MAX_FRAME_SIZE)); + + // Print some debug information about the buffer sizes + Dbprintf("Snooping buffers initialized:"); + Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); + Dbprintf(" Reader -> tag: %i bytes", MAX_FRAME_SIZE); + Dbprintf(" tag -> Reader: %i bytes", MAX_FRAME_SIZE); + Dbprintf(" DMA: %i bytes", ISO14443B_DMA_BUFFER_SIZE); + + // Signal field is off, no reader signal, no tag signal + LEDsoff(); + + // And put the FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Setup for the DMA. + FpgaSetupSsc(); + upTo = dmaBuf; + lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); + uint8_t parity[MAX_PARITY_SIZE]; + + bool TagIsActive = FALSE; + bool ReaderIsActive = FALSE; + + // And now we loop, receiving samples. + for(;;) { + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & + (ISO14443B_DMA_BUFFER_SIZE-1); + if(behindBy > maxBehindBy) { + maxBehindBy = behindBy; + } + + if(behindBy < 2) continue; + + ci = upTo[0]; + cq = upTo[1]; + upTo += 2; + lastRxCounter -= 2; + if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { + upTo = dmaBuf; + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; + WDT_HIT(); + if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not? + Dbprintf("blew circular buffer! behindBy=%d", behindBy); + break; + } + if(!tracing) { + DbpString("Reached trace limit"); + break; + } + if(BUTTON_PRESS()) { + DbpString("cancelled"); + break; + } + } + + samples += 2; + + if (!TagIsActive) { // no need to try decoding reader data if the tag is sending + if(Handle14443bUartBit(ci & 0x01)) { + if(triggered && tracing) { + LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); + } + /* And ready to receive another command. */ + UartReset(); + /* And also reset the demod code, which might have been */ + /* false-triggered by the commands from the reader. */ + DemodReset(); + } + if(Handle14443bUartBit(cq & 0x01)) { + if(triggered && tracing) { + LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); + } + /* And ready to receive another command. */ + UartReset(); + /* And also reset the demod code, which might have been */ + /* false-triggered by the commands from the reader. */ + DemodReset(); + } + ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF); + } + + if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if(Handle14443bSamplesDemod(ci | 0x01, cq | 0x01)) { + + //Use samples as a time measurement + if(tracing) + { + uint8_t parity[MAX_PARITY_SIZE]; + LogTrace(Demod.output, Demod.len, samples, samples, parity, FALSE); + } + triggered = TRUE; + + // And ready to receive another response. + DemodReset(); + } + TagIsActive = (Demod.state > DEMOD_GOT_FALLING_EDGE_OF_SOF); + } + + } + + FpgaDisableSscDma(); + LEDsoff(); + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; + DbpString("Snoop statistics:"); + Dbprintf(" Max behind by: %i", maxBehindBy); + Dbprintf(" Uart State: %x", Uart.state); + Dbprintf(" Uart ByteCnt: %i", Uart.byteCnt); + Dbprintf(" Uart ByteCntMax: %i", Uart.byteCntMax); + Dbprintf(" Trace length: %i", BigBuf_get_traceLen()); +} + + +/* + * Send raw command to tag ISO14443B + * @Input + * datalen len of buffer data + * recv bool when true wait for data from tag and send to client + * powerfield bool leave the field on when true + * data buffer with byte to send + * + * @Output + * none + * + */ +void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, uint8_t data[]) +{ + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + set_tracing(TRUE); + + CodeAndTransmit14443bAsReader(data, datalen); + + if(recv) { + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE); + cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen); + } + + if(!powerfield) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + } +} + diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c3fa8a0e..7e53d4a5 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1024,10 +1024,10 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * To compensate antenna falling times shorten the write times * and enlarge the gap ones. */ -#define START_GAP 50*8 // 10 - 50fc 250 -#define WRITE_GAP 20*8 // - 30fc 160 -#define WRITE_0 24*8 // 16 - 63fc 54fc 144 -#define WRITE_1 54*8 // 48 - 63fc 54fc 432 for T55x7; 448 for E5550 //400 +#define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) +#define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) +#define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) +#define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 #define T55xx_SAMPLES_SIZE 12000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 8355cd19..939c9002 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -16,7 +16,6 @@ #include "mifarecmd.h" #include "apps.h" #include "util.h" - #include "crc.h" // the block number for the ISO14443-4 PCB @@ -24,7 +23,6 @@ uint8_t pcb_blocknum = 0; // Deselect card by sending a s-block. the crc is precalced for speed static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4}; - //----------------------------------------------------------------------------- // Select, Authenticate, Read a MIFARE tag. // read block @@ -248,11 +246,14 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LEDsoff(); } +// arg0 = blockNo (start) +// arg1 = Pages (number of blocks) +// arg2 = useKey +// datain = KEY bytes void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) { // free eventually allocated BigBuf memory BigBuf_free(); - // clear trace clear_trace(); // params @@ -303,7 +304,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) } for (int i = 0; i < blocks; i++){ - if ((i*4) + 4 > CARD_MEMORY_SIZE) { + if ((i*4) + 4 >= CARD_MEMORY_SIZE) { Dbprintf("Data exceeds buffer!!"); break; } @@ -335,9 +336,11 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks); countblocks *= 4; + cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); + BigBuf_free(); } //----------------------------------------------------------------------------- @@ -412,7 +415,8 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LEDsoff(); } -void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) +/* // Command not needed but left for future testing +void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) { uint8_t blockNo = arg0; byte_t blockdata[16] = {0x00}; @@ -432,7 +436,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) return; }; - if(mifare_ultra_writeblock(blockNo, blockdata)) { + if(mifare_ultra_writeblock_compat(blockNo, blockdata)) { if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(0); return; }; @@ -449,10 +453,19 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } - -void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) +*/ + +// Arg0 : Block to write to. +// Arg1 : 0 = use no authentication. +// 1 = use 0x1A authentication. +// 2 = use 0x1B authentication. +// datain : 4 first bytes is data to be written. +// : 4/16 next bytes is authentication key. +void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { uint8_t blockNo = arg0; + bool useKey = (arg1 == 1); //UL_C + bool usePwd = (arg1 == 2); //UL_EV1/NTAG byte_t blockdata[4] = {0x00}; memcpy(blockdata, datain,4); @@ -468,7 +481,29 @@ void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) return; }; - if(mifare_ultra_special_writeblock(blockNo, blockdata)) { + // UL-C authentication + if ( useKey ) { + uint8_t key[16] = {0x00}; + memcpy(key, datain+4, sizeof(key) ); + + if ( !mifare_ultra_auth(key) ) { + OnError(1); + return; + } + } + + // UL-EV1 / NTAG authentication + if (usePwd) { + uint8_t pwd[4] = {0x00}; + memcpy(pwd, datain+4, 4); + uint8_t pack[4] = {0,0,0,0}; + if (!mifare_ul_ev1_auth(pwd, pack)) { + OnError(1); + return; + } + } + + if(mifare_ultra_writeblock(blockNo, blockdata)) { if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(0); return; @@ -508,7 +543,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ blockdata[1] = pwd[6]; blockdata[2] = pwd[5]; blockdata[3] = pwd[4]; - if(mifare_ultra_special_writeblock( 44, blockdata)) { + if(mifare_ultra_writeblock( 44, blockdata)) { if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(44); return; @@ -518,7 +553,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ blockdata[1] = pwd[2]; blockdata[2] = pwd[1]; blockdata[3] = pwd[0]; - if(mifare_ultra_special_writeblock( 45, blockdata)) { + if(mifare_ultra_writeblock( 45, blockdata)) { if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(45); return; @@ -528,7 +563,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ blockdata[1] = pwd[14]; blockdata[2] = pwd[13]; blockdata[3] = pwd[12]; - if(mifare_ultra_special_writeblock( 46, blockdata)) { + if(mifare_ultra_writeblock( 46, blockdata)) { if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(46); return; @@ -538,7 +573,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ blockdata[1] = pwd[10]; blockdata[2] = pwd[9]; blockdata[3] = pwd[8]; - if(mifare_ultra_special_writeblock( 47, blockdata)) { + if(mifare_ultra_writeblock( 47, blockdata)) { if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(47); return; @@ -682,7 +717,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat LED_B_OFF(); } -// ------------------------------------------------------------------------------------------------- + // ------------------------------------------------------------------------------------------------- LED_C_ON(); @@ -711,7 +746,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // nested authentication auth2_time = auth1_time + delta_time; - len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time); + len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time); if (len != 4) { if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); continue; @@ -1231,14 +1266,12 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ isOK = mifare_desfire_des_auth2(cuid, key, dataout); if( isOK) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) - Dbprintf("Authentication part2: Failed"); - //OnError(4); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed"); + OnError(4); return; } - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) - DbpString("AUTH 2 FINISHED"); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 2 FINISHED"); cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout)); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 2f84797b..8ef364c2 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -65,74 +65,25 @@ uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { return bt; } -// send commands -int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) +// send X byte basic commands +int mifare_sendcmd(uint8_t cmd, uint8_t* data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) { - return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, answer_parity, timing); -} - -int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) -{ - uint8_t dcmd[8]; - dcmd[0] = cmd; - dcmd[1] = data[0]; - dcmd[2] = data[1]; - dcmd[3] = data[2]; - dcmd[4] = data[3]; - dcmd[5] = data[4]; - AppendCrc14443a(dcmd, 6); - ReaderTransmit(dcmd, sizeof(dcmd), NULL); - int len = ReaderReceive(answer, answer_parity); - if(!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); - return 2; - } - return len; -} - -int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) -{ - uint8_t dcmd[19]; - int len; - dcmd[0] = cmd; - memcpy(dcmd+1,data,16); - AppendCrc14443a(dcmd, 17); - - ReaderTransmit(dcmd, sizeof(dcmd), timing); - len = ReaderReceive(answer, answer_parity); - if(!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed. Card timeout."); - len = ReaderReceive(answer,answer_parity); - } - if(len==1) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("NAK - Authentication failed."); - return 1; - } - return len; -} - -int mifare_sendcmd_short_mfuev1auth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) -{ - uint8_t dcmd[7]; - int len; - dcmd[0] = cmd; - memcpy(dcmd+1,data,4); - AppendCrc14443a(dcmd, 5); - + uint8_t dcmd[data_size+3]; + dcmd[0] = cmd; + memcpy(dcmd+1,data,data_size); + AppendCrc14443a(dcmd, data_size+1); ReaderTransmit(dcmd, sizeof(dcmd), timing); - len = ReaderReceive(answer, answer_parity); + int len = ReaderReceive(answer, answer_parity); if(!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed. Card timeout."); - len = ReaderReceive(answer,answer_parity); - } - if(len==1) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("NAK - Authentication failed."); - return 1; - } + if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("%02X Cmd failed. Card timeout.", cmd); + len = ReaderReceive(answer,answer_parity); + //return 0; + } return len; } -int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) +// send 2 byte commands +int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) { uint8_t dcmd[4], ecmd[4]; uint16_t pos, res; @@ -318,8 +269,10 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){ uint8_t key[4] = {0x00}; memcpy(key, keybytes, 4); - Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); - len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) + Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); + len = mifare_sendcmd(0x1B, key, sizeof(key), resp, respPar, NULL); + //len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL); if (len != 4) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len); return 0; @@ -380,8 +333,8 @@ int mifare_ultra_auth(uint8_t *keybytes){ // encrypt out, in, length, key, iv tdes_2key_enc(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b); - - len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL); + //len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL); + len = mifare_sendcmd(0xAF, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL); if (len != 11) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); return 0; @@ -425,6 +378,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; + len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); @@ -493,7 +447,8 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl return 0; } -int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) +/* // command not needed, but left for future testing +int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) { uint16_t len; uint8_t par[3] = {0}; // enough for 18 parity bits @@ -501,7 +456,6 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; - // command MIFARE_CLASSIC_WRITEBLOCK len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK @@ -524,20 +478,21 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) } return 0; } +*/ -int mifare_ultra_special_writeblock(uint8_t blockNo, uint8_t *blockData) +int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) { uint16_t len; - uint8_t d_block[8] = {0x00}; + uint8_t d_block[5] = {0x00}; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; // command MIFARE_CLASSIC_WRITEBLOCK d_block[0]= blockNo; memcpy(d_block+1,blockData,4); - AppendCrc14443a(d_block, 6); + //AppendCrc14443a(d_block, 6); - len = mifare_sendcmd_short_special(NULL, 1, 0xA2, d_block, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd(0xA2, d_block, sizeof(d_block), receivedAnswer, receivedAnswerPar, NULL); if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK if (MF_DBGLEVEL >= MF_DBG_ERROR) diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index d4fcd818..85a34ef6 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -53,23 +53,22 @@ extern int MF_DBGLEVEL; #define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); //functions +int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); -int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); - -int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing); -int mifare_sendcmd_short_mfuev1auth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing); -int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); +// mifare classic int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested); int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing); int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); +int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); +int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); + +// Ultralight/NTAG... int mifare_ul_ev1_auth(uint8_t *key, uint8_t *pack); int mifare_ultra_auth(uint8_t *key); int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData); -int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); +//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData); int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData); -int mifare_ultra_special_writeblock(uint8_t blockNo, uint8_t *blockData); -int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); int mifare_ultra_halt(); // desfire diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index 444b93d0..23562621 100644 --- a/armsrc/optimized_cipher.c +++ b/armsrc/optimized_cipher.c @@ -61,7 +61,6 @@ **/ #include "optimized_cipher.h" -#include #include #include #include diff --git a/client/Makefile b/client/Makefile index f9645194..c454533d 100644 --- a/client/Makefile +++ b/client/Makefile @@ -102,6 +102,7 @@ CMDSRCS = nonce2key/crapto1.c\ pm3_bitlib.c\ aes.c\ protocols.c\ + sha1.c\ ZLIBSRCS = deflate.c adler32.c trees.c zutil.c inflate.c inffast.c inftrees.c ZLIB_FLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED diff --git a/client/cmddata.c b/client/cmddata.c index b9069bc1..bec1b5aa 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -23,6 +23,7 @@ #include "lfdemod.h" #include "usb_cmd.h" #include "crc.h" +#include "crc16.h" uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; uint8_t g_debugMode; @@ -55,6 +56,15 @@ int CmdSetDebugMode(const char *Cmd) return 1; } +int usage_data_printdemodbuf(){ + PrintAndLog("Usage: data printdemodbuffer x o "); + PrintAndLog("Options: "); + PrintAndLog(" h This help"); + PrintAndLog(" x output in hex (omit for binary output)"); + PrintAndLog(" o enter offset in # of bits"); + return 0; +} + //by marshmellow void printDemodBuff(void) { @@ -73,23 +83,50 @@ void printDemodBuff(void) int CmdPrintDemodBuff(const char *Cmd) { - char hex; - char printBuff[512]={0x00}; - uint8_t numBits = DemodBufferLen & 0xFFFC; - sscanf(Cmd, "%c", &hex); - if (hex == 'h'){ - PrintAndLog("Usage: data printdemodbuffer [x]"); - PrintAndLog("Options: "); - PrintAndLog(" h This help"); - PrintAndLog(" x output in hex (omit for binary output)"); - return 0; + char hex[512]={0x00}; + bool hexMode = false; + bool errors = false; + uint8_t offset = 0; + char cmdp = 0; + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_data_printdemodbuf(); + case 'x': + case 'X': + hexMode = true; + cmdp++; + break; + case 'o': + case 'O': + offset = param_get8(Cmd, cmdp+1); + if (!offset) errors = true; + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) break; } - if (hex == 'x'){ - numBits = binarraytohex(printBuff, (char *)DemodBuffer, numBits); + //Validations + if(errors) return usage_data_printdemodbuf(); + + int numBits = (DemodBufferLen-offset) & 0x7FC; //make sure we don't exceed our string + + if (hexMode){ + char *buf = (char *) (DemodBuffer + offset); + numBits = binarraytohex(hex, buf, numBits); if (numBits==0) return 0; - PrintAndLog("DemodBuffer: %s",printBuff); + PrintAndLog("DemodBuffer: %s",hex); } else { - printDemodBuff(); + //setDemodBuf(DemodBuffer, DemodBufferLen-offset, offset); + char *bin = sprint_bin_break(DemodBuffer+offset,numBits,16); + PrintAndLog("DemodBuffer:\n%s",bin); } return 1; } @@ -307,8 +344,8 @@ int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType) setDemodBuf(BitStream,BitLen,0); if (verbose || g_debugMode){ if (errCnt>0) PrintAndLog("# Errors during Demoding (shown as 7 in bit stream): %d",errCnt); - if (askType) PrintAndLog("ASK/Manchester decoded bitstream:"); - else PrintAndLog("ASK/Raw decoded bitstream:"); + if (askType) PrintAndLog("ASK/Manchester - Clock: %d - Decoded bitstream:",clk); + else PrintAndLog("ASK/Raw - Clock: %d - Decoded bitstream:",clk); // Now output the bitstream to the scrollback by line of 16 bits printDemodBuff(); @@ -355,7 +392,7 @@ int Cmdmandecoderaw(const char *Cmd) int errCnt=0; size_t size=0; int invert=0; - size_t maxErr = 20; + int maxErr = 20; char cmdp = param_getchar(Cmd, 0); if (strlen(Cmd) > 5 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data manrawdecode [invert] [maxErr]"); @@ -461,22 +498,20 @@ int CmdBiphaseDecodeRaw(const char *Cmd) int ASKbiphaseDemod(const char *Cmd, bool verbose) { //ask raw demod GraphBuffer first - int offset=0, clk=0, invert=0, maxErr=0, ans=0; - ans = sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr); - if (ans>0) - ans = ASKDemod(Cmd+1, FALSE, FALSE, 0); - else - ans = ASKDemod(Cmd, FALSE, FALSE, 0); - if (!ans) { - if (g_debugMode || verbose) PrintAndLog("Error AskDemod: %d", ans); - return 0; - } + int offset=0, clk=0, invert=0, maxErr=0; + sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr); + + uint8_t BitStream[MAX_DEMOD_BUF_LEN]; + size_t size = getFromGraphBuf(BitStream); + //invert here inverts the ask raw demoded bits which has no effect on the demod, but we need the pointer + int errCnt = askdemod(BitStream, &size, &clk, &invert, maxErr, 0, 0); + if ( errCnt < 0 || errCnt > maxErr ) { + if (g_debugMode) PrintAndLog("DEBUG: no data or error found %d, clock: %d", errCnt, clk); + return 0; + } - //attempt to Biphase decode DemodBuffer - size_t size = DemodBufferLen; - uint8_t BitStream[MAX_DEMOD_BUF_LEN]; - memcpy(BitStream, DemodBuffer, DemodBufferLen); - int errCnt = BiphaseRawDecode(BitStream, &size, offset, 0); + //attempt to Biphase decode BitStream + errCnt = BiphaseRawDecode(BitStream, &size, offset, invert); if (errCnt < 0){ if (g_debugMode || verbose) PrintAndLog("Error BiphaseRawDecode: %d", errCnt); return 0; @@ -488,7 +523,7 @@ int ASKbiphaseDemod(const char *Cmd, bool verbose) //success set DemodBuffer and return setDemodBuf(BitStream, size, 0); if (g_debugMode || verbose){ - PrintAndLog("Biphase Decoded using offset: %d - # errors:%d - data:",offset,errCnt); + PrintAndLog("Biphase Decoded using offset: %d - clock: %d - # errors:%d - data:",offset,clk,errCnt); printDemodBuff(); } return 1; @@ -1421,6 +1456,83 @@ int CmdFSKdemodPyramid(const char *Cmd) return 1; } +// FDX-B ISO11784/85 demod (aka animal tag) BIPHASE, inverted, rf/32, with preamble of 00000000001 (128bits) +// 8 databits + 1 parity (1) +// CIITT 16 chksum +// NATIONAL CODE, ICAR database +// COUNTRY CODE (ISO3166) or http://cms.abvma.ca/uploads/ManufacturersISOsandCountryCodes.pdf +// FLAG (animal/non-animal) +int CmdFDXBdemodBI(const char *Cmd){ + + int invert = 1; + int clk = 32; + int errCnt = 0; + int maxErr = 0; + uint8_t BitStream[MAX_DEMOD_BUF_LEN]; + size_t size = getFromGraphBuf(BitStream); + + errCnt = askdemod(BitStream, &size, &clk, &invert, maxErr, 0, 0); + if ( errCnt < 0 || errCnt > maxErr ) { + if (g_debugMode) PrintAndLog("DEBUG: no data or error found %d, clock: %d", errCnt, clk); + return 0; + } + + errCnt = BiphaseRawDecode(BitStream, &size, maxErr, 1); + if (errCnt < 0 || errCnt > maxErr ) { + if (g_debugMode) PrintAndLog("Error BiphaseRawDecode: %d", errCnt); + return 0; + } + + int preambleIndex = FDXBdemodBI(BitStream, &size); + if (preambleIndex < 0){ + if (g_debugMode) PrintAndLog("Error FDXBDemod , no startmarker found :: %d",preambleIndex); + return 0; + } + + setDemodBuf(BitStream, 128, preambleIndex); + + // remove but don't verify parity. (pType = 2) + size = removeParity(BitStream, preambleIndex + 11, 9, 2, 117); + if ( size <= 103 ) { + if (g_debugMode) PrintAndLog("Error removeParity:: %d", size); + return 0; + } + if (g_debugMode) { + char *bin = sprint_bin_break(BitStream,size,16); + PrintAndLog("DEBUG BinStream:\n%s",bin); + } + PrintAndLog("\nFDX-B / ISO 11784/5 Animal Tag ID Found:"); + if (g_debugMode) PrintAndLog("Start marker %d; Size %d", preambleIndex, size); + + //got a good demod + uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(BitStream+32,6)) << 32) | bytebits_to_byteLSBF(BitStream,32); + uint32_t countryCode = bytebits_to_byteLSBF(BitStream+38,10); + uint8_t dataBlockBit = BitStream[48]; + uint32_t reservedCode = bytebits_to_byteLSBF(BitStream+49,14); + uint8_t animalBit = BitStream[63]; + uint32_t crc16 = bytebits_to_byteLSBF(BitStream+64,16); + uint32_t extended = bytebits_to_byteLSBF(BitStream+80,24); + + uint64_t rawid = ((uint64_t)bytebits_to_byte(BitStream,32)<<32) | bytebits_to_byte(BitStream+32,32); + uint8_t raw[8]; + num_to_bytes(rawid, 8, raw); + + if (g_debugMode) PrintAndLog("Raw ID Hex: %s", sprint_hex(raw,8)); + + uint16_t calcCrc = crc16_ccitt_kermit(raw, 8); + PrintAndLog("Animal ID: %04u-%012llu", countryCode, NationalCode); + PrintAndLog("National Code: %012llu", NationalCode); + PrintAndLog("CountryCode: %04u", countryCode); + PrintAndLog("Extended Data: %s", dataBlockBit ? "True" : "False"); + PrintAndLog("reserved Code: %u", reservedCode); + PrintAndLog("Animal Tag: %s", animalBit ? "True" : "False"); + PrintAndLog("CRC: 0x%04X - [%04X] - %s", crc16, calcCrc, (calcCrc == crc16) ? "Passed" : "Failed"); + PrintAndLog("Extended: 0x%X\n", extended); + + return 1; +} + + //by marshmellow //attempt to psk1 demod graph buffer int PSKDemod(const char *Cmd, bool verbose) @@ -1434,12 +1546,12 @@ int PSKDemod(const char *Cmd, bool verbose) clk=0; } if (invert != 0 && invert != 1) { - if (verbose) PrintAndLog("Invalid argument: %s", Cmd); + if (g_debugMode || verbose) PrintAndLog("Invalid argument: %s", Cmd); return 0; } uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; size_t BitLen = getFromGraphBuf(BitStream); - if (BitLen==0) return -1; + if (BitLen==0) return 0; uint8_t carrier=countFC(BitStream, BitLen, 0); if (carrier!=2 && carrier!=4 && carrier!=8){ //invalid carrier @@ -2165,6 +2277,7 @@ static command_t CommandTable[] = {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, {"dec", CmdDec, 1, "Decimate samples"}, {"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate of wave in GraphBuffer (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"}, + {"fdxbdemod", CmdFDXBdemodBI , 1, "Demodulate a FDX-B ISO11784/85 Biphase tag from GraphBuffer"}, {"fskawiddemod", CmdFSKdemodAWID, 1, "Demodulate an AWID FSK tag from GraphBuffer"}, //{"fskfcdetect", CmdFSKfcDetect, 1, "Try to detect the Field Clock of an FSK wave"}, {"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate a HID FSK tag from GraphBuffer"}, @@ -2182,7 +2295,7 @@ static command_t CommandTable[] = {"manrawdecode", Cmdmandecoderaw, 1, "[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer"}, {"norm", CmdNorm, 1, "Normalize max/min to +/-128"}, {"plot", CmdPlot, 1, "Show graph window (hit 'h' in window for keystroke help)"}, - {"printdemodbuffer",CmdPrintDemodBuff, 1, "[x] -- print the data in the DemodBuffer - 'x' for hex output"}, + {"printdemodbuffer",CmdPrintDemodBuff, 1, "[x] [o] -- print the data in the DemodBuffer - 'x' for hex output"}, {"pskindalademod", CmdIndalaDecode, 1, "[clock] [invert<0|1>] -- Demodulate an indala tag (PSK1) from GraphBuffer (args optional)"}, {"psknexwatchdemod",CmdPSKNexWatch, 1, "Demodulate a NexWatch tag (nexkey, quadrakey) (PSK1) from GraphBuffer"}, {"rawdemod", CmdRawDemod, 1, "[modulation] ... -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"}, diff --git a/client/cmddata.h b/client/cmddata.h index c6230736..fcc51a6b 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -27,6 +27,7 @@ int CmdBitsamples(const char *Cmd); int CmdBuffClear(const char *Cmd); int CmdDec(const char *Cmd); int CmdDetectClockRate(const char *Cmd); +int CmdFDXBdemodBI(const char *Cmd); int CmdFSKdemodAWID(const char *Cmd); int CmdFSKdemodHID(const char *Cmd); int CmdFSKdemodIO(const char *Cmd); diff --git a/client/cmdhf.c b/client/cmdhf.c index 16f7bb0f..fc6127c2 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -378,7 +378,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); } uint8_t parityBits = parityBytes[j>>3]; - if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + if (protocol != ISO_14443B && isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]); } else { diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 525ffcc6..496267cd 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -25,154 +25,23 @@ static int CmdHelp(const char *Cmd); -int CmdHF14BDemod(const char *Cmd) -{ - int i, j, iold; - int isum, qsum; - int outOfWeakAt; - bool negateI, negateQ; - - uint8_t data[256]; - int dataLen = 0; - - // As received, the samples are pairs, correlations against I and Q - // square waves. So estimate angle of initial carrier (or just - // quadrant, actually), and then do the demod. - - // First, estimate where the tag starts modulating. - for (i = 0; i < GraphTraceLen; i += 2) { - if (abs(GraphBuffer[i]) + abs(GraphBuffer[i + 1]) > 40) { - break; - } - } - if (i >= GraphTraceLen) { - PrintAndLog("too weak to sync"); - return 0; - } - PrintAndLog("out of weak at %d", i); - outOfWeakAt = i; - - // Now, estimate the phase in the initial modulation of the tag - isum = 0; - qsum = 0; - for (; i < (outOfWeakAt + 16); i += 2) { - isum += GraphBuffer[i + 0]; - qsum += GraphBuffer[i + 1]; - } - negateI = (isum < 0); - negateQ = (qsum < 0); - - // Turn the correlation pairs into soft decisions on the bit. - j = 0; - for (i = 0; i < GraphTraceLen / 2; i++) { - int si = GraphBuffer[j]; - int sq = GraphBuffer[j + 1]; - if (negateI) si = -si; - if (negateQ) sq = -sq; - GraphBuffer[i] = si + sq; - j += 2; - } - GraphTraceLen = i; - - i = outOfWeakAt / 2; - while (GraphBuffer[i] > 0 && i < GraphTraceLen) - i++; - if (i >= GraphTraceLen) goto demodError; - - iold = i; - while (GraphBuffer[i] < 0 && i < GraphTraceLen) - i++; - if (i >= GraphTraceLen) goto demodError; - if ((i - iold) > 23) goto demodError; - - PrintAndLog("make it to demod loop"); - - for (;;) { - iold = i; - while (GraphBuffer[i] >= 0 && i < GraphTraceLen) - i++; - if (i >= GraphTraceLen) goto demodError; - if ((i - iold) > 6) goto demodError; - - uint16_t shiftReg = 0; - if (i + 20 >= GraphTraceLen) goto demodError; - - for (j = 0; j < 10; j++) { - int soft = GraphBuffer[i] + GraphBuffer[i + 1]; - - if (abs(soft) < (abs(isum) + abs(qsum)) / 20) { - PrintAndLog("weak bit"); - } - - shiftReg >>= 1; - if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) { - shiftReg |= 0x200; - } - - i+= 2; - } - - if ((shiftReg & 0x200) && !(shiftReg & 0x001)) - { - // valid data byte, start and stop bits okay - PrintAndLog(" %02x", (shiftReg >> 1) & 0xff); - data[dataLen++] = (shiftReg >> 1) & 0xff; - if (dataLen >= sizeof(data)) { - return 0; - } - } else if (shiftReg == 0x000) { - // this is EOF - break; - } else { - goto demodError; - } - } - - uint8_t first, second; - ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second); - PrintAndLog("CRC: %02x %02x (%s)\n", first, second, - (first == data[dataLen-2] && second == data[dataLen-1]) ? - "ok" : "****FAIL****"); - - RepaintGraphWindow(); - return 0; - -demodError: - PrintAndLog("demod error"); - RepaintGraphWindow(); - return 0; -} - int CmdHF14BList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list 14b' instead"); return 0; } -int CmdHF14BRead(const char *Cmd) -{ - UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443, {strtol(Cmd, NULL, 0), 0, 0}}; - SendCommand(&c); - return 0; -} - -int CmdHF14Sim(const char *Cmd) -{ - UsbCommand c={CMD_SIMULATE_TAG_ISO_14443}; - SendCommand(&c); - return 0; -} -int CmdHFSimlisten(const char *Cmd) +int CmdHF14BSim(const char *Cmd) { - UsbCommand c = {CMD_SIMULATE_TAG_HF_LISTEN}; + UsbCommand c={CMD_SIMULATE_TAG_ISO_14443B}; SendCommand(&c); return 0; } int CmdHF14BSnoop(const char *Cmd) { - UsbCommand c = {CMD_SNOOP_ISO_14443}; + UsbCommand c = {CMD_SNOOP_ISO_14443B}; SendCommand(&c); return 0; } @@ -288,7 +157,7 @@ int CmdHF14BCmdRaw (const char *cmd) { if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; PrintAndLog("received %i octets",resp.arg[0]); - if(!resp.arg[0]) + if(resp.arg[0] == 0) return 0; hexout = (char *)malloc(resp.arg[0] * 3 + 1); if (hexout != NULL) { @@ -298,11 +167,13 @@ int CmdHF14BCmdRaw (const char *cmd) { } PrintAndLog("%s", hexout); free(hexout); - ComputeCrc14443(CRC_14443_B, recv, resp.arg[0]-2, &first, &second); - if(recv[resp.arg[0]-2]==first && recv[resp.arg[0]-1]==second) { - PrintAndLog("CRC OK"); - } else { - PrintAndLog("CRC failed"); + if (resp.arg[0] > 2) { + ComputeCrc14443(CRC_14443_B, recv, resp.arg[0]-2, &first, &second); + if(recv[resp.arg[0]-2]==first && recv[resp.arg[0]-1]==second) { + PrintAndLog("CRC OK"); + } else { + PrintAndLog("CRC failed"); + } } } else { PrintAndLog("malloc failed your client has low memory?"); @@ -385,12 +256,9 @@ int CmdHF14BWrite( const char *Cmd){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"demod", CmdHF14BDemod, 1, "Demodulate ISO14443 Type B from tag"}, {"list", CmdHF14BList, 0, "[Deprecated] List ISO 14443b history"}, - {"read", CmdHF14BRead, 0, "Read HF tag (ISO 14443)"}, - {"sim", CmdHF14Sim, 0, "Fake ISO 14443 tag"}, - {"simlisten", CmdHFSimlisten, 0, "Get HF samples as fake tag"}, - {"snoop", CmdHF14BSnoop, 0, "Eavesdrop ISO 14443"}, + {"sim", CmdHF14BSim, 0, "Fake ISO 14443B tag"}, + {"snoop", CmdHF14BSnoop, 0, "Eavesdrop ISO 14443B"}, {"sri512read", CmdSri512Read, 0, "Read contents of a SRI512 tag"}, {"srix4kread", CmdSrix4kRead, 0, "Read contents of a SRIX4K tag"}, {"raw", CmdHF14BCmdRaw, 0, "Send raw hex data to tag"}, diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index 3286ceb9..e9c63f20 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -9,7 +9,7 @@ //----------------------------------------------------------------------------- #include "util.h" -//#include "proxusb.h" + #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" @@ -29,9 +29,9 @@ int CmdHFEPACollectPACENonces(const char *Cmd) unsigned int n = 0; // delay between requests unsigned int d = 0; - + sscanf(Cmd, "%u %u %u", &m, &n, &d); - + // values are expected to be > 0 m = m > 0 ? m : 1; n = n > 0 ? n : 1; @@ -44,7 +44,7 @@ int CmdHFEPACollectPACENonces(const char *Cmd) UsbCommand c = {CMD_EPA_PACE_COLLECT_NONCE, {(int)m, 0, 0}}; SendCommand(&c); UsbCommand resp; - + WaitForResponse(CMD_ACK,&resp); // check if command failed @@ -68,13 +68,123 @@ int CmdHFEPACollectPACENonces(const char *Cmd) return 1; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////The commands lie below here///////////////////////////////////////////////////////////////////////////////////////// + +// perform the PACE protocol by replaying APDUs +int CmdHFEPAPACEReplay(const char *Cmd) +{ + // the 4 APDUs which are replayed + their lengths + uint8_t msesa_apdu[41], gn_apdu[8], map_apdu[75]; + uint8_t pka_apdu[75], ma_apdu[18], apdu_lengths[5] = {0}; + // pointers to the arrays to be able to iterate + uint8_t *apdus[] = {msesa_apdu, gn_apdu, map_apdu, pka_apdu, ma_apdu}; + + // usage message + static const char const *usage_msg = + "Please specify 5 APDUs separated by spaces. " + "Example:\n preplay 0022C1A4 1068000000 1086000002 1234ABCDEF 1A2B3C4D"; + + // Proxmark response + UsbCommand resp; + + int skip = 0, skip_add = 0, scan_return = 0; + // for each APDU + for (int i = 0; i < sizeof(apdu_lengths); i++) { + // scan to next space or end of string + while (Cmd[skip] != ' ' && Cmd[skip] != '\0') { + // convert + scan_return = sscanf(Cmd + skip, "%2X%n", + (unsigned int *) (apdus[i] + apdu_lengths[i]), + &skip_add); + if (scan_return < 1) { + PrintAndLog((char *)usage_msg); + PrintAndLog("Not enough APDUs! Try again!"); + return 0; + } + skip += skip_add; + apdu_lengths[i]++; + } + + // break on EOF + if (Cmd[skip] == '\0') { + if (i < sizeof(apdu_lengths) - 1) { + + PrintAndLog((char *)usage_msg); + return 0; + } + break; + } + // skip the space + skip++; + } + + // transfer the APDUs to the Proxmark + UsbCommand usb_cmd; + usb_cmd.cmd = CMD_EPA_PACE_REPLAY; + for (int i = 0; i < sizeof(apdu_lengths); i++) { + // APDU number + usb_cmd.arg[0] = i + 1; + // transfer the APDU in several parts if necessary + for (int j = 0; j * sizeof(usb_cmd.d.asBytes) < apdu_lengths[i]; j++) { + // offset into the APDU + usb_cmd.arg[1] = j * sizeof(usb_cmd.d.asBytes); + // amount of data in this packet + int packet_length = apdu_lengths[i] - (j * sizeof(usb_cmd.d.asBytes)); + if (packet_length > sizeof(usb_cmd.d.asBytes)) { + packet_length = sizeof(usb_cmd.d.asBytes); + } + usb_cmd.arg[2] = packet_length; + + memcpy(usb_cmd.d.asBytes, // + (j * sizeof(usb_cmd.d.asBytes)), + apdus[i] + (j * sizeof(usb_cmd.d.asBytes)), + packet_length); + SendCommand(&usb_cmd); + WaitForResponse(CMD_ACK, &resp); + if (resp.arg[0] != 0) { + PrintAndLog("Transfer of APDU #%d Part %d failed!", i, j); + return 0; + } + } + } + + // now perform the replay + usb_cmd.arg[0] = 0; + SendCommand(&usb_cmd); + WaitForResponse(CMD_ACK, &resp); + if (resp.arg[0] != 0) { + PrintAndLog("\nPACE replay failed in step %u!", (uint32_t)resp.arg[0]); + PrintAndLog("Measured times:"); + PrintAndLog("MSE Set AT: %u us", resp.d.asDwords[0]); + PrintAndLog("GA Get Nonce: %u us", resp.d.asDwords[1]); + PrintAndLog("GA Map Nonce: %u us", resp.d.asDwords[2]); + PrintAndLog("GA Perform Key Agreement: %u us", resp.d.asDwords[3]); + PrintAndLog("GA Mutual Authenticate: %u us", resp.d.asDwords[4]); + } else { + PrintAndLog("PACE replay successfull!"); + PrintAndLog("MSE Set AT: %u us", resp.d.asDwords[0]); + PrintAndLog("GA Get Nonce: %u us", resp.d.asDwords[1]); + PrintAndLog("GA Map Nonce: %u us", resp.d.asDwords[2]); + PrintAndLog("GA Perform Key Agreement: %u us", resp.d.asDwords[3]); + PrintAndLog("GA Mutual Authenticate: %u us", resp.d.asDwords[4]); + } + + + return 1; +} + +////////////////////////////////The new commands lie above here///////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // UI-related stuff -static const command_t CommandTable[] = +static const command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"cnonces", CmdHFEPACollectPACENonces, 0, " Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses"}, + {"preplay", CmdHFEPAPACEReplay, 0, + " Perform PACE protocol by replaying given APDUs"}, {NULL, NULL, 0, NULL} }; @@ -92,4 +202,4 @@ int CmdHFEPA(const char *Cmd) // parse CmdsParse(CommandTable, Cmd); return 0; -} \ No newline at end of file +} diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 2b5a5b87..5abda060 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1750,10 +1750,13 @@ int CmdHF14AMfCSave(const char *Cmd) { // get filename if (mfCGetBlock(0, buf, CSETBLOCK_SINGLE_OPER)) { PrintAndLog("Cant get block: %d", 0); - return 1; + len = sprintf(fnameptr, "dump"); + fnameptr += len; + } + else { + for (j = 0; j < 7; j++, fnameptr += 2) + sprintf(fnameptr, "%02x", buf[j]); } - for (j = 0; j < 7; j++, fnameptr += 2) - sprintf(fnameptr, "%02x", buf[j]); } else { memcpy(filename, Cmd, len); fnameptr += len; diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 19103298..25a073d3 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -16,16 +16,19 @@ #include "protocols.h" #include "data.h" -#define MAX_UL_BLOCKS 0x0f -#define MAX_ULC_BLOCKS 0x2b -#define MAX_ULEV1a_BLOCKS 0x13 -#define MAX_ULEV1b_BLOCKS 0x28 -#define MAX_NTAG_203 0x29 -#define MAX_NTAG_210 0x13 -#define MAX_NTAG_212 0x28 -#define MAX_NTAG_213 0x2c -#define MAX_NTAG_215 0x86 -#define MAX_NTAG_216 0xe6 +#define MAX_UL_BLOCKS 0x0f +#define MAX_ULC_BLOCKS 0x2b +#define MAX_ULEV1a_BLOCKS 0x13 +#define MAX_ULEV1b_BLOCKS 0x28 +#define MAX_NTAG_203 0x29 +#define MAX_NTAG_210 0x13 +#define MAX_NTAG_212 0x28 +#define MAX_NTAG_213 0x2c +#define MAX_NTAG_215 0x86 +#define MAX_NTAG_216 0xe6 +#define MAX_MY_D_NFC 0xff +#define MAX_MY_D_MOVE 0x25 +#define MAX_MY_D_MOVE_LEAN 0x0f #define KEYS_3DES_COUNT 7 uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { @@ -54,17 +57,18 @@ uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0x32,0x0C,0x16,0x17}, // PACK 0x80,0x80 -- AMiiboo (sniffed) }; -#define MAX_UL_TYPES 16 -uint16_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, - NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC}; +#define MAX_UL_TYPES 18 +uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, + NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, - MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_UL_BLOCKS}; + MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; static int CmdHelp(const char *Cmd); +// get version nxp product type char *getProductTypeStr( uint8_t id){ static char buf[20]; @@ -102,17 +106,20 @@ char *getUlev1CardSizeStr( uint8_t fsize ){ static void ul_switch_on_field(void) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; + clearCommandBuffer(); SendCommand(&c); } void ul_switch_off_field(void) { UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; + clearCommandBuffer(); SendCommand(&c); } static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength ) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_APPEND_CRC, cmdlen, 0}}; memcpy(c.d.asBytes, cmd, cmdlen); + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; @@ -129,6 +136,7 @@ static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, c.arg[0] |= ISO14A_APPEND_CRC; memcpy(c.d.asBytes, cmd, cmdlen); + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; @@ -193,6 +201,7 @@ static int ulc_authentication( uint8_t *key, bool switch_off_field ){ UsbCommand c = {CMD_MIFAREUC_AUTH, {switch_off_field}}; memcpy(c.d.asBytes, key, 16); + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if ( !WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) return 0; @@ -267,6 +276,38 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ return len; } + +// Fudan check checks for which error is given for a command with incorrect crc +// NXP UL chip responds with 01, fudan 00. +// other possible checks: +// send a0 + crc +// UL responds with 00, fudan doesn't respond +// or +// send a200 + crc +// UL doesn't respond, fudan responds with 00 +// or +// send 300000 + crc (read with extra byte(s)) +// UL responds with read of page 0, fudan doesn't respond. +// +// make sure field is off before calling this function +static int ul_fudan_check( void ){ + iso14a_card_select_t card; + if ( !ul_select(&card) ) + return UL_ERROR; + + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}}; + + uint8_t cmd[4] = {0x30,0x00,0x02,0xa7}; //wrong crc on purpose should be 0xa8 + memcpy(c.d.asBytes, cmd, 4); + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return UL_ERROR; + if (resp.arg[0] != 1) return UL_ERROR; + + return (!resp.d.asBytes[0]) ? FUDAN_UL : UL; //if response == 0x00 then Fudan, else Genuine NXP +} + static int ul_print_default( uint8_t *data){ uint8_t uid[7]; @@ -279,13 +320,13 @@ static int ul_print_default( uint8_t *data){ uid[6] = data[7]; PrintAndLog(" UID : %s ", sprint_hex(uid, 7)); - PrintAndLog(" UID[0] : %02X, Manufacturer: %s", uid[0], getTagInfo(uid[0]) ); - if ( uid[0] == 0x05 ) { + PrintAndLog(" UID[0] : %02X, %s", uid[0], getTagInfo(uid[0]) ); + if ( uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ - case 0xc2: PrintAndLog(" IC type : SLE 66R04P"); break; - case 0xc4: PrintAndLog(" IC type : SLE 66R16P"); break; - case 0xc6: PrintAndLog(" IC type : SLE 66R32P"); break; + case 0xc2: PrintAndLog(" IC type : SLE 66R04P 770 Bytes"); break; //77 pages + case 0xc4: PrintAndLog(" IC type : SLE 66R16P 2560 Bytes"); break; //256 pages + case 0xc6: PrintAndLog(" IC type : SLE 66R32P 5120 Bytes"); break; //512 pages /2 sectors } } // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 @@ -371,13 +412,17 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces){ else if ( tagtype & NTAG_I2C_2K ) PrintAndLog("%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); else if ( tagtype & MY_D ) - PrintAndLog("%sTYPE : INFINEON my-d\x99", spacer); + PrintAndLog("%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); else if ( tagtype & MY_D_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 NFC", spacer); + PrintAndLog("%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); else if ( tagtype & MY_D_MOVE ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move", spacer); + PrintAndLog("%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); else if ( tagtype & MY_D_MOVE_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC", spacer); + PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); + else if ( tagtype & MY_D_MOVE_LEAN ) + PrintAndLog("%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); + else if ( tagtype & FUDAN_UL ) + PrintAndLog("%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else PrintAndLog("%sTYPE : Unknown %06x", spacer, tagtype); return 0; @@ -611,13 +656,20 @@ uint32_t GetHF14AMfU_Type(void){ ul_switch_off_field(); } } + if (tagtype & UL) { + tagtype = ul_fudan_check(); + ul_switch_off_field(); + } } else { + ul_switch_off_field(); // Infinition MY-D tests Exam high nibble uint8_t nib = (card.uid[1] & 0xf0) >> 4; switch ( nib ){ - case 1: tagtype = MY_D; break; - case 2: tagtype = (MY_D | MY_D_NFC); break; //notice: we can not currently distinguish between these two - case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //notice: we can not currently distinguish between these two + // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k + case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... + case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) + case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two + case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes } } @@ -839,105 +891,239 @@ int CmdHF14AMfUInfo(const char *Cmd){ } // -// Mifare Ultralight Write Single Block +// Write Single Block // int CmdHF14AMfUWrBl(const char *Cmd){ - uint8_t blockNo = -1; - bool chinese_card = FALSE; - uint8_t bldata[16] = {0x00}; - UsbCommand resp; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu wrbl [w]"); - PrintAndLog(" [block number]"); - PrintAndLog(" [block data] - (8 hex symbols)"); - PrintAndLog(" [w] - Chinese magic ultralight tag"); - PrintAndLog(""); - PrintAndLog(" sample: hf mfu wrbl 0 01020304"); - PrintAndLog(""); - return 0; - } - - blockNo = param_get8(Cmd, 0); + int blockNo = -1; + bool errors = false; + bool hasAuthKey = false; + bool hasPwdKey = false; + bool swapEndian = false; - if (blockNo > MAX_UL_BLOCKS){ - PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); - return 1; + uint8_t cmdp = 0; + uint8_t keylen = 0; + uint8_t blockdata[20] = {0x00}; + uint8_t data[16] = {0x00}; + uint8_t authenticationkey[16] = {0x00}; + uint8_t *authKeyPtr = authenticationkey; + + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_mfu_wrbl(); + case 'k': + case 'K': + // EV1/NTAG size key + keylen = param_gethex(Cmd, cmdp+1, data, 8); + if ( !keylen ) { + memcpy(authenticationkey, data, 4); + cmdp += 2; + hasPwdKey = true; + break; + } + // UL-C size key + keylen = param_gethex(Cmd, cmdp+1, data, 32); + if (!keylen){ + memcpy(authenticationkey, data, 16); + cmdp += 2; + hasAuthKey = true; + break; + } + PrintAndLog("\nERROR: Key is incorrect length\n"); + errors = true; + break; + case 'b': + case 'B': + blockNo = param_get8(Cmd, cmdp+1); + if (blockNo < 0) { + PrintAndLog("Wrong block number"); + errors = true; + } + cmdp += 2; + break; + case 'l': + case 'L': + swapEndian = true; + cmdp++; + break; + case 'd': + case 'D': + if ( param_gethex(Cmd, cmdp+1, blockdata, 8) ) { + PrintAndLog("Block data must include 8 HEX symbols"); + errors = true; + break; + } + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + //Validations + if(errors) return usage_hf_mfu_wrbl(); } - - if (param_gethex(Cmd, 1, bldata, 8)) { - PrintAndLog("Block data must include 8 HEX symbols"); - return 1; + + if ( blockNo == -1 ) return usage_hf_mfu_wrbl(); + // starting with getting tagtype + TagTypeUL_t tagtype = GetHF14AMfU_Type(); + if (tagtype == UL_ERROR) return -1; + + uint8_t maxblockno = 0; + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ + if (tagtype & UL_TYPES_ARRAY[idx]) + maxblockno = UL_MEMORY_ARRAY[idx]; } - - if (strchr(Cmd,'w') != 0 || strchr(Cmd,'W') != 0 ) { - chinese_card = TRUE; + if (blockNo > maxblockno){ + PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + return usage_hf_mfu_wrbl(); } - - if ( blockNo <= 3) { - if (!chinese_card){ - PrintAndLog("Access Denied"); - } else { - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } + + // Swap endianness + if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); + if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + + if ( blockNo <= 3) + PrintAndLog("Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + else + PrintAndLog("Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + + //Send write Block + UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(c.d.asBytes,blockdata,4); + + if ( hasAuthKey ) { + c.arg[1] = 1; + memcpy(c.d.asBytes+4,authKeyPtr,16); + } + else if ( hasPwdKey ) { + c.arg[1] = 2; + memcpy(c.d.asBytes+4,authKeyPtr,4); + } + + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); } else { - PrintAndLog("--block no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(e.d.asBytes,bldata, 4); - SendCommand(&e); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } + PrintAndLog("Command execute timeout"); } + return 0; } - // -// Mifare Ultralight Read Single Block +// Read Single Block // int CmdHF14AMfURdBl(const char *Cmd){ - UsbCommand resp; - uint8_t blockNo = -1; - char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu rdbl "); - PrintAndLog(" sample: hfu mfu rdbl 0"); - return 0; + int blockNo = -1; + bool errors = false; + bool hasAuthKey = false; + bool hasPwdKey = false; + bool swapEndian = false; + uint8_t cmdp = 0; + uint8_t keylen = 0; + uint8_t data[16] = {0x00}; + uint8_t authenticationkey[16] = {0x00}; + uint8_t *authKeyPtr = authenticationkey; + + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_mfu_rdbl(); + case 'k': + case 'K': + // EV1/NTAG size key + keylen = param_gethex(Cmd, cmdp+1, data, 8); + if ( !keylen ) { + memcpy(authenticationkey, data, 4); + cmdp += 2; + hasPwdKey = true; + break; + } + // UL-C size key + keylen = param_gethex(Cmd, cmdp+1, data, 32); + if (!keylen){ + memcpy(authenticationkey, data, 16); + cmdp += 2; + hasAuthKey = true; + break; + } + PrintAndLog("\nERROR: Key is incorrect length\n"); + errors = true; + break; + case 'b': + case 'B': + blockNo = param_get8(Cmd, cmdp+1); + if (blockNo < 0) { + PrintAndLog("Wrong block number"); + errors = true; + } + cmdp += 2; + break; + case 'l': + case 'L': + swapEndian = true; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + //Validations + if(errors) return usage_hf_mfu_rdbl(); } - blockNo = param_get8(Cmd, 0); + if ( blockNo == -1 ) return usage_hf_mfu_rdbl(); + // start with getting tagtype + TagTypeUL_t tagtype = GetHF14AMfU_Type(); + if (tagtype == UL_ERROR) return -1; - if (blockNo > MAX_UL_BLOCKS){ - PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight"); - return 1; + uint8_t maxblockno = 0; + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ + if (tagtype & UL_TYPES_ARRAY[idx]) + maxblockno = UL_MEMORY_ARRAY[idx]; + } + if (blockNo > maxblockno){ + PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + return usage_hf_mfu_rdbl(); } - UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; - SendCommand(&c); + // Swap endianness + if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); + if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + //Read Block + UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; + if ( hasAuthKey ){ + c.arg[1] = 1; + memcpy(c.d.asBytes,authKeyPtr,16); + } + else if ( hasPwdKey ) { + c.arg[1] = 2; + memcpy(c.d.asBytes,authKeyPtr,4); + } + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { uint8_t isOK = resp.arg[0] & 0xff; if (isOK) { uint8_t *data = resp.d.asBytes; - PrintAndLog("Block: %0d (0x%02X) [ %s]", (int)blockNo, blockNo, sprint_hex(data, 4)); + PrintAndLog("\nBlock# | Data | Ascii"); + PrintAndLog("-----------------------------"); + PrintAndLog("%02d/0x%02X | %s| %.4s\n", blockNo, blockNo, sprint_hex(data, 4), data); } else { PrintAndLog("Failed reading block: (%02x)", isOK); @@ -945,7 +1131,6 @@ int CmdHF14AMfURdBl(const char *Cmd){ } else { PrintAndLog("Command execute time-out"); } - return 0; } @@ -988,6 +1173,34 @@ int usage_hf_mfu_dump(void) { return 0; } +int usage_hf_mfu_rdbl(void) { + PrintAndLog("Read a block and print. It autodetects card type.\n"); + PrintAndLog("Usage: hf mfu rdbl b k l\n"); + PrintAndLog(" Options:"); + PrintAndLog(" b : block to read"); + PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLog(" l : (optional) swap entered key's endianness"); + PrintAndLog(""); + PrintAndLog(" sample : hf mfu rdbl b 0"); + PrintAndLog(" : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"); + PrintAndLog(" : hf mfu rdbl b 0 k AABBCCDDD\n"); + return 0; +} + +int usage_hf_mfu_wrbl(void) { + PrintAndLog("Write a block. It autodetects card type.\n"); + PrintAndLog("Usage: hf mfu wrbl b d k l\n"); + PrintAndLog(" Options:"); + PrintAndLog(" b : block to write"); + PrintAndLog(" d : block data - (8 hex symbols)"); + PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLog(" l : (optional) swap entered key's endianness"); + PrintAndLog(""); + PrintAndLog(" sample : hf mfu wrbl b 0 d 01234567"); + PrintAndLog(" : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n"); + return 0; +} + // // Mifare Ultralight / Ultralight-C / Ultralight-EV1 // Read and Dump Card Contents, using auto detection of tag size. @@ -1079,10 +1292,10 @@ int CmdHF14AMfUDump(const char *Cmd){ TagTypeUL_t tagtype = GetHF14AMfU_Type(); if (tagtype == UL_ERROR) return -1; - if (!manualPages) + if (!manualPages) //get number of pages to read for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) if (tagtype & UL_TYPES_ARRAY[idx]) - Pages = UL_MEMORY_ARRAY[idx]+1; + Pages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 ul_print_type(tagtype, 0); PrintAndLog("Reading tag memory..."); @@ -1095,6 +1308,8 @@ int CmdHF14AMfUDump(const char *Cmd){ memcpy(c.d.asBytes, authKeyPtr, dataLen); } + + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) { @@ -1153,9 +1368,11 @@ int CmdHF14AMfUDump(const char *Cmd){ } } + PrintAndLog("\nBlock# | Data |lck| Ascii"); + PrintAndLog("---------------------------------"); for (i = 0; i < Pages; ++i) { if ( i < 3 ) { - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + PrintAndLog("%02d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); continue; } switch(i){ @@ -1202,8 +1419,9 @@ int CmdHF14AMfUDump(const char *Cmd){ case 43: tmplockbit = bit2[9]; break; //auth1 default: break; } - PrintAndLog("Block %02X:%s [%d] {%.4s}", i, sprint_hex(data + i * 4, 4), tmplockbit, data+i*4); + PrintAndLog("%02d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, data+i*4); } + PrintAndLog("---------------------------------"); // user supplied filename? if (fileNlen < 1) { @@ -1369,142 +1587,6 @@ int CmdTestDES(const char * cmd) } **/ -// -// Ultralight C Read Single Block -// -int CmdHF14AMfUCRdBl(const char *Cmd) -{ - UsbCommand resp; - bool hasPwd = FALSE; - uint8_t blockNo = -1; - uint8_t key[16]; - char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu crdbl "); - PrintAndLog(""); - PrintAndLog("sample: hf mfu crdbl 0"); - PrintAndLog(" hf mfu crdbl 0 00112233445566778899AABBCCDDEEFF"); - return 0; - } - - blockNo = param_get8(Cmd, 0); - if (blockNo < 0) { - PrintAndLog("Wrong block number"); - return 1; - } - - if (blockNo > MAX_ULC_BLOCKS ){ - PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight-C"); - return 1; - } - - // key - if ( strlen(Cmd) > 3){ - if (param_gethex(Cmd, 1, key, 32)) { - PrintAndLog("Key must include %d HEX symbols", 32); - return 1; - } else { - hasPwd = TRUE; - } - } - - //Read Block - UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; - if ( hasPwd ) { - c.arg[1] = 1; - memcpy(c.d.asBytes,key,16); - } - SendCommand(&c); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - if (isOK) { - uint8_t *data = resp.d.asBytes; - PrintAndLog("Block: %0d (0x%02X) [ %s]", (int)blockNo, blockNo, sprint_hex(data, 4)); - } - else { - PrintAndLog("Failed reading block: (%02x)", isOK); - } - } else { - PrintAndLog("Command execute time-out"); - } - return 0; -} - -// -// Mifare Ultralight C Write Single Block -// -int CmdHF14AMfUCWrBl(const char *Cmd){ - - uint8_t blockNo = -1; - bool chinese_card = FALSE; - uint8_t bldata[16] = {0x00}; - UsbCommand resp; - - char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu cwrbl [w]"); - PrintAndLog(" [block number]"); - PrintAndLog(" [block data] - (8 hex symbols)"); - PrintAndLog(" [w] - Chinese magic ultralight tag"); - PrintAndLog(""); - PrintAndLog(" sample: hf mfu cwrbl 0 01020304"); - PrintAndLog(""); - return 0; - } - - blockNo = param_get8(Cmd, 0); - if (blockNo > MAX_ULC_BLOCKS ){ - PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight-C Cards!"); - return 1; - } - - if (param_gethex(Cmd, 1, bldata, 8)) { - PrintAndLog("Block data must include 8 HEX symbols"); - return 1; - } - - if (strchr(Cmd,'w') != 0 || strchr(Cmd,'W') != 0 ) { - chinese_card = TRUE; - } - - if ( blockNo <= 3 ) { - if (!chinese_card){ - PrintAndLog("Access Denied"); - return 1; - } else { - PrintAndLog("--Special block no: 0x%02x", blockNo); - PrintAndLog("--Data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - return 1; - } - } - } else { - PrintAndLog("--Block no : 0x%02x", blockNo); - PrintAndLog("--Data: %s", sprint_hex(bldata, 4)); - UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(e.d.asBytes,bldata, 4); - SendCommand(&e); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk : %02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - return 1; - } - } - return 0; -} - // // Mifare Ultralight C - Set password // @@ -1530,6 +1612,7 @@ int CmdHF14AMfucSetPwd(const char *Cmd){ UsbCommand c = {CMD_MIFAREUC_SETPWD}; memcpy( c.d.asBytes, pwd, 16); + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; @@ -1578,6 +1661,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ // read block2. c.cmd = CMD_MIFAREU_READBL; c.arg[0] = 2; + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { PrintAndLog("Command execute timeout"); @@ -1595,6 +1679,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[1] = uid[1]; c.d.asBytes[2] = uid[2]; c.d.asBytes[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { PrintAndLog("Command execute timeout"); @@ -1607,6 +1692,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[1] = uid[4]; c.d.asBytes[2] = uid[5]; c.d.asBytes[3] = uid[6]; + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { PrintAndLog("Command execute timeout"); @@ -1619,6 +1705,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[1] = oldblock2[1]; c.d.asBytes[2] = oldblock2[2]; c.d.asBytes[3] = oldblock2[3]; + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { PrintAndLog("Command execute timeout"); @@ -1629,10 +1716,10 @@ int CmdHF14AMfucSetUid(const char *Cmd){ } int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ - + uint8_t iv[8] = { 0x00 }; uint8_t block = 0x07; - + // UL-EV1 //04 57 b6 e2 05 3f 80 UID //4a f8 4b 19 PWD @@ -1646,14 +1733,14 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t mix[8] = { 0x00 }; uint8_t divkey[8] = { 0x00 }; - + memcpy(mix, mifarekeyA, 4); - + mix[4] = mifarekeyA[4] ^ uid[0]; mix[5] = mifarekeyA[5] ^ uid[1]; mix[6] = block ^ uid[2]; mix[7] = uid[3]; - + des3_context ctx = { 0x00 }; des3_set2key_enc(&ctx, masterkey); @@ -1672,9 +1759,9 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ PrintAndLog("Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); PrintAndLog("Message :\t %s", sprint_hex(mix, sizeof(mix))); PrintAndLog("Diversified key: %s", sprint_hex(divkey+1, 6)); - + PrintAndLog("\n DES version"); - + for (int i=0; i < sizeof(mifarekeyA); ++i){ dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1); @@ -1692,7 +1779,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ memcpy(dmkey+8, dkeyB, 8); memcpy(dmkey+16, dkeyA, 8); memset(iv, 0x00, 8); - + des3_set3key_enc(&ctx, dmkey); des3_crypt_cbc(&ctx // des3_context @@ -1735,11 +1822,9 @@ static command_t CommandTable[] = {"help", CmdHelp, 1, "This help"}, {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"info", CmdHF14AMfUInfo, 0, "Tag information"}, - {"dump", CmdHF14AMfUDump, 0, "Dump Ultralight / Ultralight-C tag to binary file"}, - {"rdbl", CmdHF14AMfURdBl, 0, "Read block - Ultralight"}, - {"wrbl", CmdHF14AMfUWrBl, 0, "Write block - Ultralight"}, - {"crdbl", CmdHF14AMfUCRdBl, 0, "Read block - Ultralight C"}, - {"cwrbl", CmdHF14AMfUCWrBl, 0, "Write block - Ultralight C"}, + {"dump", CmdHF14AMfUDump, 0, "Dump Ultralight / Ultralight-C / NTAG tag to binary file"}, + {"rdbl", CmdHF14AMfURdBl, 0, "Read block"}, + {"wrbl", CmdHF14AMfUWrBl, 0, "Write block"}, {"cauth", CmdHF14AMfucAuth, 0, "Authentication - Ultralight C"}, {"setpwd", CmdHF14AMfucSetPwd, 1, "Set 3des password - Ultralight-C"}, {"setuid", CmdHF14AMfucSetUid, 1, "Set UID - MAGIC tags only"}, diff --git a/client/cmdhfmfu.h b/client/cmdhfmfu.h index 83f28403..6c9e3ea1 100644 --- a/client/cmdhfmfu.h +++ b/client/cmdhfmfu.h @@ -4,25 +4,24 @@ #ifndef CMDHFMFU_H__ #define CMDHFMFU_H__ -//standard ultralight int CmdHF14AMfUWrBl(const char *Cmd); int CmdHF14AMfURdBl(const char *Cmd); //Crypto Cards -int CmdHF14AMfUCRdBl(const char *Cmd); -int CmdHF14AMfUCRdCard(const char *Cmd); int CmdHF14AMfucAuth(const char *Cmd); //general stuff int CmdHF14AMfUDump(const char *Cmd); int CmdHF14AMfUInfo(const char *Cmd); -uint32_t GetHF14AMfU_Type(void); +uint32_t GetHF14AMfU_Type(void); int ul_print_type(uint32_t tagtype, uint8_t spacer); void ul_switch_off_field(void); int usage_hf_mfu_dump(void); int usage_hf_mfu_info(void); +int usage_hf_mfu_rdbl(void); +int usage_hf_mfu_wrbl(void); int CmdHFMFUltra(const char *Cmd); @@ -43,9 +42,11 @@ typedef enum TAGTYPE_UL { MY_D_NFC = 0x001000, MY_D_MOVE = 0x002000, MY_D_MOVE_NFC = 0x004000, - NTAG_I2C_1K = 0x008000, - NTAG_I2C_2K = 0x010000, - MAGIC = 0x020000, + MY_D_MOVE_LEAN= 0x008000, + NTAG_I2C_1K = 0x010000, + NTAG_I2C_2K = 0x020000, + FUDAN_UL = 0x040000, + MAGIC = 0x080000, UL_MAGIC = UL | MAGIC, UL_C_MAGIC = UL_C | MAGIC, UL_ERROR = 0xFFFFFF, diff --git a/client/cmdlf.c b/client/cmdlf.c index dfbbe992..edf02932 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -1072,6 +1072,12 @@ int CmdLFfind(const char *Cmd) return 1; } + ans=CmdFDXBdemodBI(""); + if (ans>0) { + PrintAndLog("\nValid FDX-B ID Found!"); + return 1; + } + ans=EM4x50Read("", false); if (ans>0) { PrintAndLog("\nValid EM4x50 ID Found!"); diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index c492a64d..eddeec56 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -20,6 +20,9 @@ #include "cmdlf.h" #include "cmdlfem4x.h" #include "lfdemod.h" + +#define llx PRIx64 + char *global_em410xId; static int CmdHelp(const char *Cmd); diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index d4b72b32..b357e71c 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -50,24 +50,24 @@ int usage_t55xx_config(){ } int usage_t55xx_read(){ PrintAndLog("Usage: lf t55xx read "); - PrintAndLog(" , block number to read. Between 0-7"); - PrintAndLog(" , OPTIONAL password (8 hex characters)"); - PrintAndLog(""); + PrintAndLog(" , block number to read. Between 0-7"); + PrintAndLog(" , OPTIONAL password (8 hex characters)"); + PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx read 0 - read data from block 0"); + PrintAndLog(" lf t55xx read 0 - read data from block 0"); PrintAndLog(" lf t55xx read 0 feedbeef - read data from block 0 password feedbeef"); PrintAndLog(""); return 0; } int usage_t55xx_write(){ PrintAndLog("Usage: lf t55xx wr [password]"); - PrintAndLog(" , block number to read. Between 0-7"); + PrintAndLog(" , block number to write. Between 0-7"); PrintAndLog(" , 4 bytes of data to write (8 hex characters)"); - PrintAndLog(" [password], OPTIONAL password 4bytes (8 hex characters)"); - PrintAndLog(""); + PrintAndLog(" [password], OPTIONAL password 4bytes (8 hex characters)"); + PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx wd 3 11223344 - write 11223344 to block 3"); - PrintAndLog(" lf t55xx wd 3 11223344 feedbeef - write 11223344 to block 3 password feedbeef"); + PrintAndLog(" lf t55xx wr 3 11223344 - write 11223344 to block 3"); + PrintAndLog(" lf t55xx wr 3 11223344 feedbeef - write 11223344 to block 3 password feedbeef"); PrintAndLog(""); return 0; } diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h index c5b91f99..b3a7f4ec 100644 --- a/client/hid-flasher/usb_cmd.h +++ b/client/hid-flasher/usb_cmd.h @@ -89,7 +89,6 @@ typedef struct { // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 -#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 0x0301 #define CMD_READ_SRI512_TAG 0x0303 #define CMD_READ_SRIX4K_TAG 0x0304 #define CMD_READER_ISO_15693 0x0310 @@ -105,9 +104,8 @@ typedef struct { #define CMD_SIMULATE_HITAG 0x0371 #define CMD_READER_HITAG 0x0372 -#define CMD_SIMULATE_TAG_HF_LISTEN 0x0380 -#define CMD_SIMULATE_TAG_ISO_14443 0x0381 -#define CMD_SNOOP_ISO_14443 0x0382 +#define CMD_SIMULATE_TAG_ISO_14443B 0x0381 +#define CMD_SNOOP_ISO_14443B 0x0382 #define CMD_SNOOP_ISO_14443a 0x0383 #define CMD_SIMULATE_TAG_ISO_14443a 0x0384 #define CMD_READER_ISO_14443a 0x0385 diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index 678c745e..4c7bc638 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -59,7 +59,6 @@ local _commands = { --// For the 13.56 MHz tags CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 = 0x0300, - CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 = 0x0301, CMD_READ_SRI512_TAG = 0x0303, CMD_READ_SRIX4K_TAG = 0x0304, CMD_READER_ISO_15693 = 0x0310, @@ -76,9 +75,8 @@ local _commands = { CMD_SIMULATE_HITAG = 0x0371, CMD_READER_HITAG = 0x0372, - CMD_SIMULATE_TAG_HF_LISTEN = 0x0380, - CMD_SIMULATE_TAG_ISO_14443 = 0x0381, - CMD_SNOOP_ISO_14443 = 0x0382, + CMD_SIMULATE_TAG_ISO_14443B = 0x0381, + CMD_SNOOP_ISO_14443B = 0x0382, CMD_SNOOP_ISO_14443a = 0x0383, CMD_SIMULATE_TAG_ISO_14443a = 0x0384, CMD_READER_ISO_14443a = 0x0385, diff --git a/client/lualibs/utils.lua b/client/lualibs/utils.lua index a968fde2..592d0477 100644 --- a/client/lualibs/utils.lua +++ b/client/lualibs/utils.lua @@ -99,6 +99,32 @@ local Utils = end return nil end, + + ------------ SHA1 hash + -- Takes a string and calculates a SHA1 hash + Sha1 = function(s) + if s == nil then return nil end + if #s == 0 then return nil end + if type(s) == 'string' then + local utils = require('utils') + --local asc = utils.ConvertHexToAscii(s) + local hash = core.sha1(s) + return hash + end + return nil + end, + -- Takes a hex string and calculates a SHA1 hash + Sha1Hex = function(s) + if s == nil then return nil end + if #s == 0 then return nil end + if type(s) == 'string' then + local utils = require('utils') + local asc = utils.ConvertHexToAscii(s) + local hash = core.sha1(asc) + return hash + end + return nil + end, -- input parameter is a string @@ -288,4 +314,4 @@ local Utils = -- end } -return Utils \ No newline at end of file +return Utils diff --git a/client/scripting.c b/client/scripting.c index 152fd9d4..6b26ec59 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -20,6 +20,7 @@ #include "../common/iso15693tools.h" #include "../common/crc16.h" #include "../common/crc64.h" +#include "../common/sha1.h" #include "aes.h" /** * The following params expected: @@ -231,7 +232,7 @@ static int l_iso15693_crc(lua_State *L) Simple AES 128 cbc hook up to OpenSSL. params: key, input */ -static int l_aes128decrypt(lua_State *L) +static int l_aes128decrypt_cbc(lua_State *L) { //Check number of arguments int i; @@ -260,7 +261,36 @@ static int l_aes128decrypt(lua_State *L) lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); return 1;// return 1 to signal one return value } -static int l_aes128encrypt(lua_State *L) +static int l_aes128decrypt_ecb(lua_State *L) +{ + //Check number of arguments + int i; + size_t size; + const char *p_key = luaL_checklstring(L, 1, &size); + if(size != 32) return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size); + + const char *p_encTxt = luaL_checklstring(L, 2, &size); + + unsigned char indata[16] = {0x00}; + unsigned char outdata[16] = {0x00}; + unsigned char aes_key[16] = {0x00}; + + // convert key to bytearray and convert input to bytearray + for (i = 0; i < 32; i += 2) { + sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]); + sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]); + } + aes_context ctx; + aes_init(&ctx); + aes_setkey_dec(&ctx, aes_key, 128); + aes_crypt_ecb(&ctx, AES_DECRYPT, indata, outdata ); + + //Push decrypted array as a string + lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); + return 1;// return 1 to signal one return value +} + +static int l_aes128encrypt_cbc(lua_State *L) { //Check number of arguments int i; @@ -289,6 +319,33 @@ static int l_aes128encrypt(lua_State *L) return 1;// return 1 to signal one return value } +static int l_aes128encrypt_ecb(lua_State *L) +{ + //Check number of arguments + int i; + size_t size; + const char *p_key = luaL_checklstring(L, 1, &size); + if(size != 32) return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size); + + const char *p_txt = luaL_checklstring(L, 2, &size); + + unsigned char indata[16] = {0x00}; + unsigned char outdata[16] = {0x00}; + unsigned char aes_key[16] = {0x00}; + + for (i = 0; i < 32; i += 2) { + sscanf(&p_txt[i], "%02x", (unsigned int *)&indata[i / 2]); + sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]); + } + aes_context ctx; + aes_init(&ctx); + aes_setkey_enc(&ctx, aes_key, 128); + aes_crypt_ecb(&ctx, AES_ENCRYPT, indata, outdata ); + //Push encrypted array as a string + lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); + return 1;// return 1 to signal one return value +} + static int l_crc16(lua_State *L) { size_t size; @@ -321,6 +378,16 @@ static int l_crc64(lua_State *L) return 1; } +static int l_sha1(lua_State *L) +{ + size_t size; + const char *p_str = luaL_checklstring(L, 1, &size); + unsigned char outdata[20] = {0x00}; + sha1( (uint8_t*) p_str, size, outdata); + lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); + return 1; +} + /** * @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be * able to do "require('foobar')" if foobar.lua is within lualibs folder. @@ -359,10 +426,13 @@ int set_pm3_libraries(lua_State *L) {"clearCommandBuffer", l_clearCommandBuffer}, {"console", l_CmdConsole}, {"iso15693_crc", l_iso15693_crc}, - {"aes128_decrypt", l_aes128decrypt}, - {"aes128_encrypt", l_aes128encrypt}, + {"aes128_decrypt", l_aes128decrypt_cbc}, + {"aes128_decrypt_ecb", l_aes128decrypt_ecb}, + {"aes128_encrypt", l_aes128encrypt_cbc}, + {"aes128_encrypt_ecb", l_aes128encrypt_ecb}, {"crc16", l_crc16}, {"crc64", l_crc64}, + {"sha1", l_sha1}, {NULL, NULL} }; diff --git a/client/scripts/didump.lua b/client/scripts/didump.lua new file mode 100644 index 00000000..2386d42d --- /dev/null +++ b/client/scripts/didump.lua @@ -0,0 +1,473 @@ +local cmds = require('commands') +local getopt = require('getopt') +local utils = require('utils') +local lib14a = require('read14a') + +example =[[ + script run didump + script run didump -k aabbccddeeff +]] +author = "Iceman" +usage = "script run didump -k " +desc = [[ +This is a script to dump and decrypt the data of a specific type of Mifare Mini token. + +Arguments: + -h : this help + -k : Mifare Key A. +]] + +local band=bit32.band +local bor=bit32.bor +local bnot=bit32.bnot +local bxor=bit32.bxor +local lshift=bit32.lshift +local rshift=bit32.rshift + +local FOO = 'AF62D2EC0491968CC52A1A7165F865FE' +local BAR = '286329204469736E65792032303133' +local RANDOM = FOO..BAR +local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S"); +local TIMEOUT = 2000 +local DEBUG = false +local numBlocks = 20 +local numSectors = 5 +local CHECKSUM_OFFSET = 12; -- +1??? +--- +-- A debug printout-function +function dbg(args) + if DEBUG then + print("###", args) + end +end +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) + core.clearCommandBuffer() +end +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end +--- +-- Get checksum, +-- called: data is string (32 hex digits) +-- returns: number +local function getChecksum(data) + local chksum = data:sub(25,32) + return tonumber(chksum,16) +end +--- +-- calculate checksum +-- called: data is bytes (24 hex digits) +-- returns: number +local function calculateChecksum(data) + + -- Generate table + local _tbl = {} +_tbl[0] = { 0x0 } +_tbl[1] = { 0x77073096 } +_tbl[2] = { 0xEE0E612C } +_tbl[3] = { 0x990951BA } +_tbl[4] = { 0x76DC419 } +_tbl[5] = { 0x706AF48F } +_tbl[6] = { 0xE963A535 } +_tbl[7] = { 0x9E6495A3 } +_tbl[8] = { 0xEDB8832 } +_tbl[9] = { 0x79DCB8A4 } +_tbl[10] = { 0xE0D5E91E } +_tbl[11] = { 0x97D2D988 } +_tbl[12] = { 0x9B64C2B } +_tbl[13] = { 0x7EB17CBD } +_tbl[14] = { 0xE7B82D07 } +_tbl[15] = { 0x90BF1D91 } +_tbl[16] = { 0x1DB71064 } +_tbl[17] = { 0x6AB020F2 } +_tbl[18] = { 0xF3B97148 } +_tbl[19] = { 0x84BE41DE } +_tbl[20] = { 0x1ADAD47D } +_tbl[21] = { 0x6DDDE4EB } +_tbl[22] = { 0xF4D4B551 } +_tbl[23] = { 0x83D385C7 } +_tbl[24] = { 0x136C9856 } +_tbl[25] = { 0x646BA8C0 } +_tbl[26] = { 0xFD62F97A } +_tbl[27] = { 0x8A65C9EC } +_tbl[28] = { 0x14015C4F } +_tbl[29] = { 0x63066CD9 } +_tbl[30] = { 0xFA0F3D63 } +_tbl[31] = { 0x8D080DF5 } +_tbl[32] = { 0x3B6E20C8 } +_tbl[33] = { 0x4C69105E } +_tbl[34] = { 0xD56041E4 } +_tbl[35] = { 0xA2677172 } +_tbl[36] = { 0x3C03E4D1 } +_tbl[37] = { 0x4B04D447 } +_tbl[38] = { 0xD20D85FD } +_tbl[39] = { 0xA50AB56B } +_tbl[40] = { 0x35B5A8FA } +_tbl[41] = { 0x42B2986C } +_tbl[42] = { 0xDBBBC9D6 } +_tbl[43] = { 0xACBCF940 } +_tbl[44] = { 0x32D86CE3 } +_tbl[45] = { 0x45DF5C75 } +_tbl[46] = { 0xDCD60DCF } +_tbl[47] = { 0xABD13D59 } +_tbl[48] = { 0x26D930AC } +_tbl[49] = { 0x51DE003A } +_tbl[50] = { 0xC8D75180 } +_tbl[51] = { 0xBFD06116 } +_tbl[52] = { 0x21B4F4B5 } +_tbl[53] = { 0x56B3C423 } +_tbl[54] = { 0xCFBA9599 } +_tbl[55] = { 0xB8BDA50F } +_tbl[56] = { 0x2802B89E } +_tbl[57] = { 0x5F058808 } +_tbl[58] = { 0xC60CD9B2 } +_tbl[59] = { 0xB10BE924 } +_tbl[60] = { 0x2F6F7C87 } +_tbl[61] = { 0x58684C11 } +_tbl[62] = { 0xC1611DAB } +_tbl[63] = { 0xB6662D3D } +_tbl[64] = { 0x76DC4190 } +_tbl[65] = { 0x1DB7106 } +_tbl[66] = { 0x98D220BC } +_tbl[67] = { 0xEFD5102A } +_tbl[68] = { 0x71B18589 } +_tbl[69] = { 0x6B6B51F } +_tbl[70] = { 0x9FBFE4A5 } +_tbl[71] = { 0xE8B8D433 } +_tbl[72] = { 0x7807C9A2 } +_tbl[73] = { 0xF00F934 } +_tbl[74] = { 0x9609A88E } +_tbl[75] = { 0xE10E9818 } +_tbl[76] = { 0x7F6A0DBB } +_tbl[77] = { 0x86D3D2D } +_tbl[78] = { 0x91646C97 } +_tbl[79] = { 0xE6635C01 } +_tbl[80] = { 0x6B6B51F4 } +_tbl[81] = { 0x1C6C6162 } +_tbl[82] = { 0x856530D8 } +_tbl[83] = { 0xF262004E } +_tbl[84] = { 0x6C0695ED } +_tbl[85] = { 0x1B01A57B } +_tbl[86] = { 0x8208F4C1 } +_tbl[87] = { 0xF50FC457 } +_tbl[88] = { 0x65B0D9C6 } +_tbl[89] = { 0x12B7E950 } +_tbl[90] = { 0x8BBEB8EA } +_tbl[91] = { 0xFCB9887C } +_tbl[92] = { 0x62DD1DDF } +_tbl[93] = { 0x15DA2D49 } +_tbl[94] = { 0x8CD37CF3 } +_tbl[95] = { 0xFBD44C65 } +_tbl[96] = { 0x4DB26158 } +_tbl[97] = { 0x3AB551CE } +_tbl[98] = { 0xA3BC0074 } +_tbl[99] = { 0xD4BB30E2 } +_tbl[100] = { 0x4ADFA541 } +_tbl[101] = { 0x3DD895D7 } +_tbl[102] = { 0xA4D1C46D } +_tbl[103] = { 0xD3D6F4FB } +_tbl[104] = { 0x4369E96A } +_tbl[105] = { 0x346ED9FC } +_tbl[106] = { 0xAD678846 } +_tbl[107] = { 0xDA60B8D0 } +_tbl[108] = { 0x44042D73 } +_tbl[109] = { 0x33031DE5 } +_tbl[110] = { 0xAA0A4C5F } +_tbl[111] = { 0xDD0D7CC9 } +_tbl[112] = { 0x5005713C } +_tbl[113] = { 0x270241AA } +_tbl[114] = { 0xBE0B1010 } +_tbl[115] = { 0xC90C2086 } +_tbl[116] = { 0x5768B525 } +_tbl[117] = { 0x206F85B3 } +_tbl[118] = { 0xB966D409 } +_tbl[119] = { 0xCE61E49F } +_tbl[120] = { 0x5EDEF90E } +_tbl[121] = { 0x29D9C998 } +_tbl[122] = { 0xB0D09822 } +_tbl[123] = { 0xC7D7A8B4 } +_tbl[124] = { 0x59B33D17 } +_tbl[125] = { 0x2EB40D81 } +_tbl[126] = { 0xB7BD5C3B } +_tbl[127] = { 0xC0BA6CAD } +_tbl[128] = { 0xEDB88320 } +_tbl[129] = { 0x9ABFB3B6 } +_tbl[130] = { 0x3B6E20C } +_tbl[131] = { 0x74B1D29A } +_tbl[132] = { 0xEAD54739 } +_tbl[133] = { 0x9DD277AF } +_tbl[134] = { 0x4DB2615 } +_tbl[135] = { 0x73DC1683 } +_tbl[136] = { 0xE3630B12 } +_tbl[137] = { 0x94643B84 } +_tbl[138] = { 0xD6D6A3E } +_tbl[139] = { 0x7A6A5AA8 } +_tbl[140] = { 0xE40ECF0B } +_tbl[141] = { 0x9309FF9D } +_tbl[142] = { 0xA00AE27 } +_tbl[143] = { 0x7D079EB1 } +_tbl[144] = { 0xF00F9344 } +_tbl[145] = { 0x8708A3D2 } +_tbl[146] = { 0x1E01F268 } +_tbl[147] = { 0x6906C2FE } +_tbl[148] = { 0xF762575D } +_tbl[149] = { 0x806567CB } +_tbl[150] = { 0x196C3671 } +_tbl[151] = { 0x6E6B06E7 } +_tbl[152] = { 0xFED41B76 } +_tbl[153] = { 0x89D32BE0 } +_tbl[154] = { 0x10DA7A5A } +_tbl[155] = { 0x67DD4ACC } +_tbl[156] = { 0xF9B9DF6F } +_tbl[157] = { 0x8EBEEFF9 } +_tbl[158] = { 0x17B7BE43 } +_tbl[159] = { 0x60B08ED5 } +_tbl[160] = { 0xD6D6A3E8 } +_tbl[161] = { 0xA1D1937E } +_tbl[162] = { 0x38D8C2C4 } +_tbl[163] = { 0x4FDFF252 } +_tbl[164] = { 0xD1BB67F1 } +_tbl[165] = { 0xA6BC5767 } +_tbl[166] = { 0x3FB506DD } +_tbl[167] = { 0x48B2364B } +_tbl[168] = { 0xD80D2BDA } +_tbl[169] = { 0xAF0A1B4C } +_tbl[170] = { 0x36034AF6 } +_tbl[171] = { 0x41047A60 } +_tbl[172] = { 0xDF60EFC3 } +_tbl[173] = { 0xA867DF55 } +_tbl[174] = { 0x316E8EEF } +_tbl[175] = { 0x4669BE79 } +_tbl[176] = { 0xCB61B38C } +_tbl[177] = { 0xBC66831A } +_tbl[178] = { 0x256FD2A0 } +_tbl[179] = { 0x5268E236 } +_tbl[180] = { 0xCC0C7795 } +_tbl[181] = { 0xBB0B4703 } +_tbl[182] = { 0x220216B9 } +_tbl[183] = { 0x5505262F } +_tbl[184] = { 0xC5BA3BBE } +_tbl[185] = { 0xB2BD0B28 } +_tbl[186] = { 0x2BB45A92 } +_tbl[187] = { 0x5CB36A04 } +_tbl[188] = { 0xC2D7FFA7 } +_tbl[189] = { 0xB5D0CF31 } +_tbl[190] = { 0x2CD99E8B } +_tbl[191] = { 0x5BDEAE1D } +_tbl[192] = { 0x9B64C2B0 } +_tbl[193] = { 0xEC63F226 } +_tbl[194] = { 0x756AA39C } +_tbl[195] = { 0x26D930A } +_tbl[196] = { 0x9C0906A9 } +_tbl[197] = { 0xEB0E363F } +_tbl[198] = { 0x72076785 } +_tbl[199] = { 0x5005713 } +_tbl[200] = { 0x95BF4A82 } +_tbl[201] = { 0xE2B87A14 } +_tbl[202] = { 0x7BB12BAE } +_tbl[203] = { 0xCB61B38 } +_tbl[204] = { 0x92D28E9B } +_tbl[205] = { 0xE5D5BE0D } +_tbl[206] = { 0x7CDCEFB7 } +_tbl[207] = { 0xBDBDF21 } +_tbl[208] = { 0x86D3D2D4 } +_tbl[209] = { 0xF1D4E242 } +_tbl[210] = { 0x68DDB3F8 } +_tbl[211] = { 0x1FDA836E } +_tbl[212] = { 0x81BE16CD } +_tbl[213] = { 0xF6B9265B } +_tbl[214] = { 0x6FB077E1 } +_tbl[215] = { 0x18B74777 } +_tbl[216] = { 0x88085AE6 } +_tbl[217] = { 0xFF0F6A70 } +_tbl[218] = { 0x66063BCA } +_tbl[219] = { 0x11010B5C } +_tbl[220] = { 0x8F659EFF } +_tbl[221] = { 0xF862AE69 } +_tbl[222] = { 0x616BFFD3 } +_tbl[223] = { 0x166CCF45 } +_tbl[224] = { 0xA00AE278 } +_tbl[225] = { 0xD70DD2EE } +_tbl[226] = { 0x4E048354 } +_tbl[227] = { 0x3903B3C2 } +_tbl[228] = { 0xA7672661 } +_tbl[229] = { 0xD06016F7 } +_tbl[230] = { 0x4969474D } +_tbl[231] = { 0x3E6E77DB } +_tbl[232] = { 0xAED16A4A } +_tbl[233] = { 0xD9D65ADC } +_tbl[234] = { 0x40DF0B66 } +_tbl[235] = { 0x37D83BF0 } +_tbl[236] = { 0xA9BCAE53 } +_tbl[237] = { 0xDEBB9EC5 } +_tbl[238] = { 0x47B2CF7F } +_tbl[239] = { 0x30B5FFE9 } +_tbl[240] = { 0xBDBDF21C } +_tbl[241] = { 0xCABAC28A } +_tbl[242] = { 0x53B39330 } +_tbl[243] = { 0x24B4A3A6 } +_tbl[244] = { 0xBAD03605 } +_tbl[245] = { 0xCDD70693 } +_tbl[246] = { 0x54DE5729 } +_tbl[247] = { 0x23D967BF } +_tbl[248] = { 0xB3667A2E } +_tbl[249] = { 0xC4614AB8 } +_tbl[250] = { 0x5D681B02 } +_tbl[251] = { 0x2A6F2B94 } +_tbl[252] = { 0xB40BBE37 } +_tbl[253] = { 0xC30C8EA1 } +_tbl[254] = { 0x5A05DF1B } +_tbl[255] = { 0x2D02EF8D } + + + -- Calculate it + local ret = 0 + for i,item in pairs(data) do + local tmp = band(ret, 0xFF) + local index = band( bxor(tmp, item), 0xFF) + ret = bxor(rshift(ret,8), _tbl[index][1]) + end + return ret +end +--- +-- update checksum +-- called: data is string, ( >= 24 hex digits ) +-- returns: string, (data concat new checksum) +local function updateChecksum(data) + local part = data:sub(1,24) + local chksum = calculateChecksum( utils.ConvertHexToBytes(part)) + return string.format("%s%X", part, chksum) +end +--- +-- receives the answer from deviceside, used with a readblock command +local function waitCmd() + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + if response then + local count,cmd,arg0 = bin.unpack('LL',response) + if(arg0==1) then + local count,arg1,arg2,data = bin.unpack('LLH511',response,count) + return data:sub(1,32) + else + return nil, "Couldn't read block.." + end + end + return nil, "No response from device" +end + +local function selftest() + local testdata = '000F42430D0A14000001D11F'..'5D738517' + local chksum = getChecksum(testdata) + local calc = calculateChecksum( utils.ConvertHexToBytes(testdata:sub(1,24))) + print ('TESTDATA :: '..testdata) + print ('DATA :: '..testdata:sub(1,24)) + print (('CHKSUM :: %X'):format(chksum)) + print (('CHKSUM CALC :: %X'):format(calc)) + print ('UPDATE CHKSUM :: '..updateChecksum(testdata)) + + +end +--- +-- The main entry point +-- -d decrypt +-- -e encrypt +-- -v validate +function main(args) + + local cmd, result, err, blockNo, keyA + local blocks = {} + local decryptkey = '' + + -- Read the parameters + for o, a in getopt.getopt(args, 'hk:') do + if o == "h" then help() return end + if o == "k" then keyA = a end + end + + selftest() + + local tst2 = '00100100030209094312356432324E34B79A349B' + + -- validate input args. + keyA = keyA or '6dd747e86975' + if #(keyA) ~= 12 then + return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA)) + end + + -- Turn off Debug + local cmdSetDbgOff = "hf mf dbg 0" + core.console( cmdSetDbgOff) + + -- GET TAG UID + + result, err = lib14a.read1443a(false) + if not result then + return oops(err) + end + + core.clearCommandBuffer() + + print(result.uid, keyA) + + local my = result.uid + if 1 == 1 then + return + end + + -- Show tag info + print((' Found tag %s'):format(result.name)) + + local longrandom = RANDOM..result.uid + local res = utils.Sha1Hex(longrandom) + res = utils.ConvertBytesToHex(utils.ConvertAsciiToBytes(res:sub(1,16))) + decryptkey = utils.SwapEndiannessStr(res:sub(1,8) , 32) + decryptkey = decryptkey..utils.SwapEndiannessStr( res:sub(9,16),32) + decryptkey = decryptkey..utils.SwapEndiannessStr( res:sub(17,24),32) + decryptkey = decryptkey..utils.SwapEndiannessStr( res:sub(25,32),32) + print('Decrypt key::',decryptkey) + print('Reading card data') + print('Raw','Decrypted') + for blockNo = 0, numBlocks-1, 1 do + + if core.ukbhit() then + print("aborted by user") + break + end + + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = keyA} + local err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local blockdata, err = waitCmd() + if err then return oops(err) end + + if blockNo%4 ~= 3 then + + -- blocks with zero not encrypted. + if string.find(blockdata, '^0+$') then + print(blockdata, blockdata) + else + local aes = core.aes128_decrypt_ecb(decryptkey, blockdata) + local bytes = utils.ConvertAsciiToBytes(aes) + local hex = utils.ConvertBytesToHex(bytes) + print(blockdata , hex) + end + elseif blockNo == 0 then + print(blockdata,blockdata) + else + -- Sectorblocks, not encrypted + local sectortrailer = keyA..blockdata:sub(13,20)..keyA + print(sectortrailer, sectortrailer, blockdata:sub(13,20)) + end + end + -- checksum fyra sista bytes i varje rad. (kanske inte för s0) + -- s0b1,s1b0,s2b0,s3b0 + -- +end + +main(args) diff --git a/client/scripts/dumptoemul.lua b/client/scripts/dumptoemul.lua index f9b71509..f8cc11d4 100644 --- a/client/scripts/dumptoemul.lua +++ b/client/scripts/dumptoemul.lua @@ -73,7 +73,8 @@ local function convert_to_emulform(hexdata) for i = 1, string.len(hexdata),32 do ascii = ascii ..string.sub(hexdata,i,i+31).."\n" end - return ascii + + return string.sub(ascii,1,-1) end local function main(args) diff --git a/client/util.c b/client/util.c index cea9f7d7..9f2142c6 100644 --- a/client/util.c +++ b/client/util.c @@ -108,12 +108,12 @@ void print_hex(const uint8_t * data, const size_t len) printf("\n"); } -char * sprint_hex(const uint8_t * data, const size_t len) { +char *sprint_hex(const uint8_t *data, const size_t len) { int maxLen = ( len > 1024/3) ? 1024/3 : len; static char buf[1024]; memset(buf, 0x00, 1024); - char * tmp = buf; + char *tmp = buf; size_t i; for (i=0; i < maxLen; ++i, tmp += 3) @@ -394,7 +394,7 @@ int hextobinstring(char *target, char *source) // convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source) // return number of bits converted -int binarraytohex(char *target, char *source, int length) +int binarraytohex(char *target,char *source, int length) { unsigned char i, x; int j = length; @@ -444,3 +444,12 @@ void wiegand_add_parity(char *target, char *source, char length) target += length; *(target)= GetParity(source + length / 2, ODD, length / 2); } + +void xor(unsigned char *dst, unsigned char *src, size_t len) { + for( ; len > 0; len--,dst++,src++) + *dst ^= *src; +} + +int32_t le24toh (uint8_t data[3]) { + return (data[2] << 16) | (data[1] << 8) | data[0]; +} diff --git a/client/util.h b/client/util.h index f58f64cb..2d2beaf4 100644 --- a/client/util.h +++ b/client/util.h @@ -63,3 +63,5 @@ void binarraytobinstring(char *target, char *source, int length); uint8_t GetParity( char *string, uint8_t type, int length); void wiegand_add_parity(char *target, char *source, char length); +void xor(unsigned char *dst, unsigned char *src, size_t len); +int32_t le24toh(uint8_t data[3]); diff --git a/common/crc16.c b/common/crc16.c index 973cd103..a37f1d7e 100644 --- a/common/crc16.c +++ b/common/crc16.c @@ -8,38 +8,54 @@ #include "crc16.h" - unsigned short update_crc16( unsigned short crc, unsigned char c ) { - unsigned short i, v, tcrc = 0; + unsigned short i, v, tcrc = 0; - v = (crc ^ c) & 0xff; - for (i = 0; i < 8; i++) { - tcrc = ( (tcrc ^ v) & 1 ) ? ( tcrc >> 1 ) ^ 0x8408 : tcrc >> 1; - v >>= 1; - } + v = (crc ^ c) & 0xff; + for (i = 0; i < 8; i++) { + tcrc = ( (tcrc ^ v) & 1 ) ? ( tcrc >> 1 ) ^ 0x8408 : tcrc >> 1; + v >>= 1; + } - return ((crc >> 8) ^ tcrc)&0xffff; + return ((crc >> 8) ^ tcrc)&0xffff; } uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial) { - - if (length == 0) - return (~remainder); - - for (int byte = 0; byte < length; ++byte) { - remainder ^= (message[byte] << 8); - for (uint8_t bit = 8; bit > 0; --bit) { - if (remainder & 0x8000) { - remainder = (remainder << 1) ^ polynomial; - } else { - remainder = (remainder << 1); - } - } - } - return remainder; + + if (length == 0) return (~remainder); + + for (int byte = 0; byte < length; ++byte) { + remainder ^= (message[byte] << 8); + for (uint8_t bit = 8; bit > 0; --bit) { + if (remainder & 0x8000) { + remainder = (remainder << 1) ^ polynomial; + } else { + remainder = (remainder << 1); + } + } + } + return remainder; } uint16_t crc16_ccitt(uint8_t const *message, int length) { - return crc16(message, length, 0xffff, 0x1021); + return crc16(message, length, 0xffff, 0x1021); +} + +uint16_t crc16_ccitt_kermit(uint8_t const *message, int length) { + return bit_reverse_uint16(crc16(message, length, 0x0000, 0x1021)); +} + +uint16_t bit_reverse_uint16 (uint16_t value) { + const uint16_t mask0 = 0x5555; + const uint16_t mask1 = 0x3333; + const uint16_t mask2 = 0x0F0F; + const uint16_t mask3 = 0x00FF; + + value = (((~mask0) & value) >> 1) | ((mask0 & value) << 1); + value = (((~mask1) & value) >> 2) | ((mask1 & value) << 2); + value = (((~mask2) & value) >> 4) | ((mask2 & value) << 4); + value = (((~mask3) & value) >> 8) | ((mask3 & value) << 8); + + return value; } diff --git a/common/crc16.h b/common/crc16.h index d16d83b5..8eb4befb 100644 --- a/common/crc16.h +++ b/common/crc16.h @@ -12,4 +12,6 @@ unsigned short update_crc16(unsigned short crc, unsigned char c); uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial); uint16_t crc16_ccitt(uint8_t const *message, int length); +uint16_t crc16_ccitt_kermit(uint8_t const *message, int length); +uint16_t bit_reverse_uint16 (uint16_t value); #endif diff --git a/common/lfdemod.c b/common/lfdemod.c index 7d40d22e..f13a567c 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -526,7 +526,7 @@ int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, ui return (int)startIdx; } -uint32_t bytebits_to_byte(uint8_t* src, size_t numbits) +uint32_t bytebits_to_byte(uint8_t *src, size_t numbits) { uint32_t num = 0; for(int i = 0 ; i < numbits ; i++) @@ -537,6 +537,17 @@ uint32_t bytebits_to_byte(uint8_t* src, size_t numbits) return num; } +//least significant bit first +uint32_t bytebits_to_byteLSBF(uint8_t *src, size_t numbits) +{ + uint32_t num = 0; + for(int i = 0 ; i < numbits ; i++) + { + num = (num << 1) | *(src + (numbits-(i+1))); + } + return num; +} + int IOdemodFSK(uint8_t *dest, size_t size) { if (justNoise(dest, size)) return -1; @@ -569,7 +580,7 @@ int IOdemodFSK(uint8_t *dest, size_t size) // by marshmellow // takes a array of binary values, start position, length of bits per parity (includes parity bit), -// Parity Type (1 for odd 0 for even), and binary Length (length to run) +// Parity Type (1 for odd; 0 for even; 2 for just drop it), and binary Length (length to run) size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen) { uint32_t parityWd = 0; @@ -581,7 +592,9 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p } j--; // if parity fails then return 0 - if (parityTest(parityWd, pLen, pType) == 0) return -1; + if (pType != 2) { + if (parityTest(parityWd, pLen, pType) == 0) return -1; + } bitCnt+=(pLen-1); parityWd = 0; } @@ -590,6 +603,21 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p return bitCnt; } +// Ask/Biphase Demod then try to locate an ISO 11784/85 ID +// BitStream must contain previously askrawdemod and biphasedemoded data +int FDXBdemodBI(uint8_t *dest, size_t *size) +{ + //make sure buffer has enough data + if (*size < 128) return -1; + + size_t startIdx = 0; + uint8_t preamble[] = {0,0,0,0,0,0,0,0,0,0,1}; + + uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx); + if (errChk == 0) return -2; //preamble not found + return (int)startIdx; +} + // by marshmellow // FSK Demod then try to locate an AWID ID int AWIDdemodFSK(uint8_t *dest, size_t *size) diff --git a/common/lfdemod.h b/common/lfdemod.h index ab81c34c..d16aab9e 100644 --- a/common/lfdemod.h +++ b/common/lfdemod.h @@ -19,6 +19,7 @@ int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType); int BiphaseRawDecode(uint8_t * BitStream, size_t *size, int offset, int invert); uint32_t bytebits_to_byte(uint8_t* src, size_t numbits); +uint32_t bytebits_to_byteLSBF(uint8_t* src, size_t numbits); uint16_t countFC(uint8_t *BitStream, size_t size, uint8_t fskAdj); int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr); uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t low); @@ -40,6 +41,7 @@ void psk1TOpsk2(uint8_t *BitStream, size_t size); size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen); //tag specific +int FDXBdemodBI(uint8_t *dest, size_t *size); int AWIDdemodFSK(uint8_t *dest, size_t *size); int gProxII_Demod(uint8_t BitStream[], size_t *size); int HIDdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo); diff --git a/common/protocols.c b/common/protocols.c index 6a4c9a10..aa80491b 100644 --- a/common/protocols.c +++ b/common/protocols.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/common/sha1.c b/common/sha1.c new file mode 100644 index 00000000..d20c54a4 --- /dev/null +++ b/common/sha1.c @@ -0,0 +1,665 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved + * This file is part of mbed TLS (https://tls.mbed.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#if !defined(POLARSSL_CONFIG_FILE) +//#include "polarssl/config.h" +#define POLARSSL_SHA1_C + +#else +#include POLARSSL_CONFIG_FILE +#endif + +#if defined(POLARSSL_SHA1_C) + +#include "sha1.h" + +#include + +#if defined(POLARSSL_FS_IO) +#include +#endif + +#if defined(POLARSSL_SELF_TEST) +#if defined(POLARSSL_PLATFORM_C) +#include "polarssl/platform.h" +#else +#include +#define polarssl_printf printf +#endif /* POLARSSL_PLATFORM_C */ +#endif /* POLARSSL_SELF_TEST */ + +/* Implementation that should never be optimized out by the compiler */ +static void polarssl_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#if !defined(POLARSSL_SHA1_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void sha1_init( sha1_context *ctx ) +{ + memset( ctx, 0, sizeof( sha1_context ) ); +} + +void sha1_free( sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + polarssl_zeroize( ctx, sizeof( sha1_context ) ); +} + +/* + * SHA-1 context setup + */ +void sha1_starts( sha1_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +void sha1_process( sha1_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp, W[16], A, B, C, D, E; + + GET_UINT32_BE( W[ 0], data, 0 ); + GET_UINT32_BE( W[ 1], data, 4 ); + GET_UINT32_BE( W[ 2], data, 8 ); + GET_UINT32_BE( W[ 3], data, 12 ); + GET_UINT32_BE( W[ 4], data, 16 ); + GET_UINT32_BE( W[ 5], data, 20 ); + GET_UINT32_BE( W[ 6], data, 24 ); + GET_UINT32_BE( W[ 7], data, 28 ); + GET_UINT32_BE( W[ 8], data, 32 ); + GET_UINT32_BE( W[ 9], data, 36 ); + GET_UINT32_BE( W[10], data, 40 ); + GET_UINT32_BE( W[11], data, 44 ); + GET_UINT32_BE( W[12], data, 48 ); + GET_UINT32_BE( W[13], data, 52 ); + GET_UINT32_BE( W[14], data, 56 ); + GET_UINT32_BE( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ + W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +/* + * SHA-1 process buffer + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha1_update( ctx, sha1_padding, padn ); + sha1_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); +} + +#endif /* !POLARSSL_SHA1_ALT */ + +/* + * output = SHA-1( input buffer ) + */ +void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) +{ + sha1_context ctx; + + sha1_init( &ctx ); + sha1_starts( &ctx ); + sha1_update( &ctx, input, ilen ); + sha1_finish( &ctx, output ); + sha1_free( &ctx ); +} + +#if defined(POLARSSL_FS_IO) +/* + * output = SHA-1( file contents ) + */ +int sha1_file( const char *path, unsigned char output[20] ) +{ + FILE *f; + size_t n; + sha1_context ctx; + unsigned char buf[1024]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_SHA1_FILE_IO_ERROR ); + + sha1_init( &ctx ); + sha1_starts( &ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + sha1_update( &ctx, buf, n ); + + sha1_finish( &ctx, output ); + sha1_free( &ctx ); + + if( ferror( f ) != 0 ) + { + fclose( f ); + return( POLARSSL_ERR_SHA1_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * SHA-1 HMAC context setup + */ +void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, + size_t keylen ) +{ + size_t i; + unsigned char sum[20]; + + if( keylen > 64 ) + { + sha1( key, keylen, sum ); + keylen = 20; + key = sum; + } + + memset( ctx->ipad, 0x36, 64 ); + memset( ctx->opad, 0x5C, 64 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + sha1_starts( ctx ); + sha1_update( ctx, ctx->ipad, 64 ); + + polarssl_zeroize( sum, sizeof( sum ) ); +} + +/* + * SHA-1 HMAC process buffer + */ +void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, + size_t ilen ) +{ + sha1_update( ctx, input, ilen ); +} + +/* + * SHA-1 HMAC final digest + */ +void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] ) +{ + unsigned char tmpbuf[20]; + + sha1_finish( ctx, tmpbuf ); + sha1_starts( ctx ); + sha1_update( ctx, ctx->opad, 64 ); + sha1_update( ctx, tmpbuf, 20 ); + sha1_finish( ctx, output ); + + polarssl_zeroize( tmpbuf, sizeof( tmpbuf ) ); +} + +/* + * SHA1 HMAC context reset + */ +void sha1_hmac_reset( sha1_context *ctx ) +{ + sha1_starts( ctx ); + sha1_update( ctx, ctx->ipad, 64 ); +} + +/* + * output = HMAC-SHA-1( hmac key, input buffer ) + */ +void sha1_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[20] ) +{ + sha1_context ctx; + + sha1_init( &ctx ); + sha1_hmac_starts( &ctx, key, keylen ); + sha1_hmac_update( &ctx, input, ilen ); + sha1_hmac_finish( &ctx, output ); + sha1_free( &ctx ); +} + +#if defined(POLARSSL_SELF_TEST) +/* + * FIPS-180-1 test vectors + */ +static const unsigned char sha1_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha1_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha1_test_sum[3][20] = +{ + { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, + 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D }, + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, + 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 }, + { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, + 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } +}; + +/* + * RFC 2202 test vectors + */ +static const unsigned char sha1_hmac_test_key[7][26] = +{ + { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" + "\x0B\x0B\x0B\x0B" }, + { "Jefe" }, + { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA" }, + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, + { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" + "\x0C\x0C\x0C\x0C" }, + { "" }, /* 0xAA 80 times */ + { "" } +}; + +static const int sha1_hmac_test_keylen[7] = +{ + 20, 4, 20, 25, 20, 80, 80 +}; + +static const unsigned char sha1_hmac_test_buf[7][74] = +{ + { "Hi There" }, + { "what do ya want for nothing?" }, + { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, + { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, + { "Test With Truncation" }, + { "Test Using Larger Than Block-Size Key - Hash Key First" }, + { "Test Using Larger Than Block-Size Key and Larger" + " Than One Block-Size Data" } +}; + +static const int sha1_hmac_test_buflen[7] = +{ + 8, 28, 50, 50, 20, 54, 73 +}; + +static const unsigned char sha1_hmac_test_sum[7][20] = +{ + { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B, + 0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 }, + { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74, + 0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 }, + { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3, + 0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 }, + { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84, + 0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA }, + { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2, + 0x7B, 0xE1 }, + { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70, + 0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 }, + { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B, + 0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 } +}; + +/* + * Checkup routine + */ +int sha1_self_test( int verbose ) +{ + int i, j, buflen, ret = 0; + unsigned char buf[1024]; + unsigned char sha1sum[20]; + sha1_context ctx; + + sha1_init( &ctx ); + + /* + * SHA-1 + */ + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + polarssl_printf( " SHA-1 test #%d: ", i + 1 ); + + sha1_starts( &ctx ); + + if( i == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + sha1_update( &ctx, buf, buflen ); + } + else + sha1_update( &ctx, sha1_test_buf[i], + sha1_test_buflen[i] ); + + sha1_finish( &ctx, sha1sum ); + + if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 ) + { + if( verbose != 0 ) + polarssl_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } + + if( verbose != 0 ) + polarssl_printf( "\n" ); + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + polarssl_printf( " HMAC-SHA-1 test #%d: ", i + 1 ); + + if( i == 5 || i == 6 ) + { + memset( buf, 0xAA, buflen = 80 ); + sha1_hmac_starts( &ctx, buf, buflen ); + } + else + sha1_hmac_starts( &ctx, sha1_hmac_test_key[i], + sha1_hmac_test_keylen[i] ); + + sha1_hmac_update( &ctx, sha1_hmac_test_buf[i], + sha1_hmac_test_buflen[i] ); + + sha1_hmac_finish( &ctx, sha1sum ); + + buflen = ( i == 4 ) ? 12 : 20; + + if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 ) + { + if( verbose != 0 ) + polarssl_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } + + if( verbose != 0 ) + polarssl_printf( "\n" ); + +exit: + sha1_free( &ctx ); + + return( ret ); +} + +#endif /* POLARSSL_SELF_TEST */ + +#endif /* POLARSSL_SHA1_C */ + diff --git a/common/sha1.h b/common/sha1.h new file mode 100644 index 00000000..056bba7e --- /dev/null +++ b/common/sha1.h @@ -0,0 +1,213 @@ +/** + * \file sha1.h + * + * \brief SHA-1 cryptographic hash function + * + * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SHA1_H +#define POLARSSL_SHA1_H + +#if !defined(POLARSSL_CONFIG_FILE) +//#include "config.h" +/** + * \def POLARSSL_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define POLARSSL_SHA1_C + +#else +#include POLARSSL_CONFIG_FILE +#endif + +#include + +#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define POLARSSL_ERR_SHA1_FILE_IO_ERROR -0x0076 /**< Read/write error in file. */ + +#if !defined(POLARSSL_SHA1_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void sha1_init( sha1_context *ctx ); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void sha1_free( sha1_context *ctx ); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void sha1_starts( sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void sha1_process( sha1_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* POLARSSL_SHA1_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( file contents ) + * + * \param path input file name + * \param output SHA-1 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR + */ +int sha1_file( const char *path, unsigned char output[20] ); + +/** + * \brief SHA-1 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, + size_t keylen ); + +/** + * \brief SHA-1 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-1 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-1 HMAC checksum result + */ +void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief SHA-1 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void sha1_hmac_reset( sha1_context *ctx ); + +/** + * \brief Output = HMAC-SHA-1( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-1 result + */ +void sha1_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha1.h */ diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 20fb2bd4..50c7eef9 100644 Binary files a/fpga/fpga_hf.bit and b/fpga/fpga_hf.bit differ diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v index a2100df6..8a465e75 100644 --- a/fpga/fpga_hf.v +++ b/fpga/fpga_hf.v @@ -73,9 +73,6 @@ wire hi_read_rx_xcorr_848 = conf_word[0]; // and whether to drive the coil (reader) or just short it (snooper) wire hi_read_rx_xcorr_snoop = conf_word[1]; -// Divide the expected subcarrier frequency for hi_read_rx_xcorr by 4 -wire hi_read_rx_xcorr_quarter = conf_word[2]; - // For the high-frequency simulated tag: what kind of modulation to use. wire [2:0] hi_simulate_mod_type = conf_word[2:0]; @@ -102,7 +99,7 @@ hi_read_rx_xcorr hrxc( hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk, cross_hi, cross_lo, hrxc_dbg, - hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter + hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop ); hi_simulate hs( diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v index dece2db3..afaf7cb6 100644 --- a/fpga/hi_read_rx_xcorr.v +++ b/fpga/hi_read_rx_xcorr.v @@ -10,7 +10,7 @@ module hi_read_rx_xcorr( ssp_frame, ssp_din, ssp_dout, ssp_clk, cross_hi, cross_lo, dbg, - xcorr_is_848, snoop, xcorr_quarter_freq + xcorr_is_848, snoop ); input pck0, ck_1356meg, ck_1356megb; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; @@ -20,58 +20,24 @@ module hi_read_rx_xcorr( output ssp_frame, ssp_din, ssp_clk; input cross_hi, cross_lo; output dbg; - input xcorr_is_848, snoop, xcorr_quarter_freq; + input xcorr_is_848, snoop; // Carrier is steady on through this, unless we're snooping. assign pwr_hi = ck_1356megb & (~snoop); assign pwr_oe1 = 1'b0; -assign pwr_oe2 = 1'b0; assign pwr_oe3 = 1'b0; assign pwr_oe4 = 1'b0; -reg ssp_clk; -reg ssp_frame; +wire adc_clk = ck_1356megb; reg fc_div_2; -always @(posedge ck_1356meg) - fc_div_2 = ~fc_div_2; - -reg fc_div_4; -always @(posedge fc_div_2) - fc_div_4 = ~fc_div_4; - -reg fc_div_8; -always @(posedge fc_div_4) - fc_div_8 = ~fc_div_8; - -reg adc_clk; - -always @(xcorr_is_848 or xcorr_quarter_freq or ck_1356meg) - if(~xcorr_quarter_freq) - begin - if(xcorr_is_848) - // The subcarrier frequency is fc/16; we will sample at fc, so that - // means the subcarrier is 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 ... - adc_clk <= ck_1356meg; - else - // The subcarrier frequency is fc/32; we will sample at fc/2, and - // the subcarrier will look identical. - adc_clk <= fc_div_2; - end - else - begin - if(xcorr_is_848) - // The subcarrier frequency is fc/64 - adc_clk <= fc_div_4; - else - // The subcarrier frequency is fc/128 - adc_clk <= fc_div_8; - end +always @(negedge ck_1356megb) + fc_div_2 <= fc_div_2 + 1; // When we're a reader, we just need to do the BPSK demod; but when we're an // eavesdropper, we also need to pick out the commands sent by the reader, // using AM. Do this the same way that we do it for the simulated tag. -reg after_hysteresis, after_hysteresis_prev; +reg after_hysteresis, after_hysteresis_prev, after_hysteresis_prev_prev; reg [11:0] has_been_low_for; always @(negedge adc_clk) begin @@ -97,12 +63,24 @@ end // Let us report a correlation every 4 subcarrier cycles, or 4*16 samples, // so we need a 6-bit counter. reg [5:0] corr_i_cnt; -reg [5:0] corr_q_cnt; // And a couple of registers in which to accumulate the correlations. -reg signed [15:0] corr_i_accum; -reg signed [15:0] corr_q_accum; +// we would add at most 32 times adc_d, the result can be held in 13 bits. +// Need one additional bit because it can be negative as well +reg signed [13:0] corr_i_accum; +reg signed [13:0] corr_q_accum; reg signed [7:0] corr_i_out; reg signed [7:0] corr_q_out; +// clock and frame signal for communication to ARM +reg ssp_clk; +reg ssp_frame; + + +always @(negedge adc_clk) +begin + if (xcorr_is_848 | fc_div_2) + corr_i_cnt <= corr_i_cnt + 1; +end + // ADC data appears on the rising edge, so sample it on the falling edge always @(negedge adc_clk) @@ -110,24 +88,24 @@ begin // These are the correlators: we correlate against in-phase and quadrature // versions of our reference signal, and keep the (signed) result to // send out later over the SSP. - if(corr_i_cnt == 7'd63) + if(corr_i_cnt == 6'd0) begin if(snoop) begin - corr_i_out <= {corr_i_accum[12:6], after_hysteresis_prev}; - corr_q_out <= {corr_q_accum[12:6], after_hysteresis}; + // Send only 7 most significant bits of tag signal (signed), LSB is reader signal: + corr_i_out <= {corr_i_accum[13:7], after_hysteresis_prev_prev}; + corr_q_out <= {corr_q_accum[13:7], after_hysteresis_prev}; + after_hysteresis_prev_prev <= after_hysteresis; end else begin - // Only correlations need to be delivered. + // 8 most significant bits of tag signal corr_i_out <= corr_i_accum[13:6]; corr_q_out <= corr_q_accum[13:6]; end corr_i_accum <= adc_d; corr_q_accum <= adc_d; - corr_q_cnt <= 4; - corr_i_cnt <= 0; end else begin @@ -136,18 +114,16 @@ begin else corr_i_accum <= corr_i_accum + adc_d; - if(corr_q_cnt[3]) - corr_q_accum <= corr_q_accum - adc_d; - else + if(corr_i_cnt[3] == corr_i_cnt[2]) // phase shifted by pi/2 corr_q_accum <= corr_q_accum + adc_d; + else + corr_q_accum <= corr_q_accum - adc_d; - corr_i_cnt <= corr_i_cnt + 1; - corr_q_cnt <= corr_q_cnt + 1; end // The logic in hi_simulate.v reports 4 samples per bit. We report two // (I, Q) pairs per bit, so we should do 2 samples per pair. - if(corr_i_cnt == 6'd31) + if(corr_i_cnt == 6'd32) after_hysteresis_prev <= after_hysteresis; // Then the result from last time is serialized and send out to the ARM. @@ -168,7 +144,9 @@ begin end end - if(corr_i_cnt[5:2] == 4'b000 || corr_i_cnt[5:2] == 4'b1000) + // set ssp_frame signal for corr_i_cnt = 0..3 and corr_i_cnt = 32..35 + // (send two frames with 8 Bits each) + if(corr_i_cnt[5:2] == 4'b0000 || corr_i_cnt[5:2] == 4'b1000) ssp_frame = 1'b1; else ssp_frame = 1'b0; @@ -181,5 +159,6 @@ assign dbg = corr_i_cnt[3]; // Unused. assign pwr_lo = 1'b0; +assign pwr_oe2 = 1'b0; endmodule diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 357395d4..524554e9 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -100,7 +100,6 @@ typedef struct{ // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 -#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 0x0301 #define CMD_READ_SRI512_TAG 0x0303 #define CMD_READ_SRIX4K_TAG 0x0304 #define CMD_ISO_14443B_COMMAND 0x0305 @@ -118,9 +117,8 @@ typedef struct{ #define CMD_SIMULATE_HITAG 0x0371 #define CMD_READER_HITAG 0x0372 -#define CMD_SIMULATE_TAG_HF_LISTEN 0x0380 -#define CMD_SIMULATE_TAG_ISO_14443 0x0381 -#define CMD_SNOOP_ISO_14443 0x0382 +#define CMD_SIMULATE_TAG_ISO_14443B 0x0381 +#define CMD_SNOOP_ISO_14443B 0x0382 #define CMD_SNOOP_ISO_14443a 0x0383 #define CMD_SIMULATE_TAG_ISO_14443a 0x0384 #define CMD_READER_ISO_14443a 0x0385 @@ -128,6 +126,7 @@ typedef struct{ #define CMD_READER_LEGIC_RF 0x0388 #define CMD_WRITER_LEGIC_RF 0x0389 #define CMD_EPA_PACE_COLLECT_NONCE 0x038A +#define CMD_EPA_PACE_REPLAY 0x038B #define CMD_SNOOP_ICLASS 0x0392 #define CMD_SIMULATE_TAG_ICLASS 0x0393