From 8df14408b88fcf99206738ef2b1cf4ff0e9e6a88 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 11:47:46 +0200 Subject: [PATCH 001/139] fgpa changes from official repo. Had to split felica into its own image. Leading to three bit files created. --- fpga/Makefile | 11 ++- fpga/fpga_hf.v | 172 ++++++++++++++++++++------------------------ fpga/fpga_lf.v | 4 +- fpga/hi_flite.v | 18 +++-- fpga/hi_iso14443a.v | 57 +++++++-------- fpga/hi_simulate.v | 119 +++++++++++++++++------------- fpga/hi_sniffer.v | 13 +--- 7 files changed, 191 insertions(+), 203 deletions(-) diff --git a/fpga/Makefile b/fpga/Makefile index 0d2bb1625..9b1f7a5ca 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -5,17 +5,22 @@ RMDIR = rm -rf # rmdir only if dir is empty, tolerate failure RMDIR_SOFT = -rmdir # -all: fpga_lf.bit fpga_hf.bit +all: fpga_lf.bit fpga_hf.bit fpga_felica.bit clean: - $(Q)$(RM) *.bgn *.drc *.ncd *.ngd *_par.xrpt *-placed.* *-placed_pad.* *_usage.xml xst_hf.srp xst_lf.srp + $(Q)$(RM) *.bgn *.drc *.ncd *.ngd *_par.xrpt *-placed.* *-placed_pad.* *_usage.xml xst_hf.srp xst_lf.srp xst_felica.srp $(Q)$(RM) *.map *.ngc *.xrpt *.pcf *.rbt *.bld *.mrp *.ngm *.unroutes *_summary.xml netlist.lst $(Q)$(RMDIR) *_auto_* xst -fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v hi_sniffer.v hi_flite.v hi_get_trace.v +#fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_reader.v hi_iso14443a.v hi_sniffer.v hi_flite.v hi_get_trace.v +fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_reader.v hi_iso14443a.v hi_sniffer.v hi_get_trace.v $(Q)$(RM) $@ $(info [-] XST $@) $(Q)$(XILINX_TOOLS_PREFIX)xst -ifn xst_hf.scr +fpga_felica.ngc: fpga_felica.v fpga.ucf xst_felica.scr util.v hi_simulate.v hi_reader.v hi_sniffer.v hi_flite.v hi_get_trace.v + $(Q)$(RM) $@ + $(info [-] XST $@) + $(Q)$(XILINX_TOOLS_PREFIX)xst -ifn xst_felica.scr fpga_lf.ngc: fpga_lf.v fpga.ucf xst_lf.scr util.v clk_divider.v lo_edge_detect.v lo_read.v lo_passthru.v lp20khz_1MSa_iir_filter.v min_max_tracker.v lf_edge_detect.v $(Q)$(RM) $@ diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v index d23b64a08..5448219fc 100644 --- a/fpga/fpga_hf.v +++ b/fpga/fpga_hf.v @@ -23,23 +23,28 @@ `define FPGA_CMD_TRACE_ENABLE 2 // Major modes: -`define FPGA_MAJOR_MODE_HF_READER_TX 0 -`define FPGA_MAJOR_MODE_HF_READER_RX_XCORR 1 -`define FPGA_MAJOR_MODE_HF_SIMULATOR 2 -`define FPGA_MAJOR_MODE_HF_ISO14443A 3 -`define FPGA_MAJOR_MODE_HF_SNOOP 4 -`define FPGA_MAJOR_MODE_HF_ISO18092 5 -`define FPGA_MAJOR_MODE_HF_GET_TRACE 6 +`define FPGA_MAJOR_MODE_HF_READER 0 +`define FPGA_MAJOR_MODE_HF_SIMULATOR 1 +`define FPGA_MAJOR_MODE_HF_ISO14443A 2 +`define FPGA_MAJOR_MODE_HF_SNOOP 3 +`define FPGA_MAJOR_MODE_HF_ISO18092 4 +`define FPGA_MAJOR_MODE_HF_GET_TRACE 5 `define FPGA_MAJOR_MODE_OFF 7 // Options for the generic HF reader -// Options for the HF reader, tx to tag -`define FPGA_HF_READER_TX_SHALLOW_MOD 1 +`define FPGA_HF_READER_MODE_RECEIVE_IQ 0 +`define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE 1 +`define FPGA_HF_READER_MODE_RECEIVE_PHASE 2 +`define FPGA_HF_READER_MODE_SEND_FULL_MOD 3 +`define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD 4 +`define FPGA_HF_READER_MODE_SNIFF_IQ 5 +`define FPGA_HF_READER_MODE_SNIFF_AMPLITUDE 6 +`define FPGA_HF_READER_MODE_SNIFF_PHASE 7 +`define FPGA_HF_READER_MODE_SEND_JAM 8 -// Options for the HF reader, correlating against rx from tag -`define FPGA_HF_READER_RX_XCORR_848_KHZ 1 -`define FPGA_HF_READER_RX_XCORR_SNOOP 2 -`define FPGA_HF_READER_RX_XCORR_QUARTER 4 +`define FPGA_HF_READER_SUBCARRIER_848_KHZ 0 +`define FPGA_HF_READER_SUBCARRIER_424_KHZ 1 +`define FPGA_HF_READER_SUBCARRIER_212_KHZ 2 // Options for the HF simulated tag, how to modulate `define FPGA_HF_SIMULATOR_NO_MODULATION 0 @@ -60,13 +65,12 @@ `define FPGA_HF_ISO18092_FLAG_424K 2 // 0010 should enable 414k mode (untested). No autodetect `define FPGA_HF_ISO18092_FLAG_READER 4 // 0100 enables antenna power, to act as a reader instead of tag -`include "hi_read_tx.v" -`include "hi_read_rx_xcorr.v" +`include "hi_reader.v" `include "hi_simulate.v" `include "hi_iso14443a.v" `include "hi_sniffer.v" `include "util.v" -`include "hi_flite.v" +// `include "hi_flite.v" `include "hi_get_trace.v" module fpga_hf( @@ -105,14 +109,14 @@ bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -----+------------------------------------------- cmd | x x x x major| x x x -opt | x x +opt | x x x divi | x x x x x x x x thres| x x x x x x x x -----+------------------------------------------- */ reg [15:0] shift_reg; -reg [7:0] conf_word; +reg [8:0] conf_word; reg trace_enable; // We switch modes between transmitting to the 13.56 MHz tag and receiving @@ -121,7 +125,7 @@ reg trace_enable; always @(posedge ncs) begin case(shift_reg[15:12]) - `FPGA_CMD_SET_CONFREG: conf_word <= shift_reg[7:0]; + `FPGA_CMD_SET_CONFREG: conf_word <= shift_reg[8:0]; `FPGA_CMD_TRACE_ENABLE: trace_enable <= shift_reg[0]; endcase end @@ -135,25 +139,12 @@ begin end end -wire [2:0] major_mode = conf_word[7:5]; +// select module (outputs) based on major mode +wire [2:0] major_mode = conf_word[8:6]; -// For the high-frequency transmit configuration: modulation depth, either -// 100% (just quite driving antenna, steady LOW), or shallower (tri-state -// some fraction of the buffers) -wire hi_read_tx_shallow_modulation = conf_word[0]; - -// For the high-frequency receive correlator: frequency against which to -// correlate. -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 subcarrier frequency 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]; +// configuring the HF reader +wire [1:0] subcarrier_frequency = conf_word[5:4]; +wire [3:0] minor_mode = conf_word[3:0]; //----------------------------------------------------------------------------- // And then we instantiate the modules corresponding to each of the FPGA's @@ -161,95 +152,86 @@ wire [2:0] hi_simulate_mod_type = conf_word[2:0]; // the output pins. //----------------------------------------------------------------------------- -hi_read_tx ht( - pck0, ck_1356meg, ck_1356megb, - ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4, - adc_d, ht_adc_clk, - ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk, - cross_hi, cross_lo, - ht_dbg, - hi_read_tx_shallow_modulation -); - -hi_read_rx_xcorr hrxc( - pck0, ck_1356meg, ck_1356megb, - hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3, hrxc_pwr_oe4, - adc_d, hrxc_adc_clk, - 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 +// 000 - HF reader +hi_reader hr( + ck_1356megb, + hr_pwr_lo, hr_pwr_hi, hr_pwr_oe1, hr_pwr_oe2, hr_pwr_oe3, hr_pwr_oe4, + adc_d, hr_adc_clk, + hr_ssp_frame, hr_ssp_din, ssp_dout, hr_ssp_clk, + hr_dbg, + subcarrier_frequency, minor_mode ); +// 001 - HF simulated tag hi_simulate hs( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4, adc_d, hs_adc_clk, hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk, - cross_hi, cross_lo, hs_dbg, - hi_simulate_mod_type + minor_mode ); +// 010 - HF ISO14443-A hi_iso14443a hisn( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3, hisn_pwr_oe4, adc_d, hisn_adc_clk, hisn_ssp_frame, hisn_ssp_din, ssp_dout, hisn_ssp_clk, - cross_hi, cross_lo, hisn_dbg, - hi_simulate_mod_type + minor_mode ); +// 011 - HF sniff hi_sniffer he( - pck0, ck_1356meg, ck_1356megb, - he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4, - adc_d, he_adc_clk, - he_ssp_frame, he_ssp_din, ssp_dout, he_ssp_clk, - cross_hi, cross_lo, - he_dbg, - hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter + ck_1356megb, + he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4, + adc_d, he_adc_clk, + he_ssp_frame, he_ssp_din, he_ssp_clk ); +// 100 - HF ISO18092 FeliCa +/* hi_flite hfl( - pck0, ck_1356meg, ck_1356megb, - hfl_pwr_lo, hfl_pwr_hi, hfl_pwr_oe1, hfl_pwr_oe2, hfl_pwr_oe3, hfl_pwr_oe4, - adc_d, hfl_adc_clk, - hfl_ssp_frame, hfl_ssp_din, ssp_dout, hfl_ssp_clk, - cross_hi, cross_lo, - hfl_dbg, - hi_simulate_mod_type + ck_1356megb, + hfl_pwr_lo, hfl_pwr_hi, hfl_pwr_oe1, hfl_pwr_oe2, hfl_pwr_oe3, hfl_pwr_oe4, + adc_d, hfl_adc_clk, + hfl_ssp_frame, hfl_ssp_din, ssp_dout, hfl_ssp_clk, + hfl_dbg, + minor_mode ); +*/ +// 101 - HF get trace hi_get_trace gt( ck_1356megb, adc_d, trace_enable, major_mode, gt_ssp_frame, gt_ssp_din, gt_ssp_clk ); - // Major modes: +// 000 -- HF reader; subcarrier frequency and modulation depth selectable +// 001 -- HF simulated tag +// 010 -- HF ISO14443-A +// 011 -- HF sniff +// 100 -- HF ISO18092 FeliCa +// 101 -- HF get trace +// 110 -- unused +// 111 -- FPGA_MAJOR_MODE_OFF -// 000 -- HF reader, transmitting to tag; modulation depth selectable -// 001 -- HF reader, receiving from tag, correlating as it goes; frequency selectable -// 010 -- HF simulated tag -// 011 -- HF ISO14443-A -// 100 -- HF Snoop -// 101 -- Felica modem, reusing HF reader -// 110 -- HF get trace -// 111 -- everything off +// 000 001 010 011 100 101 110 111 -mux8 mux_ssp_clk (major_mode, ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, hfl_ssp_clk, gt_ssp_clk, 1'b0); -mux8 mux_ssp_din (major_mode, ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, hfl_ssp_din, gt_ssp_din, 1'b0); -mux8 mux_ssp_frame (major_mode, ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, hfl_ssp_frame, gt_ssp_frame, 1'b0); -mux8 mux_pwr_oe1 (major_mode, pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, hfl_pwr_oe1, 1'b0, 1'b0); -mux8 mux_pwr_oe2 (major_mode, pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, hfl_pwr_oe2, 1'b0, 1'b0); -mux8 mux_pwr_oe3 (major_mode, pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, hfl_pwr_oe3, 1'b0, 1'b0); -mux8 mux_pwr_oe4 (major_mode, pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, hfl_pwr_oe4, 1'b0, 1'b0); -mux8 mux_pwr_lo (major_mode, pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, hfl_pwr_lo, 1'b0, 1'b0); -mux8 mux_pwr_hi (major_mode, pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, hfl_pwr_hi, 1'b0, 1'b0); -mux8 mux_adc_clk (major_mode, adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, hfl_adc_clk, 1'b0, 1'b0); -mux8 mux_dbg (major_mode, dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, he_dbg, hfl_dbg, 1'b0, 1'b0); +mux8 mux_ssp_clk (major_mode, ssp_clk, hr_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, hfl_ssp_clk, gt_ssp_clk, 1'b0, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, hr_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, hfl_ssp_din, gt_ssp_din, 1'b0, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, hr_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, hfl_ssp_frame, gt_ssp_frame, 1'b0, 1'b0); +mux8 mux_pwr_oe1 (major_mode, pwr_oe1, hr_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, hfl_pwr_oe1, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe2 (major_mode, pwr_oe2, hr_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, hfl_pwr_oe2, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe3 (major_mode, pwr_oe3, hr_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, hfl_pwr_oe3, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe4 (major_mode, pwr_oe4, hr_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, hfl_pwr_oe4, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_lo (major_mode, pwr_lo, hr_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, hfl_pwr_lo, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, hr_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, hfl_pwr_hi, 1'b0, 1'b0, 1'b0); +mux8 mux_adc_clk (major_mode, adc_clk, hr_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, hfl_adc_clk, 1'b0, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, hr_dbg, hs_dbg, hisn_dbg, he_dbg, hfl_dbg, 1'b0, 1'b0, 1'b0); // In all modes, let the ADC's outputs be enabled. assign adc_noe = 1'b0; diff --git a/fpga/fpga_lf.v b/fpga/fpga_lf.v index dd3fe3b0b..aa79da234 100644 --- a/fpga/fpga_lf.v +++ b/fpga/fpga_lf.v @@ -122,7 +122,7 @@ reg [7:0] divisor; reg [7:0] lf_ed_threshold; reg [11:0] conf_word; -wire [2:0] major_mode = conf_word[7:5]; +wire [2:0] major_mode = conf_word[8:6]; wire lf_field = conf_word[0]; wire lf_ed_toggle_mode = conf_word[1]; @@ -135,7 +135,7 @@ begin begin // 12 bit data conf_word <= shift_reg[11:0]; - if (shift_reg[7:5] == `FPGA_MAJOR_MODE_LF_EDGE_DETECT) + if (shift_reg[8:6] == `FPGA_MAJOR_MODE_LF_EDGE_DETECT) begin lf_ed_threshold <= 127; // default threshold end diff --git a/fpga/hi_flite.v b/fpga/hi_flite.v index 97d0154ea..6cb87825e 100644 --- a/fpga/hi_flite.v +++ b/fpga/hi_flite.v @@ -14,25 +14,23 @@ */ module hi_flite( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, dbg, mod_type - ); - input pck0, ck_1356meg, ck_1356megb; + input ck_1356meg; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; input [7:0] adc_d; output adc_clk; input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; output dbg; - input [2:0] mod_type; -assign dbg=0; + input [3:0] mod_type; + +assign dbg = 0; wire power = mod_type[2]; wire speed = mod_type[1]; @@ -40,7 +38,7 @@ wire disabl = mod_type[0]; // Most off, oe4 for modulation; // Trying reader emulation (would presumably just require switching power on, but I am not sure) -assign pwr_lo = 1'b0; +assign pwr_lo = 1'b0; // 512x64/fc -wait before ts0, 32768 ticks // tslot: 256*64/fc @@ -347,11 +345,11 @@ reg pwr_oe4; wire mod = ((fccount >= bithalf) ^ dlay) & (~disabl); -always @(ck_1356megb or ssp_dout or power or disabl or mod) +always @(ck_1356meg or ssp_dout or power or disabl or mod) begin if (power) begin - pwr_hi <= ck_1356megb; + pwr_hi <= ck_1356meg; pwr_oe1 <= 1'b0;//mod; pwr_oe2 <= 1'b0;//mod; pwr_oe3 <= 1'b0;//mod; diff --git a/fpga/hi_iso14443a.v b/fpga/hi_iso14443a.v index 3bb550d73..6b09847ec 100644 --- a/fpga/hi_iso14443a.v +++ b/fpga/hi_iso14443a.v @@ -3,31 +3,22 @@ // Gerhard de Koning Gans, April 2008 //----------------------------------------------------------------------------- -// constants for the different modes: -`define SNIFFER 3'b000 -`define TAGSIM_LISTEN 3'b001 -`define TAGSIM_MOD 3'b010 -`define READER_LISTEN 3'b011 -`define READER_MOD 3'b100 - module hi_iso14443a( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, dbg, mod_type ); - input pck0, ck_1356meg, ck_1356megb; + input ck_1356meg; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; input [7:0] adc_d; output adc_clk; input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; output dbg; - input [2:0] mod_type; + input [3:0] mod_type; wire adc_clk = ck_1356meg; @@ -151,7 +142,7 @@ begin end // adjust internal timer counter if necessary: - if (negedge_cnt[3:0] == 4'd13 && (mod_type == `SNIFFER || mod_type == `TAGSIM_LISTEN) && deep_modulation) + if (negedge_cnt[3:0] == 4'd13 && (mod_type == `FPGA_HF_ISO14443A_SNIFFER || mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN) && deep_modulation) begin if (reader_falling_edge_time == 4'd1) // reader signal changes right after sampling. Better sample earlier next time. begin @@ -185,7 +176,7 @@ reg [3:0] mod_detect_reset_time; always @(negedge adc_clk) begin - if (mod_type == `READER_LISTEN) + if (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN) // (our) reader signal changes at negedge_cnt[3:0]=9, tag response expected to start n*16+4 ticks later, further delayed by // 3 ticks ADC conversion. The maximum filter output (edge detected) will be detected after subcarrier zero crossing (+7 ticks). // To allow some timing variances, we want to have the maximum filter outputs well within the detection window, i.e. @@ -195,7 +186,7 @@ begin mod_detect_reset_time <= 4'd4; end else - if (mod_type == `SNIFFER) + if (mod_type == `FPGA_HF_ISO14443A_SNIFFER) begin // detect a rising edge of reader's signal and sync modulation detector to the tag's answer: if (~pre_after_hysteresis && after_hysteresis && deep_modulation) @@ -320,7 +311,7 @@ reg [3:0] sub_carrier_cnt; // response window of 1128 - 774 = 354 ticks. // reset on a pause in listen mode. I.e. the counter starts when the pause is over: -assign fdt_reset = ~after_hysteresis && mod_type == `TAGSIM_LISTEN; +assign fdt_reset = ~after_hysteresis && mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN; always @(negedge adc_clk) begin @@ -363,7 +354,7 @@ reg mod_sig_coil; always @(negedge adc_clk) begin - if (mod_type == `TAGSIM_MOD) // need to take care of proper fdt timing + if (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD) // need to take care of proper fdt timing begin if(fdt_counter == `FDT_COUNT) begin @@ -438,7 +429,7 @@ always @(negedge adc_clk) begin if (negedge_cnt[5:0] == 6'd63) // fill the buffer begin - if (mod_type == `SNIFFER) + if (mod_type == `FPGA_HF_ISO14443A_SNIFFER) begin if(deep_modulation) // a reader is sending (or there's no field at all) begin @@ -455,7 +446,7 @@ begin end end - if(negedge_cnt[2:0] == 3'b000 && mod_type == `SNIFFER) // shift at double speed + if(negedge_cnt[2:0] == 3'b000 && mod_type == `FPGA_HF_ISO14443A_SNIFFER) // shift at double speed begin // Don't shift if we just loaded new data, obviously. if(negedge_cnt[5:0] != 6'd0) @@ -464,7 +455,7 @@ begin end end - if(negedge_cnt[3:0] == 4'b0000 && mod_type != `SNIFFER) + if(negedge_cnt[3:0] == 4'b0000 && mod_type != `FPGA_HF_ISO14443A_SNIFFER) begin // Don't shift if we just loaded new data, obviously. if(negedge_cnt[6:0] != 7'd0) @@ -484,8 +475,8 @@ reg ssp_frame; always @(negedge adc_clk) begin - if(mod_type == `SNIFFER) - // SNIFFER mode (ssp_clk = adc_clk / 8, ssp_frame clock = adc_clk / 64)): + if(mod_type == `FPGA_HF_ISO14443A_SNIFFER) + // FPGA_HF_ISO14443A_SNIFFER mode (ssp_clk = adc_clk / 8, ssp_frame clock = adc_clk / 64)): begin if(negedge_cnt[2:0] == 3'd0) ssp_clk <= 1'b1; @@ -505,7 +496,7 @@ begin if(negedge_cnt[3:0] == 4'd8) ssp_clk <= 1'b0; - if(negedge_cnt[6:0] == 7'd7) // ssp_frame rising edge indicates start of frame + if(negedge_cnt[6:0] == 7'd7) // ssp_frame rising edge indicates start of frame, sampled on falling edge of ssp_clk ssp_frame <= 1'b1; if(negedge_cnt[6:0] == 7'd23) ssp_frame <= 1'b0; @@ -525,23 +516,23 @@ begin if(negedge_cnt[3:0] == 4'd0) begin // What do we communicate to the ARM - if(mod_type == `TAGSIM_LISTEN) + if(mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN) sendbit = after_hysteresis; - else if(mod_type == `TAGSIM_MOD) + else if(mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD) /* if(fdt_counter > 11'd772) sendbit = mod_sig_coil; // huh? else */ sendbit = fdt_indicator; - else if (mod_type == `READER_LISTEN) + else if (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN) sendbit = curbit; else sendbit = 1'b0; end - if(mod_type == `SNIFFER) + if(mod_type == `FPGA_HF_ISO14443A_SNIFFER) // send sampled reader and tag data: bit_to_arm = to_arm[7]; - else if (mod_type == `TAGSIM_MOD && fdt_elapsed && temp_buffer_reset) + else if (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD && fdt_elapsed && temp_buffer_reset) // send timing information: bit_to_arm = to_arm[7]; else @@ -554,22 +545,22 @@ end assign ssp_din = bit_to_arm; -// Subcarrier (adc_clk/16, for TAGSIM_MOD only). +// Subcarrier (adc_clk/16, for FPGA_HF_ISO14443A_TAGSIM_MOD only). wire sub_carrier; assign sub_carrier = ~sub_carrier_cnt[3]; -// in READER_MOD: drop carrier for mod_sig_coil==1 (pause); in READER_LISTEN: carrier always on; in other modes: carrier always off -assign pwr_hi = (ck_1356megb & (((mod_type == `READER_MOD) & ~mod_sig_coil) || (mod_type == `READER_LISTEN))); +// in FPGA_HF_ISO14443A_READER_MOD: drop carrier for mod_sig_coil==1 (pause); in FPGA_HF_ISO14443A_READER_LISTEN: carrier always on; in other modes: carrier always off +assign pwr_hi = (ck_1356meg & (((mod_type == `FPGA_HF_ISO14443A_READER_MOD) & ~mod_sig_coil) || (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN))); // Enable HF antenna drivers: assign pwr_oe1 = 1'b0; assign pwr_oe3 = 1'b0; -// TAGSIM_MOD: short circuit antenna with different resistances (modulated by sub_carrier modulated by mod_sig_coil) +// FPGA_HF_ISO14443A_TAGSIM_MOD: short circuit antenna with different resistances (modulated by sub_carrier modulated by mod_sig_coil) // for pwr_oe4 = 1 (tristate): antenna load = 10k || 33 = 32,9 Ohms // for pwr_oe4 = 0 (active): antenna load = 10k || 33 || 33 = 16,5 Ohms -assign pwr_oe4 = mod_sig_coil & sub_carrier & (mod_type == `TAGSIM_MOD); +assign pwr_oe4 = mod_sig_coil & sub_carrier & (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD); // This is all LF, so doesn't matter. assign pwr_oe2 = 1'b0; diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index d336a5ddf..737dd4586 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -17,82 +17,105 @@ //----------------------------------------------------------------------------- module hi_simulate( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, dbg, mod_type ); - input pck0, ck_1356meg, ck_1356megb; + input ck_1356meg; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; input [7:0] adc_d; output adc_clk; input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; output dbg; - input [2:0] mod_type; + input [3:0] mod_type; // Power amp goes between LOW and tri-state, so pwr_hi (and pwr_lo) can // always be low. -assign pwr_hi = 1'b0; -assign pwr_lo = 1'b0; +assign pwr_hi = 1'b0; // HF antenna connected to GND +assign pwr_lo = 1'b0; // LF antenna connected to GND + +// This one is all LF, so doesn't matter +assign pwr_oe2 = 1'b0; + +assign adc_clk = ck_1356meg; +assign dbg = ssp_frame; // The comparator with hysteresis on the output from the peak detector. reg after_hysteresis; -assign adc_clk = ck_1356meg; +reg [11:0] has_been_low_for; always @(negedge adc_clk) begin - if(& adc_d[7:5]) after_hysteresis = 1'b1; - else if(~(| adc_d[7:5])) after_hysteresis = 1'b0; + if (& adc_d[7:5]) after_hysteresis <= 1'b1; // if (adc_d >= 224) + else if (~(| adc_d[7:5])) after_hysteresis <= 1'b0; // if (adc_d <= 31) + + if (adc_d >= 224) + begin + has_been_low_for <= 12'd0; + end + else + begin + if (has_been_low_for == 12'd4095) + begin + has_been_low_for <= 12'd0; + after_hysteresis <= 1'b1; + end + else + begin + has_been_low_for <= has_been_low_for + 1; + end + end end // Divide 13.56 MHz to produce various frequencies for SSP_CLK -// and modulation. 11 bits allow for factors of up to /128. -reg [10:0] ssp_clk_divider; +// and modulation. +reg [8:0] ssp_clk_divider; -always @(posedge adc_clk) +always @(negedge adc_clk) ssp_clk_divider <= (ssp_clk_divider + 1); reg ssp_clk; always @(negedge adc_clk) begin - if(mod_type == 3'b101) - // Get bit every at 53kHz (every 8th carrier bit of 424kHz) - ssp_clk <= ssp_clk_divider[7]; - else if(mod_type == 3'b010) + if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT) + // Get bit every at 53KHz (every 8th carrier bit of 424kHz) + ssp_clk <= ~ssp_clk_divider[7]; + else if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) // Get next bit at 212kHz - ssp_clk <= ssp_clk_divider[5]; + ssp_clk <= ~ssp_clk_divider[5]; else // Get next bit at 424kHz - ssp_clk <= ssp_clk_divider[4]; + ssp_clk <= ~ssp_clk_divider[4]; end -// Divide SSP_CLK by 8 to produce the byte framing signal; the phase of -// this is arbitrary, because it's just a bitstream. -// One nasty issue, though: I can't make it work with both rx and tx at -// once. The phase wrt ssp_clk must be changed. TODO to find out why -// that is and make a better fix. -reg [2:0] ssp_frame_divider_to_arm; -always @(posedge ssp_clk) - ssp_frame_divider_to_arm <= (ssp_frame_divider_to_arm + 1); -reg [2:0] ssp_frame_divider_from_arm; -always @(negedge ssp_clk) - ssp_frame_divider_from_arm <= (ssp_frame_divider_from_arm + 1); - - +// Produce the byte framing signal; the phase of this signal +// is arbitrary, because it's just a bit stream in this module. reg ssp_frame; -always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type) - if(mod_type == 3'b000) // not modulating, so listening, to ARM - ssp_frame = (ssp_frame_divider_to_arm == 3'b000); +always @(negedge adc_clk) +begin + if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) + begin + if (ssp_clk_divider[8:5] == 4'd1) + ssp_frame <= 1'b1; + if (ssp_clk_divider[8:5] == 4'd5) + ssp_frame <= 1'b0; + end else - ssp_frame = (ssp_frame_divider_from_arm == 3'b000); + begin + if (ssp_clk_divider[7:4] == 4'd1) + ssp_frame <= 1'b1; + if (ssp_clk_divider[7:4] == 4'd5) + ssp_frame <= 1'b0; + end +end + // Synchronize up the after-hysteresis signal, to produce DIN. reg ssp_din; @@ -101,29 +124,25 @@ always @(posedge ssp_clk) // Modulating carrier frequency is fc/64 (212kHz) to fc/16 (848kHz). Reuse ssp_clk divider for that. reg modulating_carrier; -always @(mod_type or ssp_clk or ssp_dout) - if(mod_type == 3'b000) +always @(*) + if(mod_type == `FPGA_HF_SIMULATOR_NO_MODULATION) modulating_carrier <= 1'b0; // no modulation - else if(mod_type == 3'b001) + else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_BPSK) modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK - else if(mod_type == 3'b010) + else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) modulating_carrier <= ssp_dout & ssp_clk_divider[5]; // switch 212kHz subcarrier on/off - else if(mod_type == 3'b100 || mod_type == 3'b101) + else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K || mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT) modulating_carrier <= ssp_dout & ssp_clk_divider[4]; // switch 424kHz modulation on/off else modulating_carrier <= 1'b0; // yet unused -// This one is all LF, so doesn't matter -assign pwr_oe2 = modulating_carrier; -// Toggle only one of these, since we are already producing much deeper + +// Load modulation. Toggle only one of these, since we are already producing much deeper // modulation than a real tag would. -assign pwr_oe1 = modulating_carrier; -assign pwr_oe4 = modulating_carrier; - +assign pwr_oe1 = 1'b0; // 33 Ohms Load +assign pwr_oe4 = modulating_carrier; // 33 Ohms Load // This one is always on, so that we can watch the carrier. -assign pwr_oe3 = 1'b0; - -assign dbg = ssp_din; +assign pwr_oe3 = 1'b0; // 10k Load endmodule diff --git a/fpga/hi_sniffer.v b/fpga/hi_sniffer.v index 3a989ce62..c2dc844a7 100644 --- a/fpga/hi_sniffer.v +++ b/fpga/hi_sniffer.v @@ -1,21 +1,14 @@ module hi_sniffer( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg, - xcorr_is_848, snoop, xcorr_quarter_freq // not used. + ssp_frame, ssp_din, ssp_clk ); - input pck0, ck_1356meg, ck_1356megb; + input ck_1356meg; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; input [7:0] adc_d; output adc_clk; - input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - input xcorr_is_848, snoop, xcorr_quarter_freq; // not used. // We are only snooping, all off. assign pwr_hi = 1'b0; From 41dde3281d0da555b42eb50ab0a4ff6d4850e9ba Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 11:49:22 +0200 Subject: [PATCH 002/139] add files --- fpga/fpga_felica.v | 228 ++++++++++++++++++++++++++++++ fpga/hi_reader.v | 335 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 563 insertions(+) create mode 100644 fpga/fpga_felica.v create mode 100644 fpga/hi_reader.v diff --git a/fpga/fpga_felica.v b/fpga/fpga_felica.v new file mode 100644 index 000000000..461d90b02 --- /dev/null +++ b/fpga/fpga_felica.v @@ -0,0 +1,228 @@ +//----------------------------------------------------------------------------- +// The FPGA is responsible for interfacing between the A/D, the coil drivers, +// and the ARM. In the low-frequency modes it passes the data straight +// through, so that the ARM gets raw A/D samples over the SSP. In the high- +// frequency modes, the FPGA might perform some demodulation first, to +// reduce the amount of data that we must send to the ARM. +// +// I am not really an FPGA/ASIC designer, so I am sure that a lot of this +// could be improved. +// +// Jonathan Westhues, March 2006 +// Added ISO14443-A support by Gerhard de Koning Gans, April 2008 +// iZsh , June 2014 +// Piwi, Feb 2019 +//----------------------------------------------------------------------------- + + +// Defining commands, modes and options. This must be aligned to the definitions in fpgaloader.h +// Note: the definitions here are without shifts + +// Commands: +`define FPGA_CMD_SET_CONFREG 1 +`define FPGA_CMD_TRACE_ENABLE 2 + +// Major modes: +`define FPGA_MAJOR_MODE_HF_READER 0 +`define FPGA_MAJOR_MODE_HF_SIMULATOR 1 +`define FPGA_MAJOR_MODE_HF_ISO14443A 2 +`define FPGA_MAJOR_MODE_HF_SNOOP 3 +`define FPGA_MAJOR_MODE_HF_ISO18092 4 +`define FPGA_MAJOR_MODE_HF_GET_TRACE 5 +`define FPGA_MAJOR_MODE_OFF 7 + +// Options for the generic HF reader +`define FPGA_HF_READER_MODE_RECEIVE_IQ 0 +`define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE 1 +`define FPGA_HF_READER_MODE_RECEIVE_PHASE 2 +`define FPGA_HF_READER_MODE_SEND_FULL_MOD 3 +`define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD 4 +`define FPGA_HF_READER_MODE_SNIFF_IQ 5 +`define FPGA_HF_READER_MODE_SNIFF_AMPLITUDE 6 +`define FPGA_HF_READER_MODE_SNIFF_PHASE 7 +`define FPGA_HF_READER_MODE_SEND_JAM 8 + +`define FPGA_HF_READER_SUBCARRIER_848_KHZ 0 +`define FPGA_HF_READER_SUBCARRIER_424_KHZ 1 +`define FPGA_HF_READER_SUBCARRIER_212_KHZ 2 + +// Options for the HF simulated tag, how to modulate +`define FPGA_HF_SIMULATOR_NO_MODULATION 0 +`define FPGA_HF_SIMULATOR_MODULATE_BPSK 1 +`define FPGA_HF_SIMULATOR_MODULATE_212K 2 +`define FPGA_HF_SIMULATOR_MODULATE_424K 4 +`define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 5 + +// Options for ISO14443A +`define FPGA_HF_ISO14443A_SNIFFER 0 +`define FPGA_HF_ISO14443A_TAGSIM_LISTEN 1 +`define FPGA_HF_ISO14443A_TAGSIM_MOD 2 +`define FPGA_HF_ISO14443A_READER_LISTEN 3 +`define FPGA_HF_ISO14443A_READER_MOD 4 + +//options for ISO18092 / Felica +`define FPGA_HF_ISO18092_FLAG_NOMOD 1 // 0001 disable modulation module +`define FPGA_HF_ISO18092_FLAG_424K 2 // 0010 should enable 414k mode (untested). No autodetect +`define FPGA_HF_ISO18092_FLAG_READER 4 // 0100 enables antenna power, to act as a reader instead of tag + +`include "hi_reader.v" +`include "hi_simulate.v" +//`include "hi_iso14443a.v" +`include "hi_sniffer.v" +`include "util.v" +`include "hi_flite.v" +`include "hi_get_trace.v" + +module fpga_felica( + input spck, output miso, input mosi, input ncs, + input pck0, input ck_1356meg, input ck_1356megb, + output pwr_lo, output pwr_hi, + output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4, + input [7:0] adc_d, output adc_clk, output adc_noe, + output ssp_frame, output ssp_din, input ssp_dout, output ssp_clk, + input cross_hi, input cross_lo, + output dbg +); + +//----------------------------------------------------------------------------- +// The SPI receiver. This sets up the configuration word, which the rest of +// the logic looks at to determine how to connect the A/D and the coil +// drivers (i.e., which section gets it). Also assign some symbolic names +// to the configuration bits, for use below. +//----------------------------------------------------------------------------- + +/* + Attempt to write up how its hooked up. Iceman 2020. + + Communication between ARM / FPGA is done inside armsrc/fpgaloader.c see: function FpgaSendCommand() + Send 16 bit command / data pair to FPGA + The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 + where + C is 4bit command + D is 12bit data + + shift_reg receive this 16bit frame + + +-----+--------- frame layout -------------------- +bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +-----+------------------------------------------- +cmd | x x x x +major| x x x +opt | x x x +divi | x x x x x x x x +thres| x x x x x x x x +-----+------------------------------------------- +*/ + +reg [15:0] shift_reg; +reg [8:0] conf_word; +reg trace_enable; + +// We switch modes between transmitting to the 13.56 MHz tag and receiving +// from it, which means that we must make sure that we can do so without +// glitching, or else we will glitch the transmitted carrier. +always @(posedge ncs) +begin + case(shift_reg[15:12]) + `FPGA_CMD_SET_CONFREG: conf_word <= shift_reg[8:0]; + `FPGA_CMD_TRACE_ENABLE: trace_enable <= shift_reg[0]; + endcase +end + +always @(posedge spck) +begin + if(~ncs) + begin + shift_reg[15:1] <= shift_reg[14:0]; + shift_reg[0] <= mosi; + end +end + +// select module (outputs) based on major mode +wire [2:0] major_mode = conf_word[8:6]; + +// configuring the HF reader +wire [1:0] subcarrier_frequency = conf_word[5:4]; +wire [3:0] minor_mode = conf_word[3:0]; + +//----------------------------------------------------------------------------- +// And then we instantiate the modules corresponding to each of the FPGA's +// major modes, and use muxes to connect the outputs of the active mode to +// the output pins. +//----------------------------------------------------------------------------- + +// 000 - HF reader +hi_reader hr( + ck_1356megb, + hr_pwr_lo, hr_pwr_hi, hr_pwr_oe1, hr_pwr_oe2, hr_pwr_oe3, hr_pwr_oe4, + adc_d, hr_adc_clk, + hr_ssp_frame, hr_ssp_din, ssp_dout, hr_ssp_clk, + hr_dbg, + subcarrier_frequency, minor_mode +); + +// 001 - HF simulated tag +hi_simulate hs( + ck_1356meg, + hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4, + adc_d, hs_adc_clk, + hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk, + hs_dbg, + minor_mode +); + +// 011 - HF sniff +hi_sniffer he( + ck_1356megb, + he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4, + adc_d, he_adc_clk, + he_ssp_frame, he_ssp_din, he_ssp_clk +); + +// 100 - HF ISO18092 FeliCa +/* +hi_flite hfl( + ck_1356megb, + hfl_pwr_lo, hfl_pwr_hi, hfl_pwr_oe1, hfl_pwr_oe2, hfl_pwr_oe3, hfl_pwr_oe4, + adc_d, hfl_adc_clk, + hfl_ssp_frame, hfl_ssp_din, ssp_dout, hfl_ssp_clk, + hfl_dbg, + minor_mode +); +*/ + +// 101 - HF get trace +hi_get_trace gt( + ck_1356megb, + adc_d, trace_enable, major_mode, + gt_ssp_frame, gt_ssp_din, gt_ssp_clk +); + +// Major modes: +// 000 -- HF reader; subcarrier frequency and modulation depth selectable +// 001 -- HF simulated tag +// 010 -- HF ISO14443-A - removed for space... +// 011 -- HF sniff +// 100 -- HF ISO18092 FeliCa +// 101 -- HF get trace +// 110 -- unused +// 111 -- FPGA_MAJOR_MODE_OFF + +// 000 001 010 011 100 101 110 111 +mux8 mux_ssp_clk (major_mode, ssp_clk, hr_ssp_clk, hs_ssp_clk, 1'b0, he_ssp_clk, hfl_ssp_clk, gt_ssp_clk, 1'b0, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, hr_ssp_din, hs_ssp_din, 1'b0, he_ssp_din, hfl_ssp_din, gt_ssp_din, 1'b0, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, hr_ssp_frame, hs_ssp_frame, 1'b0, he_ssp_frame, hfl_ssp_frame, gt_ssp_frame, 1'b0, 1'b0); +mux8 mux_pwr_oe1 (major_mode, pwr_oe1, hr_pwr_oe1, hs_pwr_oe1, 1'b0, he_pwr_oe1, hfl_pwr_oe1, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe2 (major_mode, pwr_oe2, hr_pwr_oe2, hs_pwr_oe2, 1'b0, he_pwr_oe2, hfl_pwr_oe2, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe3 (major_mode, pwr_oe3, hr_pwr_oe3, hs_pwr_oe3, 1'b0, he_pwr_oe3, hfl_pwr_oe3, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe4 (major_mode, pwr_oe4, hr_pwr_oe4, hs_pwr_oe4, 1'b0, he_pwr_oe4, hfl_pwr_oe4, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_lo (major_mode, pwr_lo, hr_pwr_lo, hs_pwr_lo, 1'b0, he_pwr_lo, hfl_pwr_lo, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, hr_pwr_hi, hs_pwr_hi, 1'b0, he_pwr_hi, hfl_pwr_hi, 1'b0, 1'b0, 1'b0); +mux8 mux_adc_clk (major_mode, adc_clk, hr_adc_clk, hs_adc_clk, 1'b0, he_adc_clk, hfl_adc_clk, 1'b0, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, hr_dbg, hs_dbg, 1'b0, he_dbg, hfl_dbg, 1'b0, 1'b0, 1'b0); + +// In all modes, let the ADC's outputs be enabled. +assign adc_noe = 1'b0; + +endmodule diff --git a/fpga/hi_reader.v b/fpga/hi_reader.v new file mode 100644 index 000000000..ab03f7ba4 --- /dev/null +++ b/fpga/hi_reader.v @@ -0,0 +1,335 @@ +//----------------------------------------------------------------------------- +// +// Jonathan Westhues, April 2006 +//----------------------------------------------------------------------------- + +module hi_reader( + ck_1356meg, + pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, + adc_d, adc_clk, + ssp_frame, ssp_din, ssp_dout, ssp_clk, + dbg, + subcarrier_frequency, minor_mode +); + input ck_1356meg; + output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; + input [7:0] adc_d; + output adc_clk; + input ssp_dout; + output ssp_frame, ssp_din, ssp_clk; + output dbg; + input [1:0] subcarrier_frequency; + input [3:0] minor_mode; + +assign adc_clk = ck_1356meg; // sample frequency is 13,56 MHz + +// 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, after_hysteresis_prev_prev; +reg [11:0] has_been_low_for; +always @(negedge adc_clk) +begin + if (& adc_d[7:0]) after_hysteresis <= 1'b1; + else if (~(| adc_d[7:0])) after_hysteresis <= 1'b0; + + if (after_hysteresis) + begin + has_been_low_for <= 12'd0; + end + else + begin + if (has_been_low_for == 12'd4095) + begin + has_been_low_for <= 12'd0; + after_hysteresis <= 1'b1; + end + else + has_been_low_for <= has_been_low_for + 1; + end +end + + +// Let us report a correlation every 64 samples. I.e. +// one Q/I pair after 4 subcarrier cycles for the 848kHz subcarrier, +// one Q/I pair after 2 subcarrier cycles for the 424kHz subcarriers, +// one Q/I pair for each subcarrier cyle for the 212kHz subcarrier. +// We need a 6-bit counter for the timing. +reg [5:0] corr_i_cnt; +always @(negedge adc_clk) +begin + corr_i_cnt <= corr_i_cnt + 1; +end + + +// A couple of registers in which to accumulate the correlations. From the 64 samples +// we would add at most 32 times the difference between unmodulated and modulated signal. It should +// be safe to assume that a tag will not be able to modulate the carrier signal by more than 25%. +// 32 * 255 * 0,25 = 2040, which can be held in 11 bits. Add 1 bit for sign. +// Temporary we might need more bits. For the 212kHz subcarrier we could possible add 32 times the +// maximum signal value before a first subtraction would occur. 32 * 255 = 8160 can be held in 13 bits. +// Add one bit for sign -> need 14 bit registers but final result will fit into 12 bits. +reg signed [13:0] corr_i_accum; +reg signed [13:0] corr_q_accum; +// we will report maximum 8 significant bits +reg signed [7:0] corr_i_out; +reg signed [7:0] corr_q_out; + + +// the amplitude of the subcarrier is sqrt(ci^2 + cq^2). +// approximate by amplitude = max(|ci|,|cq|) + 1/2*min(|ci|,|cq|) +reg [13:0] corr_amplitude, abs_ci, abs_cq, max_ci_cq; +reg [12:0] min_ci_cq_2; // min_ci_cq / 2 + +always @(*) +begin + if (corr_i_accum[13] == 1'b0) + abs_ci <= corr_i_accum; + else + abs_ci <= -corr_i_accum; + + if (corr_q_accum[13] == 1'b0) + abs_cq <= corr_q_accum; + else + abs_cq <= -corr_q_accum; + + if (abs_ci > abs_cq) + begin + max_ci_cq <= abs_ci; + min_ci_cq_2 <= abs_cq / 2; + end + else + begin + max_ci_cq <= abs_cq; + min_ci_cq_2 <= abs_ci / 2; + end + + corr_amplitude <= max_ci_cq + min_ci_cq_2; + +end + + +// The subcarrier reference signals +reg subcarrier_I; +reg subcarrier_Q; + +always @(*) +begin + if (subcarrier_frequency == `FPGA_HF_READER_SUBCARRIER_848_KHZ) + begin + subcarrier_I = ~corr_i_cnt[3]; + subcarrier_Q = ~(corr_i_cnt[3] ^ corr_i_cnt[2]); + end + else if (subcarrier_frequency == `FPGA_HF_READER_SUBCARRIER_212_KHZ) + begin + subcarrier_I = ~corr_i_cnt[5]; + subcarrier_Q = ~(corr_i_cnt[5] ^ corr_i_cnt[4]); + end + else + begin // 424 kHz + subcarrier_I = ~corr_i_cnt[4]; + subcarrier_Q = ~(corr_i_cnt[4] ^ corr_i_cnt[3]); + end +end + + +// ADC data appears on the rising edge, so sample it on the falling edge +always @(negedge adc_clk) +begin + // These are the correlators: we correlate against in-phase and quadrature + // versions of our reference signal, and keep the (signed) results or the + // resulting amplitude to send out later over the SSP. + if (corr_i_cnt == 6'd0) + begin + if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_AMPLITUDE) + begin + // send amplitude plus 2 bits reader signal + corr_i_out <= corr_amplitude[13:6]; + corr_q_out <= {corr_amplitude[5:0], after_hysteresis_prev_prev, after_hysteresis_prev}; + end + else if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_IQ) + begin + + // Send 7 most significant bits of in phase tag signal (signed), plus 1 bit reader signal + if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) + corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev}; + else // truncate to maximum value + if (corr_i_accum[13] == 1'b0) + corr_i_out <= {7'b0111111, after_hysteresis_prev_prev}; + else + corr_i_out <= {7'b1000000, after_hysteresis_prev_prev}; + + // Send 7 most significant bits of quadrature phase tag signal (signed), plus 1 bit reader signal + if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) + corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev}; + else // truncate to maximum value + if (corr_q_accum[13] == 1'b0) + corr_q_out <= {7'b0111111, after_hysteresis_prev}; + else + corr_q_out <= {7'b1000000, after_hysteresis_prev}; + end + else if (minor_mode == `FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE) + begin + // send amplitude + corr_i_out <= {2'b00, corr_amplitude[13:8]}; + corr_q_out <= corr_amplitude[7:0]; + end + else if (minor_mode == `FPGA_HF_READER_MODE_RECEIVE_IQ) + begin + + // Send 8 bits of in phase tag signal + if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) + corr_i_out <= corr_i_accum[11:4]; + else // truncate to maximum value + if (corr_i_accum[13] == 1'b0) + corr_i_out <= 8'b01111111; + else + corr_i_out <= 8'b10000000; + + // Send 8 bits of quadrature phase tag signal + if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) + corr_q_out <= corr_q_accum[11:4]; + else // truncate to maximum value + if (corr_q_accum[13] == 1'b0) + corr_q_out <= 8'b01111111; + else + corr_q_out <= 8'b10000000; + end + + // for each Q/I pair report two reader signal samples when sniffing. Store the 1st. + after_hysteresis_prev_prev <= after_hysteresis; + + // Initialize next correlation. + // Both I and Q reference signals are high when corr_i_nct == 0. Therefore need to accumulate. + corr_i_accum <= $signed({1'b0, adc_d}); + corr_q_accum <= $signed({1'b0, adc_d}); + end + else + begin + if (subcarrier_I) + corr_i_accum <= corr_i_accum + $signed({1'b0, adc_d}); + else + corr_i_accum <= corr_i_accum - $signed({1'b0, adc_d}); + + if (subcarrier_Q) + corr_q_accum <= corr_q_accum + $signed({1'b0, adc_d}); + else + corr_q_accum <= corr_q_accum - $signed({1'b0, adc_d}); + end + + // for each Q/I pair report two reader signal samples when sniffing. Store the 2nd. + 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. + // We get one report each cycle, and each report is 16 bits, so the + // ssp_clk should be the adc_clk divided by 64/16 = 4. + // ssp_clk frequency = 13,56MHz / 4 = 3.39MHz + + if (corr_i_cnt[1:0] == 2'b00) + begin + // Don't shift if we just loaded new data, obviously. + if (corr_i_cnt != 6'd0) + begin + corr_i_out[7:0] <= {corr_i_out[6:0], corr_q_out[7]}; + corr_q_out[7:1] <= corr_q_out[6:0]; + end + end + +end + + +// ssp clock and frame signal for communication to and from ARM +// _____ _____ _____ _ +// ssp_clk | |_____| |_____| |_____| +// _____ +// ssp_frame ___| |____________________________ +// ___________ ___________ ___________ _ +// ssp_d_in X___________X___________X___________X_ +// +// corr_i_cnt 0 1 2 3 4 5 6 7 8 9 10 11 12 ... +// + +reg ssp_clk; +reg ssp_frame; + +always @(negedge adc_clk) +begin + if (corr_i_cnt[1:0] == 2'b00) + ssp_clk <= 1'b1; + + if (corr_i_cnt[1:0] == 2'b10) + ssp_clk <= 1'b0; + + // set ssp_frame signal for corr_i_cnt = 1..3 + // (send one frame with 16 Bits) + if (corr_i_cnt == 6'd1) + ssp_frame <= 1'b1; + + if (corr_i_cnt == 6'd3) + ssp_frame <= 1'b0; +end + + +assign ssp_din = corr_i_out[7]; + + +// a jamming signal +reg jam_signal; +reg [3:0] jam_counter; + +always @(negedge adc_clk) +begin + if (corr_i_cnt == 6'd0) + begin + jam_counter <= jam_counter + 1; + jam_signal <= jam_counter[1] ^ jam_counter[3]; + end +end + +// Antenna drivers +reg pwr_hi, pwr_oe4; + +always @(*) +begin + if (minor_mode == `FPGA_HF_READER_MODE_SEND_SHALLOW_MOD) + begin + pwr_hi = ck_1356meg; + pwr_oe4 = ssp_dout; + end + else if (minor_mode == `FPGA_HF_READER_MODE_SEND_FULL_MOD) + begin + pwr_hi = ck_1356meg & ~ssp_dout; + pwr_oe4 = 1'b0; + end + else if (minor_mode == `FPGA_HF_READER_MODE_SEND_JAM) + begin + pwr_hi = ck_1356meg & jam_signal; + pwr_oe4 = 1'b0; + end + else if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_IQ + || minor_mode == `FPGA_HF_READER_MODE_SNIFF_AMPLITUDE + || minor_mode == `FPGA_HF_READER_MODE_SNIFF_PHASE) + begin // all off + pwr_hi = 1'b0; + pwr_oe4 = 1'b0; + end + else // receiving from tag + begin + pwr_hi = ck_1356meg; + pwr_oe4 = 1'b0; + end +end + +// always on +assign pwr_oe1 = 1'b0; +assign pwr_oe3 = 1'b0; + +// Unused. +assign pwr_lo = 1'b0; +assign pwr_oe2 = 1'b0; + +// Debug Output +assign dbg = corr_i_cnt[3]; + +endmodule From 081f397ed7bfdc6326592c5d2da153982203d5bc Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 11:49:46 +0200 Subject: [PATCH 003/139] remove --- fpga/xst_nfc.scr | 1 - 1 file changed, 1 deletion(-) delete mode 100644 fpga/xst_nfc.scr diff --git a/fpga/xst_nfc.scr b/fpga/xst_nfc.scr deleted file mode 100644 index 68f0d01e9..000000000 --- a/fpga/xst_nfc.scr +++ /dev/null @@ -1 +0,0 @@ -run -ifn fpga_nfc.v -ifmt Verilog -ofn fpga_nfc.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_nfc -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact From 59836bbb3b07082af0dbe48646bc86aca98a1460 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 11:50:01 +0200 Subject: [PATCH 004/139] remove --- fpga/hi_read_rx_xcorr.v | 197 ---------------------------------------- fpga/hi_read_tx.v | 78 ---------------- 2 files changed, 275 deletions(-) delete mode 100644 fpga/hi_read_rx_xcorr.v delete mode 100644 fpga/hi_read_tx.v diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v deleted file mode 100644 index be70b97b0..000000000 --- a/fpga/hi_read_rx_xcorr.v +++ /dev/null @@ -1,197 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Jonathan Westhues, April 2006 -//----------------------------------------------------------------------------- - -module hi_read_rx_xcorr( - pck0, ck_1356meg, ck_1356megb, - pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, - adc_d, adc_clk, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg, - xcorr_is_848, snoop, xcorr_quarter_freq -); - input pck0, ck_1356meg, ck_1356megb; - output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; - input [7:0] adc_d; - output adc_clk; - input ssp_dout; - output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - input xcorr_is_848, snoop, xcorr_quarter_freq; - -// Carrier is steady on through this, unless we're snooping. -assign pwr_hi = ck_1356megb & (~snoop); -assign pwr_oe1 = 1'b0; -assign pwr_oe3 = 1'b0; -assign pwr_oe4 = 1'b0; - -reg [2:0] fc_div; -always @(negedge ck_1356megb) - fc_div <= fc_div + 1; - -(* clock_signal = "yes" *) reg adc_clk; // sample frequency, always 16 * fc -always @(ck_1356megb, xcorr_is_848, xcorr_quarter_freq, fc_div) - if (xcorr_is_848 & ~xcorr_quarter_freq) // fc = 847.5 kHz, standard ISO14443B - adc_clk <= ck_1356megb; - else if (~xcorr_is_848 & ~xcorr_quarter_freq) // fc = 423.75 kHz - adc_clk <= fc_div[0]; - else if (xcorr_is_848 & xcorr_quarter_freq) // fc = 211.875 kHz - adc_clk <= fc_div[1]; - else // fc = 105.9375 kHz - adc_clk <= fc_div[2]; - -// 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, after_hysteresis_prev_prev; -reg [11:0] has_been_low_for; -always @(negedge adc_clk) -begin - if(& adc_d[7:0]) after_hysteresis <= 1'b1; - else if(~(| adc_d[7:0])) after_hysteresis <= 1'b0; - - if(after_hysteresis) - begin - has_been_low_for <= 7'b0; - end - else - begin - if(has_been_low_for == 12'd4095) - begin - has_been_low_for <= 12'd0; - after_hysteresis <= 1'b1; - end - else - has_been_low_for <= has_been_low_for + 1; - end -end - -// Let us report a correlation every 4 subcarrier cycles, or 4*16=64 samples, -// so we need a 6-bit counter. -reg [5:0] corr_i_cnt; - -// And a couple of registers in which to accumulate the correlations. Since -// load modulation saturates the ADC we have to use a large enough register -// 32 * 255 = 8160, which can be held in 13 bits. Add 1 bit for sign. -// -// The initial code assumed a phase shift of up to 25% and the accumulators were -// 11 bits (32 * 255 * 0,25 = 2040), we will pack all bits exceeding 11 bits into -// MSB. This prevents under/-overflows but preserves sensitivity on the lower end. -reg signed [13:0] corr_i_accum; -reg signed [13:0] corr_q_accum; - -// we will report maximum 8 significant bits -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 - 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) -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 == 6'd0) - begin - // send 10 bits of tag signal, 4 MSBs are stuffed into 2 MSB - if(~corr_i_accum[13]) - corr_i_out <= {corr_i_accum[13], - corr_i_accum[12] | corr_i_accum[11] | corr_i_accum[10], - corr_i_accum[12] | corr_i_accum[11] | corr_i_accum[9], - corr_i_accum[8:4]}; - else - corr_i_out <= {corr_i_accum[13], - corr_i_accum[12] & corr_i_accum[11] & corr_i_accum[10], - corr_i_accum[12] & corr_i_accum[11] & corr_i_accum[9], - corr_i_accum[8:4]}; - - if(~corr_q_accum[13]) - corr_q_out <= {corr_q_accum[13], - corr_q_accum[12] | corr_q_accum[11] | corr_q_accum[10], - corr_q_accum[12] | corr_q_accum[11] | corr_q_accum[9], - corr_q_accum[8:4]}; - else - corr_q_out <= {corr_q_accum[13], - corr_q_accum[12] & corr_q_accum[11] & corr_q_accum[10], - corr_q_accum[12] & corr_q_accum[11] & corr_q_accum[9], - corr_q_accum[8:4]}; - - if(snoop) - begin - // replace LSB with 1 bit reader signal - corr_i_out[0] <= after_hysteresis_prev_prev; - corr_q_out[0] <= after_hysteresis_prev; - after_hysteresis_prev_prev <= after_hysteresis; - end - - corr_i_accum <= adc_d; - corr_q_accum <= adc_d; - end - else - begin - if(corr_i_cnt[3]) - corr_i_accum <= corr_i_accum - adc_d; - else - corr_i_accum <= corr_i_accum + adc_d; - - 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; - - 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'd32) - after_hysteresis_prev <= after_hysteresis; - - // Then the result from last time is serialized and send out to the ARM. - // We get one report each cycle, and each report is 16 bits, so the - // ssp_clk should be the adc_clk divided by 64/16 = 4. - - if(corr_i_cnt[1:0] == 2'b10) - ssp_clk <= 1'b0; - - if(corr_i_cnt[1:0] == 2'b00) - begin - ssp_clk <= 1'b1; - // Don't shift if we just loaded new data, obviously. - if(corr_i_cnt != 6'd0) - begin - corr_i_out[7:0] <= {corr_i_out[6:0], corr_q_out[7]}; - corr_q_out[7:1] <= corr_q_out[6:0]; - end - end - - // 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; - -end - -assign ssp_din = corr_i_out[7]; - -assign dbg = corr_i_cnt[3]; - -// Unused. -assign pwr_lo = 1'b0; -assign pwr_oe2 = 1'b0; - -endmodule diff --git a/fpga/hi_read_tx.v b/fpga/hi_read_tx.v deleted file mode 100644 index f9550ed24..000000000 --- a/fpga/hi_read_tx.v +++ /dev/null @@ -1,78 +0,0 @@ -//----------------------------------------------------------------------------- -// The way that we connect things when transmitting a command to an ISO -// 15693 tag, using 100% modulation only for now. -// -// Jonathan Westhues, April 2006 -//----------------------------------------------------------------------------- - -module hi_read_tx( - pck0, ck_1356meg, ck_1356megb, - pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, - adc_d, adc_clk, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg, - shallow_modulation -); - input pck0, ck_1356meg, ck_1356megb; - output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; - input [7:0] adc_d; - output adc_clk; - input ssp_dout; - output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - input shallow_modulation; - -// low frequency outputs, not relevant -assign pwr_lo = 1'b0; -assign pwr_oe2 = 1'b0; - -// The high-frequency stuff. For now, for testing, just bring out the carrier, -// and allow the ARM to modulate it over the SSP. -reg pwr_hi; -reg pwr_oe1; -reg pwr_oe3; -reg pwr_oe4; - -always @(ck_1356megb or ssp_dout or shallow_modulation) -begin - if(shallow_modulation) - begin - pwr_hi <= ck_1356megb; - pwr_oe1 <= 1'b0; - pwr_oe3 <= 1'b0; - pwr_oe4 <= ~ssp_dout; - end - else - begin - pwr_hi <= ck_1356megb & ssp_dout; - pwr_oe1 <= 1'b0; - pwr_oe3 <= 1'b0; - pwr_oe4 <= 1'b0; - end -end - - -// Then just divide the 13.56 MHz clock down to produce appropriate clocks -// for the synchronous serial port. - -reg [6:0] hi_div_by_128; - -always @(posedge ck_1356meg) - hi_div_by_128 <= hi_div_by_128 + 1; - -assign ssp_clk = hi_div_by_128[6]; - -reg [2:0] hi_byte_div; - -always @(negedge ssp_clk) - hi_byte_div <= hi_byte_div + 1; - -assign ssp_frame = (hi_byte_div == 3'b000); - -assign ssp_din = 1'b0; - -assign dbg = ssp_frame; - -endmodule From da947affeb6a9b3d420c6a97a5731472edd02e13 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 11:51:07 +0200 Subject: [PATCH 005/139] felica fpga scr file --- fpga/xst_felica.scr | 1 + 1 file changed, 1 insertion(+) create mode 100644 fpga/xst_felica.scr diff --git a/fpga/xst_felica.scr b/fpga/xst_felica.scr new file mode 100644 index 000000000..b069fab13 --- /dev/null +++ b/fpga/xst_felica.scr @@ -0,0 +1 @@ +run -ifn fpga_felica.v -ifmt Verilog -ofn fpga_felica.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_felica -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact From fdd0487c37d2993df1a7448efadba1ec00d9f20b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 11:51:52 +0200 Subject: [PATCH 006/139] updated bit files --- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/fpga_lf.bit | Bin 42175 -> 42175 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 9a054eec60c9bb30acbe343f4c6685039cd9d260..7d20e220fd35db4ff4743ce9abe5571984253151 100644 GIT binary patch literal 42175 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 z zC-CzlxtMKm_73j|4_fYr)lq(4l&^K4QLAap!38zb^Izh;73Qn3OdQ8IxW_hztuI93 zWaLb<_$5q4_=NiTbf+xgLoIqn?H40rPrEx^$bUgL)N&!830XrR%y`S{iFt+JW>fjE zBDqDeGp}+qjy@SmSYE1>4Nmyznr?!2aj1p3fKDJRw7kQ>ILkrMbvS2VqI4~NUkQuN z*$_gmMNGBztf7fQ{tIQ;g#5BBn}>cV$DGfImv#R@SWFygG(IDYYQE-c8is% z75V%Z>JQDpVU(YpWE&K6bmYG%ZLTKQcMJKiEYzOWzX{s4Rm>lEVer~doYg5D1WQff z7cvnXb6?1ww>lkf8nC6&b_Hik7Z>h7ME=VRi@*Tlx)<(Qx}(lkAJ^V+7KqJ{&p0r} zzcMWACE}8H@i1H7rJmyBC1K0cg+pgq`;z%DX?n=QKsK}?a8=#}5+Qc4)u!FQu@={S zfp+a@quTz2mnVAT^RhSAMov!WU;8<12lmDH6NuP$*WB4pn@}BR7W6~pzX-G|xMo4^p$j;VEvEp60xJC~o+WGU!N|!1~TNQ9pmP zjY9e#vUK8R8~iJu|9ZlP0`sOv`pl2$;6pfsa+$_r2Lxuyieqv-x%;D_A4=MVdlakO z>(#IcMG-e5s`>oa!?C@RTYVQ2>T6W3>Fw(OqAr>*jL*9s&+U0xfB3BQ*mBGp%qmL; z9waJJLAvl!ND?}q31e6RBu8b z!#R$WXS`59kJHLITs|ASV1}92tB%3jgdg78yCToOP=Dw^Ep%pt>9XB`D^I{vjyrqA zs$Kc~m$pvsLnq;8b^Ji2iu8xQ&6E(0J7jGp-4G!acF#hjd9S6ISoa3R(+ohLV&l1W=d;Jz5#GoHN!6BNs(^o9Cu1amU6;<;S4QdO*}4=P z6~7l~Q5?98bJ=o&)9UB#7@|r7BkPs{r+m&6U8pOFuiRC@uSWV$tc3yK#iA@4M7>bG zb)daE?!Q#Xf3?bU0eJJQOY6tGfHQvpWZ!3Ff_eQgWcG?$``_DGIdzG-wm!(@T^4f( z^!0`Md5sQJlR(C2Go4mK9qt9sZKl7N3%lF}{JJ*9F$)LFB=PInu6jAIPibiv@_Ol< zeGL|6*io^Nmm+MY-&1HC=Jf&AJ-o^Nq?*UCjgo&ky5-W*upZK5Fe1dONqs?0zJ7jt ze2e&O5NWR)O(enw0lsh227%L*>sh{j15s0Co`YM$B;B?|!eS1^d3JI0`r-bTmm-Vo z(oE-K>nnPL(Cu08(NW%vCrvy5)jFXqu{`2A#J$!*s&~{(Y_cdDy%+FHW}Mq#r!r3z zFxR!}GnvM>nN}-^81i4DE(RdWL#;Rc6smI}G8-a`H1r*b+t7og6iBRs_2X;mtUSwx%4f0=)Z zCv4=uHZgBJAs+EZAZ<`W0irom`7gcbdAeW6mArScy9G*3T53#aR`*jq$KVea@C(=W zM!`Mr7T}fKm0WXqao|4xOKY{ma$e`LV zTVC#y_ixaZIPzc9_*ZZ2$x3C|h_X5S=k$m>(a!p4ua1iPXn8*WCGVfd)i*O)lmt~- zx3)9W+K22Q>Z7jmFRS9P7!sCcm`oM6V-c?1*l6vF1vr@n{`G6R$i3s9fzEZJ=S0Yv zpTfZ+xhPn{tG^}aExPCpAK!}W^bxclOqZopnS=hJ@YtAXQ2KBMH+ACL4RU8XO&tv+ z**eGRxZU7iccPkFvwb?WzZbZjlJrb@P~SpT>BJC(@lMrpVEB3b^5MKWaGB!kOcV>X z+%^O zk3qVFuPxvgWGM1D>bNpV&vFm{|Knd?sGx^8J8FnfW+OXaj)I7l1zrH6UB$0Uv{i3# zvis0Q-kHW`cDAeAvPhpXjepslrj24-_qFXPOZr6hx2GFRUa~Jl-9pNNP8t)-Y1-X<)!<+ znXf-=6+IMl5E?~riXlL^`x$aTn$N{Q<0i)#-Zq<&&uar!~h6YLzOzwm`Tpv=hUzn;?NeJQK3UPx2Qz(bvkWR=qA3;2cG zr>)(`-B5rL0Ece#^s8qz1kwtCERSE{U+q=kU*-vI3xqP`J}>Y~n@`w3+jDV(gL48K zcT|nt+J>2D2fvf|zk!DLd4Y=ufgPa-a3lobPR|Us*0?l?KvM43BeEMdWvT|X zYT2yOJ58gbvVnEkEM;X=4U#M|W@`l3pDB6ZFpCy3WaCz$YqWPIDKx0Knp%mdV$p~7VM(tKAEFMG6I9$St_Gt;`(L9t zzg&@Ub!wj{&k60;<|KTld?wU?SGwfSBpc1?Y73l=p!Ifph;~cVt7?ClT%OLIo8dMb zM!~)lvvSYNeQP^+)ZBllXZ5)|*)J-VtOspjVm!3?f3}TmuJV^cv*1ibLSP(XVpOq; z;Qg;8?vJtr_eDp1q0Ohgurk;DrEItO7Vm$le7VYB*VFyf?%|9)?kJ;j8BQnWFYK;$ zZj{nc$gxA$M!+FD}1SiB8}SnM_NTh&!b zuEhm(Tpa9wmFc6~7b%!sr+9il$N_umqx`e>+{k~(_Ser!%wO1c|6esRAc!?FURqjAf<&=iO=E(lqf$G58DwsRyS!!L6t-35`8>}h^Q5wPJ z5iK5Mgi2g&jwK&ZB9~ZzUk$lsuOXWo_VtV7HxO0M^VkpRJpujNk(guZ84~*L>$1YQ zMEs%Gw8!{M0culC3pSsmGtQEg+nA}fei`s@{2Sq%ik{)b+spMF2kT+yrW5;m4|&*6iTJBi=s8?r#Rz329NleaC&ml*JPcaN^@6L(M7<8; zD;2`LmpTaZ23gpU_0YKyf4L^=r7&zTek^Rij$j}m0@+JCwe}ZZ1KZE@;m0_N*5sPU zP##Q-nEibH^5U=2+e2OMC7WV*&}-gR0te4;rI);}cFd3ge|gTY4eWNgQ}-f|`$gLe z_DHc4)?b^K%);-d+viAp6gzzzBrK@`dO)-v;l;mzA7HpXi`((Fe&POkTnpJI?^hf@ z&kE}l*NY*0CcHh((f-#d`qB2M*C+PH?yy$2F5u5G7<62A%f^vv{2@X>EqrIBviW17 z4YAWrKLPlg;@pp`{Pl?U8`Ui_s}ESO81uZ&J)3_>Z{-(x$pwiPU%!sTp)v;SK@)dt zad{edU}NQFiGqz(?JvF)tX+02Msvd*y4cQ`cgtPo>;>S0O;q6isuEY74O8ti7=jc01bHSZ{pR)h(AzCnMXL0S}`ykfjJYy@pfr|+`v(@^Smh|sZ;6~v{1x%PHD$QK=XQ%`$GOY!r%YG zZK8=m@k^-{}m&5!z0AaiR!Ef;s+B_xs88!}L3WYY!{n(^sH7jpYRH-=N(p>DAa@;IC)>^I!TN z=}`nCBGS^VJ^$r@YN``vmqZ|ki$?f0UCZlCN<{Y8dZn$c9mO%wRvU+8jM^{5E&!tm zKMpMup9#-^P62J1m-i)(6+h_tG0nXeeOl!&cncu|+M+FTT_Lf`{0~C>SfRrT^^4Ch zGw0e$hi!CoUsRlv#$5zQVq|}PfO#Hjbu9KKUa(0rlX<%a3}cd6KvU_ zI(4OAfqWa;@Oc^J3;*Fve|?Df4Ttv>5`-ykc(3Sa7{=bju$m$8_JF_g&@bLoNF2lc zQM>SMl=_vsSBZb1%eWRRL;l*sAuBHC%msuq&ZirWn~&2r)#|eC>GyjX-*-4ebI`nq z-*}To+{O%i=08{6Zt{UJegpR($}{a4bq~fyAq;?x6%FP-SQEb?xqYtirijZ<(lbuu z!D(6RC|1j`$fEtPMQ}0A8MeP4>kz&nhP$utGrKWJ%m!aC5I-;2+N#INR@#lZZkBBt zZP;<9hLMKreEll-OgEm8b1V5u+hV$#)_JhMutKx{+`D(MVS}F!?w_~${@%v54S#0+ zKs{A%Jl?yAM%5R~Q}0ZC-Q?j+_Vs%(Lt_7H#5iR=&Gjnxu7}3K{_0K?O_yaP`0HJD zX=UnhEaT6P%ohk>?4}oo=C|VDmE-ppzW*h0+s2rU?-O~CBaqczVeV}ErL$`^F?e6V zDGsc!e@5#x6pF7pkAL+t1**M?y&@_R@z;hHT#3-!S+VDVvJohCyPY(jqkE4Dw|aln zlj(nK?A?J_U81>(~`6mR^&sI~zwZCpg?b zDn8eF250D@df$-fTsgapgDO9wwj-DmBL1?lk0w0O7S{{m+_*oAwo{qvv*G<4y#IyI zGI|M~>-Hi3FgY?~tMeNZ4uQd#i0OH?e5wBWh6G!EjPhKq4KbcK6v`a&7ru96W0`RV z`<3u9nwWO7G>Q{pu$LqI>m3+xh}PI=zC%wJ@$r|f%`=*Z!Dz#KYwR!D-vJkHwho6H zoKD$cHNZ#8QHiq`RAg|e*7E|#vCDRI z^L3yfTvpaz{Lt4gKL7QEY8CfyGGCF8-#4plubui8`!Ut}D|qWU`5k^#XgjLe-s}C!`)d+Pc(VgME*mxk7RG^j5ZiP zi&W=Gtb-2mN~Sy`ir)Z#i7U1v8p?sbU!g#?8Ox98sGeWOR^7-ICli~B4}yHZ!TiNB zC#Yb)E{fkcivH@XK%4G^*@a0a+lI(kB@~FPCVm4xnR3&~#FOd;I7k~GzNEu^p}c?l zsmhEfenW4UTiaC8HQ|=0saDJbJ6zq|REkCR7tfF!1s8+MrVP7)0}L*B{;LAr!IG~$ z&$YkDh8Ti95N%kA>@Tba+m2iU^F%yFGx7_M@kNLfL;Qw0=Jy51M?ETqgo}V<`Mxjn zI*@}SI->n$&0lIBEhnrq`5+i*tIa;5_Lnh!!t=`)qs-p35^MFB=!{&r0%03`f7GHv z)3K`m(63h#u04m)gAsKt{KAO0&fbfC#+w_r!C#{R+% zore;RIr~j~Hih@>hER)+5peDx>ki^KP@Ua{`UlJt>M1!#4s%2CLAe_Kg8%Rg)FJ7+ z1eX*Lh~tAEF1@{)!1~yD#9d`PQPoe_m~l z>@Pm8%=TCFEYkkN6XqB1{&x0{v6X1P;P-|8ekBS1h9mJBsbZ(isRoZR7$cGWg=j;8 zBUIls=b0r1#{wL8_4kQ-1sMgBv~hu-|kwhv?b>Fgo64Ufl`kiJN&#(&6rTdmM9 zZ07KlhW5(XpVAi5O12xtZxD14F5JXvQ(r{yahd5KX&u4m>5<_6!ue&MTNWg`QTKh& zFZAgEt|%5{i>m)npZ_}6bbIUv3X0}+av5QpUw`46$C<#0+I`vQM0@s@9oy-ja` zztB68{lz=!^Koo>Mpk@6cN_tKf$Y?60{&jFPp?J!`<0lVkHH3M<%LHDD)X-Wj1;bo zd}P31h*-c_g^Zx5#T?nNvxuNR7k5w$6)T~BCAnTKgL+|c(%_h*h#4pg%o~Rct~&gO zx1c;2KVVM`wmII^5tK)NXc&w3kiWRh2MD_-zCY^6gRu|v7ZRJi*xoul=IL-xY*4=H zTxB&LjDRuNqf@*t|6Pas;v0>dXi2r7KvucUDU-RPyWRsaU$ z1I8MXUMg$Js9q#7ed5?22$&oLz(&E~btdWwWDdJngA@sKzo-F5ky@4A6TIuNjJw8{ zX&G8WgVi#v>ed^1q@<%V%a}{Y36aZ6gNvws81Ficn>!jKnVgj!N{U|FIaC9@r0B7o zuniSamXZ`B@*;rmIr%Aq^n*UlDx5U4twSMrECJK1yRV* ztfmzJM#eDFI%yg9SDn$L3T{g#UISM6DHPOe$TUbv;qX{xP~fp@m3nYZvlYr5UKU%S zUUIL@G**GRVo0Zi@7l5~zH#U#cTFZeW`tl$0KA~g{mWt-)vNARnZ_~G2L=nj>i$*c zQZMD#tG}90l%cgzB{^p= zt260PreDSfjhko#Lj}Z z>aQaiqi#@s*SXxPKWGlh>CV@DfRvVcFBGyuUS>Mh1U;G#m^zX%jewVn=YWi*!hDFT zd}?JtH?_nX2-(EEe2qvQu^3DV!OD)73+8hkK}Y#a;AJ?@0)lpN*I4k(ZnoRdOFL;M)hi9^G=T75P<@dzMp^nN@^WjehMYA?r7#XB@Nz`Z48nIA5^5Fc z*Et|~mr<)DfuQ*kdsKY;^SQta^1-<6lF34> zg$`3!4+96lPdOC6tJiW5X0pqYsm+$_F)#r96cx0gA!)*NVv&^5da{pu^ETC9E}1>i6+I7RA|u)k{7Vzqr<)P3O>+Na}P5ii#QUjqGgee4GL z(y=QSG@cJ+STEbUm1?*kA_V|1$cUJZn?qin0D3}^KPWFxq~nmFzZJdfd^!$OK8a)| z@Nz`Z8bmT}B@0LYa}7>gDG4C!onomSU*wgzLo|AHqxV#8!VGhdw3v;er<80ZJ7+pn zvH_&oqDpYm*wU!VWUPxYBf?_M_?8N1m^46NqAFvnHo-^oDbMS^VS(L4RVT0rYzyDS zgyz7^fx2S!DuUsoN1)XXOEh?FvWJ3v_J;Xnlodnk4&ZnhJFhI?jm$}Fdv4@RPm5@CX$?N9j~b!`kc2W0GUXTPOhMcoq3mb&?2p&%HC(KBf!|n}#LYG5n z|0i^LP$^`G|D+cHH%O_`Wv#;albAFlG+95M|0DWWq1gHfevpV#{B(XzFumZ?r?4dG z+1jV7r{jU@ExjvHkVxzTGNJGVWZoTr*W+aTl@Bf;GagI@OG9uWncqW~?_3(_^4SCD z%n4D3p9&DxZ*T`^DR=Fs3QhiEvIQnvV6p`!TVS#UCR<>#1wO+qpw~-SFk!tUKf}#1 zS@p>lm~4T`7MN^-$rhMwfzN0QWOXp#NB@*11(zVjvLx$&pQZ@p<5?>6-(f99_<8VK I=l<>g0hW%~E&u=k literal 42175 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 diff --git a/fpga/fpga_lf.bit b/fpga/fpga_lf.bit index ba6b4322e6d470175b46d7116b49ddceaa3408f3..dca02afcc2e275d3dcb454e6c3629be3fb1af94a 100644 GIT binary patch literal 42175 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 From e2f0f08202d463bad9162e368f922e06e776bb64 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 11:52:16 +0200 Subject: [PATCH 007/139] added felica bit file --- fpga/fpga_felica.bit | Bin 0 -> 42179 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 fpga/fpga_felica.bit diff --git a/fpga/fpga_felica.bit b/fpga/fpga_felica.bit new file mode 100644 index 0000000000000000000000000000000000000000..dc68b740b025bee0adeee9d72a787e1216b84b5c GIT binary patch literal 42179 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 Date: Thu, 2 Jul 2020 12:32:55 +0200 Subject: [PATCH 008/139] chg: scc frames 16 or 8 bit wide --- armsrc/fpgaloader.c | 18 +++++++++------- armsrc/fpgaloader.h | 50 +++++++++++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index f1f157eec..8313404bf 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -134,7 +134,7 @@ void SetupSpi(int mode) { // Set up the synchronous serial port with the set of options that fits // the FPGA mode. Both RX and TX are always enabled. //----------------------------------------------------------------------------- -void FpgaSetupSsc(void) { +void FpgaSetupSsc(uint16_t fpga_mode) { // First configure the GPIOs, and get ourselves a clock. AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_FRAME | @@ -152,12 +152,16 @@ void FpgaSetupSsc(void) { // data and frame signal is sampled on falling edge of RK AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); - // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync + // 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync // pulse, no output sync - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); + if ((fpga_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) { + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); + } else { + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); + } - // TX clock comes from TK pin, no clock output, outputs change on falling - // edge of TK, frame sync is sampled on rising edge of TK, start TX on rising edge of TF + // TX clock comes from TK pin, no clock output, outputs change on rising edge of TK, + // TF (frame sync) is sampled on falling edge of TK, start TX on rising edge of TF AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); // tx framing is the same as the rx framing @@ -171,7 +175,7 @@ void FpgaSetupSsc(void) { // a single buffer as a circular buffer (so that we just chain back to // ourselves, not to another buffer). //----------------------------------------------------------------------------- -bool FpgaSetupSscDma(uint8_t *buf, int len) { +bool FpgaSetupSscDma(uint8_t *buf, uint16_t len) { if (buf == NULL) return false; FpgaDisableSscDma(); @@ -439,7 +443,7 @@ void FpgaDownloadAndGo(int bitstream_version) { // The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 // where C is the 4 bit command and D is the 12 bit data // -// @params cmd and v gets or over eachother. Take careful note of overlapping bits. +// @params cmd and v gets OR:ED over each other. Take careful note of overlapping bits. //----------------------------------------------------------------------------- void FpgaSendCommand(uint16_t cmd, uint16_t v) { SetupSpi(SPI_FPGA_MODE); diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 636c5b7b7..474c08e1a 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -52,23 +52,26 @@ thres| x x x x x x x x #define FPGA_CMD_TRACE_ENABLE (2<<12) // C // Definitions for the FPGA configuration word. +#define FPGA_MAJOR_MODE_MASK 0x01C0 +#define FPGA_MINOR_MODE_MASK 0x003F + // LF -#define FPGA_MAJOR_MODE_LF_READER (0<<5) -#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) -#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) -#define FPGA_MAJOR_MODE_LF_ADC (3<<5) +#define FPGA_MAJOR_MODE_LF_READER (0<<6) +#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<6) +#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<6) +#define FPGA_MAJOR_MODE_LF_ADC (3<<6) // HF -#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) // D -#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) // D -#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) // D -#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) // D -#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) // D -#define FPGA_MAJOR_MODE_HF_ISO18092 (5<<5) // D -#define FPGA_MAJOR_MODE_HF_GET_TRACE (6<<5) // D +#define FPGA_MAJOR_MODE_HF_READER (0<<6) // D +#define FPGA_MAJOR_MODE_HF_SIMULATOR (1<<6) // D +#define FPGA_MAJOR_MODE_HF_ISO14443A (2<<6) // D +#define FPGA_MAJOR_MODE_HF_SNOOP (3<<6) // D +#define FPGA_MAJOR_MODE_HF_ISO18092 (4<<6) // D +#define FPGA_MAJOR_MODE_HF_GET_TRACE (5<<6) // D // BOTH HF / LF -#define FPGA_MAJOR_MODE_OFF (7<<5) // D +#define FPGA_MAJOR_MODE_OFF (7<<6) // D + // Options for LF_READER #define FPGA_LF_ADC_READER_FIELD 0x1 @@ -78,13 +81,20 @@ thres| x x x x x x x x #define FPGA_LF_EDGE_DETECT_READER_FIELD 0x1 #define FPGA_LF_EDGE_DETECT_TOGGLE_MODE 0x2 -// Options for the HF reader, tx to tag -#define FPGA_HF_READER_TX_SHALLOW_MOD 0x1 +// Options for the HF reader +#define FPGA_HF_READER_MODE_RECEIVE_IQ (0<<0) +#define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE (1<<0) +#define FPGA_HF_READER_MODE_RECEIVE_PHASE (2<<0) +#define FPGA_HF_READER_MODE_SEND_FULL_MOD (3<<0) +#define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD (4<<0) +#define FPGA_HF_READER_MODE_SNOOP_IQ (5<<0) +#define FPGA_HF_READER_MODE_SNOOP_AMPLITUDE (6<<0) +#define FPGA_HF_READER_MODE_SNOOP_PHASE (7<<0) +#define FPGA_HF_READER_MODE_SEND_JAM (8<<0) -// Options for the HF reader, correlating against rx from tag -#define FPGA_HF_READER_RX_XCORR_848_KHZ 0x1 -#define FPGA_HF_READER_RX_XCORR_SNOOP 0x2 -#define FPGA_HF_READER_RX_XCORR_QUARTER 0x4 +#define FPGA_HF_READER_SUBCARRIER_848_KHZ (0<<4) +#define FPGA_HF_READER_SUBCARRIER_424_KHZ (1<<4) +#define FPGA_HF_READER_SUBCARRIER_212_KHZ (2<<4) // Options for the HF simulated tag, how to modulate #define FPGA_HF_SIMULATOR_NO_MODULATION 0x0 // 0000 @@ -112,9 +122,9 @@ void FpgaEnableTracing(void); void FpgaDisableTracing(void); void FpgaDownloadAndGo(int bitstream_version); // void FpgaGatherVersion(int bitstream_version, char *dst, int len); -void FpgaSetupSsc(void); +void FpgaSetupSsc(uint16_t fpga_mode); void SetupSpi(int mode); -bool FpgaSetupSscDma(uint8_t *buf, int len); +bool FpgaSetupSscDma(uint8_t *buf, uint16_t len); void Fpga_print_status(void); int FpgaGetCurrent(void); void SetAdcMuxFor(uint32_t whichGpio); From 2f4335d31e3031a82e809d6fd253237889c2a800 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:33:23 +0200 Subject: [PATCH 009/139] chg: ssp clock changes --- armsrc/ticks.c | 56 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/armsrc/ticks.c b/armsrc/ticks.c index 0ce55e417..e9cbea219 100644 --- a/armsrc/ticks.c +++ b/armsrc/ticks.c @@ -117,47 +117,61 @@ uint32_t RAMFUNC GetCountUS(void) { void StartCountSspClk(void) { AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 - | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none - | AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0 + | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none + | AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0 // configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs: AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1 AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz - | AT91C_TC_CPCSTOP // Stop clock on RC compare - | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event - | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16) - | AT91C_TC_ENETRG // Enable external trigger event - | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_AEEVT_SET // Set TIOA1 on external event - | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare - AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04 + | AT91C_TC_CPCSTOP // Stop clock on RC compare + | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event + | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16) + | AT91C_TC_ENETRG // Enable external trigger event + | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_AEEVT_SET // Set TIOA1 on external event + | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare + AT91C_BASE_TC1->TC_RC = 0x01; // RC Compare value = 0x01, pulse width to TC0 // use TC0 to count TIOA1 pulses AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1 - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_WAVESEL_UP // just count - | AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare - | AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_WAVESEL_UP // just count + | AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare + | AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2 AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow // use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk) AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2 AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0 - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_WAVESEL_UP; // just count + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_WAVESEL_UP; // just count AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC0 AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1 AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2 + // // synchronize the counter with the ssp_frame signal. - // Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high + // Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present + // + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 1st ssp_clk after start of frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 2nd ssp_clk after start of frame + if ((AT91C_BASE_SSC->SSC_RFMR & SSC_FRAME_MODE_BITS_IN_WORD(32)) == SSC_FRAME_MODE_BITS_IN_WORD(16)) { // 16bit frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 3rd ssp_clk after start of frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 4th ssp_clk after start of frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 5th ssp_clk after start of frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 6th ssp_clk after start of frame + } // note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame // it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge From 9130474818cae82596c10ba81979af9436b69eb3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:33:53 +0200 Subject: [PATCH 010/139] adaptations to new code --- armsrc/em4x50.c | 2 +- armsrc/lfadc.c | 2 +- armsrc/thinfilm.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index ddc297591..93da6425f 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -192,7 +192,7 @@ static void em4x50_setup_read(void) { // 50ms for the resonant antenna to settle. SpinDelay(50); // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); // start a 1.5ticks is 1us StartTicks(); diff --git a/armsrc/lfadc.c b/armsrc/lfadc.c index 8c453bdc9..2c46f5581 100644 --- a/armsrc/lfadc.c +++ b/armsrc/lfadc.c @@ -181,7 +181,7 @@ void lf_init(bool reader, bool simulate) { SetAdcMuxFor(GPIO_MUXSEL_LOPKD); // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); // When in reader mode, give the field a bit of time to settle. // 313T0 = 313 * 8us = 2504us = 2.5ms Hitag2 tags needs to be fully powered. diff --git a/armsrc/thinfilm.c b/armsrc/thinfilm.c index a77a70744..16c91c8bf 100644 --- a/armsrc/thinfilm.c +++ b/armsrc/thinfilm.c @@ -122,7 +122,7 @@ void SimulateThinFilm(uint8_t *data, size_t len) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Set up the synchronous serial port - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // connect Demodulated Signal to ADC: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); From 85053d106f0f58a808ad0ec6bedf985a9afa2384 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:34:48 +0200 Subject: [PATCH 011/139] adapt to fpga changes. And bug hunting COTAG functionality that doesnt work --- armsrc/lfsampling.c | 50 +++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index f77084b3d..aaf7ec86c 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -51,11 +51,11 @@ void printConfig(void) { } void printSamples(void) { - DbpString(_CYAN_("LF Sampling memory")); - Dbprintf(" decimation counter.....%d ", samples.dec_counter); - Dbprintf(" sum.....%u ", samples.sum); - Dbprintf(" counter.....%u ", samples.counter); - Dbprintf(" total saved.....%u ", samples.total_saved); + DbpString(_CYAN_("LF Sampling memory usage")); +// Dbprintf(" decimation counter...%d", samples.dec_counter); +// Dbprintf(" sum..................%u", samples.sum); + Dbprintf(" counter.............." _YELLOW_("%u"), samples.counter); + Dbprintf(" total saved.........." _YELLOW_("%u"), samples.total_saved); print_stack_usage(); } @@ -241,7 +241,7 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) { SpinDelay(50); // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); // start a 1.5ticks is 1us StartTicks(); @@ -480,19 +480,19 @@ void doT55x7Acquisition(size_t sample_size) { #define COTAG_T1 384 #define COTAG_T2 (COTAG_T1>>1) -#define COTAG_ONE_THRESHOLD 128+10 -#define COTAG_ZERO_THRESHOLD 128-10 +#define COTAG_ONE_THRESHOLD 128+5 +#define COTAG_ZERO_THRESHOLD 128-5 #ifndef COTAG_BITS #define COTAG_BITS 264 #endif -void doCotagAcquisition(size_t sample_size) { +void doCotagAcquisition() { uint8_t *dest = BigBuf_get_addr(); - uint16_t bufsize = MIN(sample_size, BigBuf_max_traceLen()); + uint16_t bufsize = BigBuf_max_traceLen(); dest[0] = 0; uint8_t firsthigh = 0, firstlow = 0; - uint16_t i = 0, noise_counter = 0, checker = 0; + uint16_t i = 0, noise_counter = 0; if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("doCotagAcquisition - after init"); @@ -504,21 +504,8 @@ void doCotagAcquisition(size_t sample_size) { if (BUTTON_PRESS()) break; - if (checker == 4000) { - if (data_available()) - break; - else - checker = 0; - } else { - ++checker; - } - WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - LED_D_ON(); - } - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -551,9 +538,13 @@ void doCotagAcquisition(size_t sample_size) { } } + Dbprintf("doCotagAcquisition - %u high %u == 1 low %u == 1", i, firsthigh, firstlow); + // Ensure that DC offset removal and noise check is performed for any device-side processing removeSignalOffset(dest, bufsize); + printSamples(); computeSignalProperties(dest, bufsize); + printSamples(); } uint32_t doCotagAcquisitionManchester(void) { @@ -565,7 +556,7 @@ uint32_t doCotagAcquisitionManchester(void) { uint8_t firsthigh = 0, firstlow = 0; uint8_t curr = 0, prev = 0; uint16_t sample_counter = 0, period = 0; - uint16_t noise_counter = 0, checker = 0; + uint16_t noise_counter = 0; if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("doCotagAcquisitionManchester - after init"); @@ -576,15 +567,6 @@ uint32_t doCotagAcquisitionManchester(void) { if (BUTTON_PRESS()) break; - - if (checker == 4000) { - if ( data_available()) - break; - else - checker = 0; - } else { - ++checker; - } WDT_HIT(); From ee69987210cf53731b944e20766289b8ab98e273 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:35:24 +0200 Subject: [PATCH 012/139] chg: third fpga image for felica --- armsrc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 1bbbf2ba7..44ca3ab6b 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -79,7 +79,7 @@ endif include Standalone/Makefile.inc #the FPGA bitstream files. Note: order matters! -FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit +FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit fpga_felica.bit #the lz4 source files required for decompressing the fpga config at run time SRC_LZ4 = lz4.c From ecdd91392bb79da1e7e8192baf46c593eab236d9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:35:33 +0200 Subject: [PATCH 013/139] adapt to fpga changes. And bug hunting COTAG functionality that doesnt work --- armsrc/lfsampling.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h index 9b8c4c6b1..28721f6ca 100644 --- a/armsrc/lfsampling.h +++ b/armsrc/lfsampling.h @@ -21,7 +21,7 @@ typedef struct { * acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384 * and is Manchester?, we directly gather the manchester data into bigbuff **/ -void doCotagAcquisition(size_t sample_size); +void doCotagAcquisition(void); uint32_t doCotagAcquisitionManchester(void); /** From 4043832c623829e00cdba59518dd2bb611b42a70 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:35:54 +0200 Subject: [PATCH 014/139] adapt to fpga changes. And bug hunting COTAG functionality that doesnt work --- armsrc/lfops.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 7e907da09..4a9373cec 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -678,7 +678,7 @@ void AcquireTiType(void) { AT91C_BASE_SSC->SSC_TCMR = 0; // Transmit Frame Mode Register AT91C_BASE_SSC->SSC_TFMR = 0; - // iceman, FpgaSetupSsc() ?? the code above? can it be replaced? + // iceman, FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER) ?? the code above? can it be replaced? LED_D_ON(); // modulate antenna @@ -721,7 +721,7 @@ void AcquireTiType(void) { } // reset SSC - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); } // arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc @@ -2597,24 +2597,35 @@ void Cotag(uint32_t arg0) { LFSetupFPGAForADC(LF_FREQ2DIV(132), true); //clear buffer now so it does not interfere with timing later + BigBuf_free(); BigBuf_Clear_ext(false); //send COTAG start pulse +/* ON(740) OFF(2035) ON(3330) OFF(2035) ON(740) OFF(2035) ON(1000) +*/ + + ON(800) OFF(2200) + ON(3600) OFF(2200) + ON(800) OFF(2200) + ON(3400) + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_FREQ2DIV(125)); switch (rawsignal) { case 0: - doCotagAcquisition(40000); + doCotagAcquisition(); break; case 1: doCotagAcquisitionManchester(); break; - case 2: + case 2: { DoAcquisition_config(false, 0); break; + } } // Turn the field off From 837efdf5c4e92a8789aaa51f43d2de169ae5dd16 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:36:24 +0200 Subject: [PATCH 015/139] chg: adapt to fpga changes --- armsrc/legicrf.c | 16 +++++----------- armsrc/legicrfsim.c | 5 ++--- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 21b0c0a42..1d2693347 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -152,7 +152,7 @@ static void tx_bit(bool bit) { //----------------------------------------------------------------------------- static void tx_frame(uint32_t frame, uint8_t len) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); // wait for next tx timeslot last_frame_end += RWD_FRAME_WAIT; @@ -180,9 +180,7 @@ static void tx_frame(uint32_t frame, uint8_t len) { } static uint32_t rx_frame(uint8_t len) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); // hold sampling until card is expected to respond last_frame_end += TAG_FRAME_WAIT; @@ -210,9 +208,7 @@ static uint32_t rx_frame(uint8_t len) { static bool rx_ack(void) { // change fpga into rx mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); // hold sampling until card is expected to respond last_frame_end += TAG_FRAME_WAIT; @@ -279,14 +275,12 @@ static int init_card(uint8_t cardtype, legic_card_select_t *p_card) { static void init_reader(bool clear_mem) { // configure FPGA FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); LED_A_ON(); // configure SSC with defaults - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // re-claim GPIO_SSC_DOUT as GPIO and enable output AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c index 35eefc56c..2ca65f54a 100644 --- a/armsrc/legicrfsim.c +++ b/armsrc/legicrfsim.c @@ -303,12 +303,11 @@ static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) { static void init_tag(void) { // configure FPGA FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR - | FPGA_HF_SIMULATOR_MODULATE_212K); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_212K); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // configure SSC with defaults - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); // first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT LOW(GPIO_SSC_DOUT); From fce4c1d13f208ce112d508b5cea44928f7db097f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:36:49 +0200 Subject: [PATCH 016/139] chg: adapt to fpga changes --- armsrc/appmain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 95b42982a..a252bbe8e 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -213,7 +213,7 @@ static void MeasureAntennaTuning(void) { LED_A_ON(); // Let the FPGA drive the high-frequency antenna around 13.56 MHz. FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); SpinDelay(50); #if defined RDV4 @@ -1616,7 +1616,7 @@ static void PacketReceived(PacketCommandNG *packet) { case 1: // MEASURE_ANTENNA_TUNING_HF_START // Let the FPGA drive the high-frequency antenna around 13.56 MHz. FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_SUCCESS, NULL, 0); break; case 2: From 80cda059b17c8ce7c01435a0a011c1b007c960eb Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:37:07 +0200 Subject: [PATCH 017/139] chg: adapt to fpga changes --- armsrc/iso15693.c | 2003 +++++++++++++++++++++++++++++++-------------- armsrc/iso15693.h | 21 +- 2 files changed, 1411 insertions(+), 613 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index d88bae1f0..a82bb9a07 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -3,24 +3,22 @@ // Modified by Greg Jones, Jan 2009 // Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011 // Modified by Christian Herrmann "iceman", 2017 +// Modified by piwi, Oct 2018 // // 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 15693. This includes both the reader software and -// the `fake tag' modes, but at the moment I've implemented only the reader -// stuff, and that barely. -// Modified to perform modulation onboard in arm rather than on PC -// Also added additional reader commands (SELECT, READ etc.) +// the `fake tag' modes. //----------------------------------------------------------------------------- -// The ISO 15693 describes two transmission modes from reader to tag, and 4 -// transmission modes from tag to reader. As of Mar 2010 this code only -// supports one of each: "1of4" mode from reader to tag, and the highspeed -// variant with one subcarrier from card to reader. -// As long, as the card fully support ISO 15693 this is no problem, since the -// reader chooses both data rates, but some non-standard tags do not. Further for -// the simulation to work, we will need to support all data rates. + +// The ISO 15693 describes two transmission modes from reader to tag, and four +// transmission modes from tag to reader. As of Oct 2018 this code supports +// both reader modes and the high speed variant with one subcarrier from card to reader. +// As long as the card fully support ISO 15693 this is no problem, since the +// reader chooses both data rates, but some non-standard tags do not. +// For card simulation, the code supports both high and low speed modes with one subcarrier. // // VCD (reader) -> VICC (tag) // 1 out of 256: @@ -47,15 +45,11 @@ // *) UID is always used "transmission order" (LSB), which is reverse to display order // TODO / BUGS / ISSUES: -// *) writing to tags takes longer: we miss the answer from the tag in most cases -// -> tweak the read-timeout times -// *) signal decoding from the card is still a bit shaky. -// *) signal decoding is unable to detect collissions. -// *) add anti-collission support for inventory-commands +// *) signal decoding is unable to detect collisions. +// *) add anti-collision support for inventory-commands // *) read security status of a block -// *) sniffing and simulation do only support one transmission mode. need to support -// all 8 transmission combinations -// *) remove or refactor code under "depricated" +// *) sniffing and simulation do not support two subcarrier modes. +// *) remove or refactor code under "deprecated" // *) document all the functions #include "iso15693.h" @@ -72,12 +66,36 @@ #include "ticks.h" #include "BigBuf.h" #include "crc16.h" + +// Delays in SSP_CLK ticks. +// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag +#define DELAY_READER_TO_ARM 8 +#define DELAY_ARM_TO_READER 0 + +//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16 +#define DELAY_ARM_TO_TAG 16 +#define DELAY_TAG_TO_ARM 32 + +//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when snooping. All values should be multiples of 16 +#define DELAY_TAG_TO_ARM_SNIFF 32 +#define DELAY_READER_TO_ARM_SNIFF 32 + +// times in samples @ 212kHz when acting as reader +#define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us, should be even enough for iClass tags responding to ACTALL +#define ISO15693_READER_TIMEOUT_WRITE 4700 // 4700/212kHz = 22ms, nominal 20ms + /////////////////////////////////////////////////////////////////////// // ISO 15693 Part 2 - Air Interface -// This section basicly contains transmission and receiving of bits +// This section basically contains transmission and receiving of bits /////////////////////////////////////////////////////////////////////// +// buffers +#define ISO15693_DMA_BUFFER_SIZE 256 // must be a power of 2 +#define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet +#define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet + + // 32 + 2 crc + 1 #define ISO15_MAX_FRAME 35 #define CMD_ID_RESP 5 @@ -93,397 +111,981 @@ #define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) -static void BuildIdentifyRequest(uint8_t *cmdout); -//static void BuildReadBlockRequest(uint8_t *cmdout, uint8_t *uid, uint8_t blockNumber ); -static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid); +static void BuildIdentifyRequest(uint8_t *cmd); +static void BuildInventoryResponse(uint8_t *uid); // --------------------------- // Signal Processing // --------------------------- // prepare data using "1 out of 4" code for later transmission -// resulting data rate is 26,48 kbit/s (fc/512) +// resulting data rate is 26.48 kbit/s (fc/512) // cmd ... data // n ... length of data static void CodeIso15693AsReader(uint8_t *cmd, int n) { - int i, j; - ToSendReset(); + ToSendReset(); - // Give it a bit of slack at the beginning - for (i = 0; i < 24; i++) - ToSendStuffBit(1); + // SOF for 1of4 + ToSend[++ToSendMax] = 0x84; //10000100 - // SOF for 1of4 - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - for (i = 0; i < n; i++) { - for (j = 0; j < 8; j += 2) { - int these = (cmd[i] >> j) & 3; - switch (these) { - case 0: - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 1: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 2: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 3: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - break; - } - } - } - // EOF - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); + // data + for (int i = 0; i < n; i++) { + for (int j = 0; j < 8; j += 2) { + int these = (cmd[i] >> j) & 0x03; + switch(these) { + case 0: + ToSend[++ToSendMax] = 0x40; //01000000 + break; + case 1: + ToSend[++ToSendMax] = 0x10; //00010000 + break; + case 2: + ToSend[++ToSendMax] = 0x04; //00000100 + break; + case 3: + ToSend[++ToSendMax] = 0x01; //00000001 + break; + } + } + } - // And slack at the end, too. - for (i = 0; i < 24; i++) - ToSendStuffBit(1); + // EOF + ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding + + ToSendMax++; } -// encode data using "1 out of 256" sheme +// Encode EOF only +static void CodeIso15693AsReaderEOF(void) { + ToSendReset(); + ToSend[++ToSendMax] = 0x20; + ToSendMax++; +} + + +// encode data using "1 out of 256" scheme // data rate is 1,66 kbit/s (fc/8192) // is designed for more robust communication over longer distances static void CodeIso15693AsReader256(uint8_t *cmd, int n) { - int i, j; - ToSendReset(); + ToSendReset(); - // Give it a bit of slack at the beginning - for (i = 0; i < 24; i++) - ToSendStuffBit(1); + // SOF for 1of256 + ToSend[++ToSendMax] = 0x81; //10000001 - // SOF for 1of256 - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); + // data + for(int i = 0; i < n; i++) { + for (int j = 0; j <= 255; j++) { + if (cmd[i] == j) { + ToSendStuffBit(0); + ToSendStuffBit(1); + } else { + ToSendStuffBit(0); + ToSendStuffBit(0); + } + } + } - for (i = 0; i < n; i++) { - for (j = 0; j <= 255; j++) { - if (cmd[i] == j) { - ToSendStuffBit(1); - ToSendStuffBit(0); - } else { - ToSendStuffBit(1); - ToSendStuffBit(1); - } - } - } - // EOF - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); + // EOF + ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - // And slack at the end, too. - for (i = 0; i < 24; i++) - ToSendStuffBit(1); + ToSendMax++; } -// Transmit the command (to the tag) that was placed in ToSend[]. -static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *wait) { +static const uint8_t encode_4bits[16] = { 0xaa, 0x6a, 0x9a, 0x5a, 0xa6, 0x66, 0x96, 0x56, 0xa9, 0x69, 0x99, 0x59, 0xa5, 0x65, 0x95, 0x55 }; - int c; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); +static void CodeIso15693AsTag(uint8_t *cmd, size_t len) { + /* + * SOF comprises 3 parts; + * * An unmodulated time of 56.64 us + * * 24 pulses of 423.75 kHz (fc/32) + * * A logic 1, which starts with an unmodulated time of 18.88us + * followed by 8 pulses of 423.75kHz (fc/32) + * + * EOF comprises 3 parts: + * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated + * time of 18.88us. + * - 24 pulses of fc/32 + * - An unmodulated time of 56.64 us + * + * A logic 0 starts with 8 pulses of fc/32 + * followed by an unmodulated time of 256/fc (~18,88us). + * + * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by + * 8 pulses of fc/32 (also 18.88us) + * + * A bit here becomes 8 pulses of fc/32. Therefore: + * The SOF can be written as 00011101 = 0x1D + * The EOF can be written as 10111000 = 0xb8 + * A logic 1 is 01 + * A logic 0 is 10 + * + * */ - if (wait) { - for (c = 0; c < *wait;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! - ++c; - } - WDT_HIT(); - } - } + ToSendReset(); - c = 0; - for (;;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = cmd[c]; - if (++c >= len) break; - } - WDT_HIT(); - } + // SOF + ToSend[++ToSendMax] = 0x1D; // 00011101 - if (samples) { - if (wait) - *samples = (c + *wait) << 3; - else - *samples = c << 3; - } + // data + for (int i = 0; i < len; i++) { + ToSend[++ToSendMax] = encode_4bits[cmd[i] & 0xF]; + ToSend[++ToSendMax] = encode_4bits[cmd[i] >> 4]; + } + + // EOF + ToSend[++ToSendMax] = 0xB8; // 10111000 + + ToSendMax++; +} + +// Transmit the command (to the tag) that was placed in cmd[]. +static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); + + if (*start_time < DELAY_ARM_TO_TAG) { + *start_time = DELAY_ARM_TO_TAG; + } + + *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; + + if (GetCountSspClk() > *start_time) { // we may miss the intended time + *start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time + } + + while (GetCountSspClk() < *start_time) + /* wait */ ; + + LED_B_ON(); + for (int c = 0; c < len; c++) { + uint8_t data = cmd[c]; + for (int i = 0; i < 8; i++) { + uint16_t send_word = (data & 0x80) ? 0xffff : 0x0000; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; + data <<= 1; + } + WDT_HIT(); + } + LED_B_OFF(); + + *start_time = *start_time + DELAY_ARM_TO_TAG; } //----------------------------------------------------------------------------- -// Transmit the command (to the reader) that was placed in ToSend[]. +// Transmit the command (to the reader) that was placed in cmd[]. //----------------------------------------------------------------------------- -static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *wait) { - int c = 0; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); +static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow) { - if (wait) { - for (c = 0; c < *wait;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! - ++c; - } - WDT_HIT(); - } - } + // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); - c = 0; - for (;;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = cmd[c]; - if (++c >= len) break; - } - WDT_HIT(); - } - if (samples) { - if (wait) - *samples = (c + *wait) << 3; - else - *samples = c << 3; - } + uint32_t modulation_start_time = *start_time - DELAY_ARM_TO_READER + 3 * 8; // no need to transfer the unmodulated start of SOF + + while (GetCountSspClk() > (modulation_start_time & 0xfffffff8) + 3) { // we will miss the intended time + if (slot_time) { + modulation_start_time += slot_time; // use next available slot + } else { + modulation_start_time = (modulation_start_time & 0xfffffff8) + 8; // next possible time + } + } + + while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) + /* wait */ ; + + uint8_t shift_delay = modulation_start_time & 0x00000007; + + *start_time = modulation_start_time + DELAY_ARM_TO_READER - 3 * 8; + + LED_C_ON(); + uint8_t bits_to_shift = 0x00; + uint8_t bits_to_send = 0x00; + for (size_t c = 0; c < len; c++) { + for (int i = (c==0?4:7); i >= 0; i--) { + uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; + for (int j = 0; j < (slow?4:1); ) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; + AT91C_BASE_SSC->SSC_THR = bits_to_send; + bits_to_shift = cmd_bits; + j++; + } + } + } + WDT_HIT(); + } + // send the remaining bits, padded with 0: + bits_to_send = bits_to_shift << (8 - shift_delay); + for ( ; ; ) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = bits_to_send; + break; + } + } + LED_C_OFF(); } +//============================================================================= +// An ISO 15693 decoder for tag responses (one subcarrier only). +// Uses cross correlation to identify each bit and EOF. +// This function is called 8 times per bit (every 2 subcarrier cycles). +// Subcarrier frequency fs is 424kHz, 1/fs = 2,36us, +// 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 +//============================================================================= + +#define NOISE_THRESHOLD 80 // don't try to correlate noise +#define MAX_PREVIOUS_AMPLITUDE (-1 - NOISE_THRESHOLD) + +typedef struct DecodeTag { + enum { + STATE_TAG_SOF_LOW, + STATE_TAG_SOF_RISING_EDGE, + STATE_TAG_SOF_HIGH, + STATE_TAG_SOF_HIGH_END, + STATE_TAG_RECEIVING_DATA, + STATE_TAG_EOF, + STATE_TAG_EOF_TAIL + } state; + int bitCount; + int posCount; + enum { + LOGIC0, + LOGIC1, + SOF_PART1, + SOF_PART2 + } lastBit; + uint16_t shiftReg; + uint16_t max_len; + uint8_t *output; + int len; + int sum1, sum2; + int threshold_sof; + int threshold_half; + uint16_t previous_amplitude; +} DecodeTag_t; + //----------------------------------------------------------------------------- // DEMODULATE tag answer //----------------------------------------------------------------------------- -static int DemodAnswer(uint8_t *received, uint8_t *dest, uint16_t samplecount) { +static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { + switch (DecodeTag->state) { + case STATE_TAG_SOF_LOW: + // waiting for a rising edge + if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) { + if (DecodeTag->posCount > 10) { + DecodeTag->threshold_sof = amplitude - DecodeTag->previous_amplitude; // to be divided by 2 + DecodeTag->threshold_half = 0; + DecodeTag->state = STATE_TAG_SOF_RISING_EDGE; + } else { + DecodeTag->posCount = 0; + } + } else { + DecodeTag->posCount++; + DecodeTag->previous_amplitude = amplitude; + } + break; - int i, j; - int max = 0, maxPos = 0, skip = 4; - int k = 0; // this will be our return value + case STATE_TAG_SOF_RISING_EDGE: + if (amplitude > DecodeTag->threshold_sof + DecodeTag->previous_amplitude) { // edge still rising + if (amplitude > DecodeTag->threshold_sof + DecodeTag->threshold_sof) { // steeper edge, take this as time reference + DecodeTag->posCount = 1; + } else { + DecodeTag->posCount = 2; + } + DecodeTag->threshold_sof = (amplitude - DecodeTag->previous_amplitude) / 2; + } else { + DecodeTag->posCount = 2; + DecodeTag->threshold_sof = DecodeTag->threshold_sof/2; + } + // DecodeTag->posCount = 2; + DecodeTag->state = STATE_TAG_SOF_HIGH; + break; - // First, correlate for SOF - for (i = 0; i < samplecount; i++) { - int corr = 0; - for (j = 0; j < ARRAYLEN(FrameSOF); j += skip) { - corr += FrameSOF[j] * dest[i + (j / skip)]; - } - if (corr > max) { - max = corr; - maxPos = i; - } - } - // DbpString("SOF at %d, correlation %d", maxPos,max/(ARRAYLEN(FrameSOF)/skip)); + case STATE_TAG_SOF_HIGH: + // waiting for 10 times high. Take average over the last 8 + if (amplitude > DecodeTag->threshold_sof) { + DecodeTag->posCount++; + if (DecodeTag->posCount > 2) { + DecodeTag->threshold_half += amplitude; // keep track of average high value + } + if (DecodeTag->posCount == 10) { + DecodeTag->threshold_half >>= 2; // (4 times 1/2 average) + DecodeTag->state = STATE_TAG_SOF_HIGH_END; + } + } else { // high phase was too short + DecodeTag->posCount = 1; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + } + break; - // greg - If correlation is less than 1 then there's little point in continuing - if ((max / (ARRAYLEN(FrameSOF) / skip)) < 1) - return k; + case STATE_TAG_SOF_HIGH_END: + // check for falling edge + if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) { + DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) + DecodeTag->shiftReg = 0; + DecodeTag->bitCount = 0; + DecodeTag->len = 0; + DecodeTag->sum1 = amplitude; + DecodeTag->sum2 = 0; + DecodeTag->posCount = 2; + DecodeTag->state = STATE_TAG_RECEIVING_DATA; + // FpgaDisableTracing(); // DEBUGGING + // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", + // amplitude, + // DecodeTag->threshold_sof, + // DecodeTag->threshold_half/4, + // DecodeTag->previous_amplitude); // DEBUGGING + LED_C_ON(); + } else { + DecodeTag->posCount++; + if (DecodeTag->posCount > 13) { // high phase too long + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + break; - i = maxPos + ARRAYLEN(FrameSOF) / skip; + case STATE_TAG_RECEIVING_DATA: + // FpgaDisableTracing(); // DEBUGGING + // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", + // amplitude, + // DecodeTag->threshold_sof, + // DecodeTag->threshold_half/4, + // DecodeTag->previous_amplitude); // DEBUGGING + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; + } + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += amplitude; + } else { + DecodeTag->sum2 += amplitude; + } + if (DecodeTag->posCount == 8) { + if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in both halves + if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF + DecodeTag->state = STATE_TAG_EOF; + } else { + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } else if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in second half + // logic 1 + if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF + DecodeTag->lastBit = SOF_PART2; // SOF completed + } else { + DecodeTag->lastBit = LOGIC1; + DecodeTag->shiftReg >>= 1; + DecodeTag->shiftReg |= 0x80; + DecodeTag->bitCount++; + if (DecodeTag->bitCount == 8) { + DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; + DecodeTag->len++; + // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING + if (DecodeTag->len > DecodeTag->max_len) { + // buffer overflow, give up + LED_C_OFF(); + return true; + } + DecodeTag->bitCount = 0; + DecodeTag->shiftReg = 0; + } + } + } else if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half + // logic 0 + if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } else { + DecodeTag->lastBit = LOGIC0; + DecodeTag->shiftReg >>= 1; + DecodeTag->bitCount++; + if (DecodeTag->bitCount == 8) { + DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; + DecodeTag->len++; + // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING + if (DecodeTag->len > DecodeTag->max_len) { + // buffer overflow, give up + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + DecodeTag->bitCount = 0; + DecodeTag->shiftReg = 0; + } + } + } else { // no modulation + if (DecodeTag->lastBit == SOF_PART2) { // only SOF (this is OK for iClass) + LED_C_OFF(); + return true; + } else { + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + DecodeTag->posCount = 0; + } + DecodeTag->posCount++; + break; - uint8_t outBuf[ISO15_MAX_FRAME]; - memset(outBuf, 0, sizeof(outBuf)); - uint8_t mask = 0x01; - for (;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; - for (j = 0; j < ARRAYLEN(Logic0); j += skip) { - corr0 += Logic0[j] * dest[i + (j / skip)]; - } - for (j = 0; j < ARRAYLEN(Logic1); j += skip) { - corr1 += Logic1[j] * dest[i + (j / skip)]; - } - for (j = 0; j < ARRAYLEN(FrameEOF); j += skip) { - corrEOF += FrameEOF[j] * dest[i + (j / skip)]; - } - // Even things out by the length of the target waveform. - corr0 *= 4; - corr1 *= 4; - // if (DBGLEVEL >= DBG_EXTENDED) - // Dbprintf("Corr1 %d, Corr0 %d, CorrEOF %d", corr1, corr0, corrEOF); + case STATE_TAG_EOF: + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; + } + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += amplitude; + } else { + DecodeTag->sum2 += amplitude; + } + if (DecodeTag->posCount == 8) { + if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_EOF_TAIL; + } else { + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + DecodeTag->posCount++; + break; - if (corrEOF > corr1 && corrEOF > corr0) - break; + case STATE_TAG_EOF_TAIL: + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; + } + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += amplitude; + } else { + DecodeTag->sum2 += amplitude; + } + if (DecodeTag->posCount == 8) { + if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // no modulation in both halves + LED_C_OFF(); + return true; + } else { + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + DecodeTag->posCount++; + break; + } - if (corr1 > corr0) { - i += ARRAYLEN(Logic1) / skip; - outBuf[k] |= mask; - } else { - i += ARRAYLEN(Logic0) / skip; - } - - mask <<= 1; - - if (mask == 0) { - k++; - mask = 0x01; - } - - if ((i + (int)ARRAYLEN(FrameEOF)) >= samplecount - 1) { - //Dbprintf("[!] ran off end! %d | %d",( i + (int)ARRAYLEN(FrameEOF)), samplecount-1); - break; - } - } - - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("ice: demod bytes %u", k); - - if (mask != 0x01) { // this happens, when we miss the EOF - - // TODO: for some reason this happens quite often - if (DBGLEVEL >= DBG_ERROR && k != 0) Dbprintf("[!] error, uneven octet! (extra bits!) mask %02x", mask); - //if (mask < 0x08) k--; // discard the last uneven octet; - // 0x08 is an assumption - but works quite often - } - - for (i = 0; i < k; i++) - received[i] = outBuf[i]; - - // return the number of bytes demodulated - return k; + return false; } -// Read from Tag -// Parameters: -// received -// samples -// elapsed -// returns: -// number of decoded bytes -// logging enabled -#define SIGNAL_BUFF_SIZE 20000 +static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) { + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + DecodeTag->output = data; + DecodeTag->max_len = max_len; +} -static int GetIso15693AnswerFromTag(uint8_t *received, int *elapsed) { - - // get current clock - uint32_t time_0 = GetCountSspClk(); - uint32_t time_stop = 0; - bool getNext = false; - int counter = 0, ci, cq = 0; - uint8_t *buf = BigBuf_malloc(SIGNAL_BUFF_SIZE); - - if (elapsed) *elapsed = 0; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - - for (;;) { - WDT_HIT(); - - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; //0x43; - // To make use of exact timing of next command from reader!! - if (elapsed)(*elapsed)++; - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - - ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; - ci = ABS(ci); - - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates, so every other sample is I, - // every other is Q. We just want power, so abs(I) + abs(Q) is - // close to what we want. - // iceman 2016, amplitude sqrt(abs(i) + abs(q)) - if (getNext) { - - buf[counter++] = (uint8_t)(MAX(ci, cq) + (MIN(ci, cq) >> 1)); - - if (counter >= SIGNAL_BUFF_SIZE) - break; - } else { - cq = ci; - } - getNext = !getNext; - } - } - time_stop = GetCountSspClk(); - int len = DemodAnswer(received, buf, counter); - LogTrace(received, len, time_0 << 4, time_stop << 4, NULL, false); - BigBuf_free(); - return len; +static void DecodeTagReset(DecodeTag_t *DecodeTag) { + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; } -// Now the GetISO15693 message from sniffing command -// logging enable, -static int GetIso15693AnswerFromSniff(uint8_t *received, int *samples, int *elapsed) { +/* + * Receive and decode the tag response, also log to tracebuffer + */ +static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { - bool getNext = false; - int counter = 0, ci, cq = 0; - uint32_t time_0 = 0, time_stop = 0; - uint8_t *buf = BigBuf_malloc(SIGNAL_BUFF_SIZE); + int samples = 0; + int ret = 0; - // get current clock - time_0 = GetCountSspClk(); + uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + // the Decoder data structure + DecodeTag_t DecodeTag = { 0 }; + DecodeTagInit(&DecodeTag, response, max_len); - for (;;) { - WDT_HIT(); + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + // And put the FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); - ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; - ci = ABS(ci); + // Setup and start DMA. + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + uint32_t dma_start_time = 0; + uint16_t *upTo = dmaBuf; - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates, so every other sample is I, - // every other is Q. We just want power, so abs(I) + abs(Q) is - // close to what we want. - if (getNext) { + for(;;) { + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - buf[counter++] = (uint8_t)(MAX(ci, cq) + (MIN(ci, cq) >> 1)); + if (behindBy == 0) continue; - if (counter >= 20000) - break; - } else { - cq = ci; - } - getNext = !getNext; - } - } + samples++; + if (samples == 1) { + // DMA has transferred the very first data + dma_start_time = GetCountSspClk() & 0xfffffff0; + } - time_stop = GetCountSspClk(); - int k = DemodAnswer(received, buf, counter); - LogTrace(received, k, time_0 << 4, time_stop << 4, NULL, false); - BigBuf_free(); - return k; + uint16_t tagdata = *upTo++; + + if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + ret = -1; + break; + } + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + } + + if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) { + *eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM; // end of EOF + if (DecodeTag.lastBit == SOF_PART2) { + *eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) + } + if (DecodeTag.len > DecodeTag.max_len) { + ret = -2; // buffer overflow + } + break; + } + + if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { + ret = -1; // timeout + break; + } + + } + + FpgaDisableSscDma(); + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d", + samples, ret, DecodeTag.state, DecodeTag.lastBit, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); + + if (ret < 0) { + return ret; + } + + uint32_t sof_time = *eof_time + - DecodeTag.len * 8 * 8 * 16 // time for byte transfers + - 32 * 16 // time for SOF transfer + - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("timing: sof_time = %d, eof_time = %d", sof_time, *eof_time); + + LogTrace(DecodeTag.output, DecodeTag.len, sof_time*4, *eof_time*4, NULL, false); + + return DecodeTag.len; +} + + +//============================================================================= +// An ISO15693 decoder for reader commands. +// +// 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 B -> ON once we have received the SOF and are expecting the rest. +// LED B -> 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 +//============================================================================= + +typedef struct DecodeReader { + enum { + STATE_READER_UNSYNCD, + STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF, + STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF, + STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF, + STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF, + STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4, + STATE_READER_RECEIVE_DATA_1_OUT_OF_4, + STATE_READER_RECEIVE_DATA_1_OUT_OF_256, + STATE_READER_RECEIVE_JAMMING + } state; + enum { + CODING_1_OUT_OF_4, + CODING_1_OUT_OF_256 + } Coding; + uint8_t shiftReg; + uint8_t bitCount; + int byteCount; + int byteCountMax; + int posCount; + int sum1, sum2; + uint8_t *output; + uint8_t jam_search_len; + uint8_t *jam_search_string; +} DecodeReader_t; + +static void DecodeReaderInit(DecodeReader_t* DecodeReader, uint8_t *data, uint16_t max_len, uint8_t jam_search_len, uint8_t *jam_search_string) { + DecodeReader->output = data; + DecodeReader->byteCountMax = max_len; + DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReader->byteCount = 0; + DecodeReader->bitCount = 0; + DecodeReader->posCount = 1; + DecodeReader->shiftReg = 0; + DecodeReader->jam_search_len = jam_search_len; + DecodeReader->jam_search_string = jam_search_string; +} + +static void DecodeReaderReset(DecodeReader_t* DecodeReader) { + DecodeReader->state = STATE_READER_UNSYNCD; +} + +static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeReader) { + switch (DecodeReader->state) { + case STATE_READER_UNSYNCD: + // wait for unmodulated carrier + if (bit) { + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } + break; + + case STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF: + if (!bit) { + // we went low, so this could be the beginning of a SOF + DecodeReader->posCount = 1; + DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; + } + break; + + case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF: + DecodeReader->posCount++; + if (bit) { // detected rising edge + if (DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { // SOF + DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; + } + } else { + if (DecodeReader->posCount > 5) { // stayed low for too long + DecodeReaderReset(DecodeReader); + } else { + // do nothing, keep waiting + } + } + break; + + case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF: + DecodeReader->posCount++; + if (!bit) { // detected a falling edge + if (DecodeReader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) + DecodeReaderReset(DecodeReader); + } else if (DecodeReader->posCount < 23) { // SOF for 1 out of 4 coding + DecodeReader->Coding = CODING_1_OUT_OF_4; + DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) + DecodeReaderReset(DecodeReader); + } else { // SOF for 1 out of 256 coding + DecodeReader->Coding = CODING_1_OUT_OF_256; + DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + } + } else { + if (DecodeReader->posCount > 29) { // stayed high for too long + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { + // do nothing, keep waiting + } + } + break; + + case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF: + DecodeReader->posCount++; + if (bit) { // detected rising edge + if (DecodeReader->Coding == CODING_1_OUT_OF_256) { + if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { + DecodeReader->posCount = 1; + DecodeReader->bitCount = 0; + DecodeReader->byteCount = 0; + DecodeReader->sum1 = 1; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; + LED_B_ON(); + } + } else { // CODING_1_OUT_OF_4 + if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { + DecodeReader->posCount = 1; + DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; + } + } + } else { + if (DecodeReader->Coding == CODING_1_OUT_OF_256) { + if (DecodeReader->posCount > 34) { // signal stayed low for too long + DecodeReaderReset(DecodeReader); + } else { + // do nothing, keep waiting + } + } else { // CODING_1_OUT_OF_4 + if (DecodeReader->posCount > 26) { // signal stayed low for too long + DecodeReaderReset(DecodeReader); + } else { + // do nothing, keep waiting + } + } + } + break; + + case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: + DecodeReader->posCount++; + if (bit) { + if (DecodeReader->posCount == 9) { + DecodeReader->posCount = 1; + DecodeReader->bitCount = 0; + DecodeReader->byteCount = 0; + DecodeReader->sum1 = 1; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; + LED_B_ON(); + } else { + // do nothing, keep waiting + } + } else { // unexpected falling edge + DecodeReaderReset(DecodeReader); + } + break; + + case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: + DecodeReader->posCount++; + if (DecodeReader->posCount == 1) { + DecodeReader->sum1 = bit?1:0; + } else if (DecodeReader->posCount <= 4) { + if (bit) DecodeReader->sum1++; + } else if (DecodeReader->posCount == 5) { + DecodeReader->sum2 = bit?1:0; + } else { + if (bit) DecodeReader->sum2++; + } + if (DecodeReader->posCount == 8) { + DecodeReader->posCount = 0; + if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF + LED_B_OFF(); // Finished receiving + DecodeReaderReset(DecodeReader); + if (DecodeReader->byteCount != 0) { + return true; + } + } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected a 2bit position + DecodeReader->shiftReg >>= 2; + DecodeReader->shiftReg |= (DecodeReader->bitCount << 6); + } + if (DecodeReader->bitCount == 15) { // we have a full byte + DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; + if (DecodeReader->byteCount > DecodeReader->byteCountMax) { + // buffer overflow, give up + LED_B_OFF(); + DecodeReaderReset(DecodeReader); + } + DecodeReader->bitCount = 0; + DecodeReader->shiftReg = 0; + if (DecodeReader->byteCount == DecodeReader->jam_search_len) { + if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); + DecodeReader->state = STATE_READER_RECEIVE_JAMMING; + } + } + } else { + DecodeReader->bitCount++; + } + } + break; + + case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: + DecodeReader->posCount++; + if (DecodeReader->posCount == 1) { + DecodeReader->sum1 = bit?1:0; + } else if (DecodeReader->posCount <= 4) { + if (bit) DecodeReader->sum1++; + } else if (DecodeReader->posCount == 5) { + DecodeReader->sum2 = bit?1:0; + } else if (bit) { + DecodeReader->sum2++; + } + if (DecodeReader->posCount == 8) { + DecodeReader->posCount = 0; + if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF + LED_B_OFF(); // Finished receiving + DecodeReaderReset(DecodeReader); + if (DecodeReader->byteCount != 0) { + return true; + } + } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected the bit position + DecodeReader->shiftReg = DecodeReader->bitCount; + } + if (DecodeReader->bitCount == 255) { // we have a full byte + DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; + if (DecodeReader->byteCount > DecodeReader->byteCountMax) { + // buffer overflow, give up + LED_B_OFF(); + DecodeReaderReset(DecodeReader); + } + if (DecodeReader->byteCount == DecodeReader->jam_search_len) { + if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); + DecodeReader->state = STATE_READER_RECEIVE_JAMMING; + } + } + } + DecodeReader->bitCount++; + } + break; + + case STATE_READER_RECEIVE_JAMMING: + DecodeReader->posCount++; + if (DecodeReader->Coding == CODING_1_OUT_OF_4) { + if (DecodeReader->posCount == 7*16) { // 7 bits jammed + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); // stop jamming + // FpgaDisableTracing(); + LED_D_OFF(); + } else if (DecodeReader->posCount == 8*16) { + DecodeReader->posCount = 0; + DecodeReader->output[DecodeReader->byteCount++] = 0x00; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; + } + } else { + if (DecodeReader->posCount == 7*256) { // 7 bits jammend + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); // stop jamming + LED_D_OFF(); + } else if (DecodeReader->posCount == 8*256) { + DecodeReader->posCount = 0; + DecodeReader->output[DecodeReader->byteCount++] = 0x00; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; + } + } + break; + + default: + LED_B_OFF(); + DecodeReaderReset(DecodeReader); + break; + } + + 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 len) or someone presses the pushbutton on the board (returns -1). +// +// Assume that we're called with the SSC (to the FPGA) and ADC path set +// correctly. +//----------------------------------------------------------------------------- + +static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) { + int samples = 0; + bool gotFrame = false; + uint8_t b; + + uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + + // the decoder data structure + DecodeReader_t DecodeReader = {0}; + DecodeReaderInit(&DecodeReader, received, max_len, 0, NULL); + + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); + + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + + // clear receive register and wait for next transfer + uint32_t temp = AT91C_BASE_SSC->SSC_RHR; + (void) temp; + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; + + uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8; + + // Setup and start DMA. + FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE); + uint8_t *upTo = dmaBuf; + + for (;;) { + uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + + if (behindBy == 0) continue; + + b = *upTo++; + if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + break; + } + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + } + + for (int i = 7; i >= 0; i--) { + if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { + *eof_time = dma_start_time + samples - DELAY_READER_TO_ARM; // end of EOF + gotFrame = true; + break; + } + samples++; + } + + if (gotFrame) { + break; + } + + if (BUTTON_PRESS()) { + DecodeReader.byteCount = -1; + break; + } + + WDT_HIT(); + } + + FpgaDisableSscDma(); + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", + samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); + + if (DecodeReader.byteCount > 0) { + uint32_t sof_time = *eof_time + - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers + - 32 // time for SOF transfer + - 16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*32, *eof_time*32, NULL, true); + } + + return DecodeReader.byteCount; } //----------------------------------------------------------------------------- @@ -492,133 +1094,231 @@ static int GetIso15693AnswerFromSniff(uint8_t *received, int *samples, int *elap // so that it can be downloaded to a PC and processed there. //----------------------------------------------------------------------------- void AcquireRawAdcSamplesIso15693(void) { - int c = 0, getNext = false; - int ci, cq = 0; + LED_A_ON(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); + //iceman: needs malloc + uint8_t *dest = BigBuf_get_addr(); - // Now send the command - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - SpinDelay(200); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + LED_D_ON(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - uint8_t *buf = BigBuf_get_addr(); + uint8_t cmd[5]; + BuildIdentifyRequest(cmd); + CodeIso15693AsReader(cmd, sizeof(cmd)); - uint32_t time_start = GetCountSspClk(); - uint8_t cmd[CMD_ID_RESP] = {0}; - BuildIdentifyRequest(cmd); + // Give the tags time to energize + SpinDelay(100); - // sending command - c = 0; - for (;;) { - WDT_HIT(); + // Now send the command + uint32_t start_time = 0; + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ToSend[c]; - c++; - if (c == ToSendMax + 3) { - break; - } - } - } + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ; - LogTrace(cmd, CMD_ID_RESP, time_start << 4, GetCountSspClk() << 4, NULL, true); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + for(int c = 0; c < 4000; ) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + uint16_t r = AT91C_BASE_SSC->SSC_RHR; + dest[c++] = r >> 5; + } + } - c = 0; - for (;;) { - WDT_HIT(); - - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - - ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; - ci = ABS(ci); - - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates, so every other sample is I, - // every other is Q. We just want power, so abs(I) + abs(Q) is - // close to what we want. - // iceman 2016, amplitude sqrt(abs(i) + abs(q)) - if (getNext) { - - buf[c++] = (uint8_t)(MAX(ci, cq) + (MIN(ci, cq) >> 1)); - - if (c >= 7000) break; - - } else { - cq = ci; - } - getNext = !getNext; - } - } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } -// switch_off, initreader, no logging -void RecordRawAdcSamplesIso15693(void) { +void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { - int c = 0, getNext = false; - int ci, cq = 0; + LED_A_ON(); - Iso15693InitReader(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - uint8_t *buf = BigBuf_get_addr(); + clear_trace(); + set_tracing(true); - for (;;) { - WDT_HIT(); + // The DMA buffer, used to stream samples from the FPGA + uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + // Count of samples received so far, so that we can include timing + // information in the trace buffer. + int samples = 0; - ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; - ci = ABS(ci); - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates, so every other sample is I, - // every other is Q. We just want power, so abs(I) + abs(Q) is - // close to what we want. - if (getNext) { + DecodeTag_t DecodeTag = {0}; + uint8_t response[ISO15693_MAX_RESPONSE_LENGTH]; + DecodeTagInit(&DecodeTag, response, sizeof(response)); - buf[c++] = (uint8_t)(MAX(ci, cq) + (MIN(ci, cq) >> 1)); + DecodeReader_t DecodeReader = {0}; + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd), jam_search_len, jam_search_string); - if (c >= 7000) - break; - } else { - cq = ci; - } + // Print some debug information about the buffer sizes + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("Sniffing buffers initialized:"); + Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); + Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); + Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); + Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); + } - getNext = !getNext; - } - } + Dbprintf("Sniff started. Press PM3 Button to stop."); - Dbprintf("done"); - switch_off(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); + LED_D_OFF(); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + StartCountSspClk(); + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + + bool TagIsActive = false; + bool ReaderIsActive = false; + bool ExpectTagAnswer = false; + uint32_t dma_start_time = 0; + uint16_t *upTo = dmaBuf; + + uint16_t max_behindBy = 0; + + // And now we loop, receiving samples. + for(;;) { + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + if (behindBy > max_behindBy) { + max_behindBy = behindBy; + } + + if (behindBy == 0) continue; + + samples++; + if (samples == 1) { + // DMA has transferred the very first data + dma_start_time = GetCountSspClk() & 0xfffffff0; + } + + uint16_t snoopdata = *upTo++; + + if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + + Dbprintf("About to blow circular buffer - aborted! behindBy=%d, samples=%d", behindBy, samples); + break; + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + WDT_HIT(); + if (BUTTON_PRESS()) { + DbpString("Sniff stopped."); + break; + } + } + } + + if (!TagIsActive) { // no need to try decoding reader data if the tag is sending + if (Handle15693SampleFromReader(snoopdata & 0x02, &DecodeReader)) { + + uint32_t eof_time = dma_start_time + samples*16 + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF + if (DecodeReader.byteCount > 0) { + uint32_t sof_time = eof_time + - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers + - 32*16 // time for SOF transfer + - 16*16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); + } + // And ready to receive another command. + DecodeReaderReset(&DecodeReader); + // And also reset the demod code, which might have been + // false-triggered by the commands from the reader. + DecodeTagReset(&DecodeTag); + ReaderIsActive = false; + ExpectTagAnswer = true; + + } else if (Handle15693SampleFromReader(snoopdata & 0x01, &DecodeReader)) { + + uint32_t eof_time = dma_start_time + samples*16 + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF + if (DecodeReader.byteCount > 0) { + uint32_t sof_time = eof_time + - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers + - 32*16 // time for SOF transfer + - 16*16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); + } + // And ready to receive another command + DecodeReaderReset(&DecodeReader); + + // And also reset the demod code, which might have been + // false-triggered by the commands from the reader. + DecodeTagReset(&DecodeTag); + ReaderIsActive = false; + ExpectTagAnswer = true; + + } else { + ReaderIsActive = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); + } + } + + if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + if (Handle15693SamplesFromTag(snoopdata >> 2, &DecodeTag)) { + + uint32_t eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM_SNIFF; // end of EOF + if (DecodeTag.lastBit == SOF_PART2) { + eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) + } + uint32_t sof_time = eof_time + - DecodeTag.len * 8 * 8 * 16 // time for byte transfers + - 32 * 16 // time for SOF transfer + - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer + LogTrace(DecodeTag.output, DecodeTag.len, sof_time*4, eof_time*4, NULL, false); + // And ready to receive another response. + DecodeTagReset(&DecodeTag); + DecodeReaderReset(&DecodeReader); + ExpectTagAnswer = false; + TagIsActive = false; + } else { + TagIsActive = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); + } + } + + } + + FpgaDisableSscDma(); + + DbpString("Sniff statistics:"); + Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", ExpectTagAnswer, TagIsActive, ReaderIsActive); + Dbprintf(" DecodeTag State: %d", DecodeTag.state); + Dbprintf(" DecodeTag byteCnt: %d", DecodeTag.len); + Dbprintf(" DecodeTag posCount: %d", DecodeTag.posCount); + Dbprintf(" DecodeReader State: %d", DecodeReader.state); + Dbprintf(" DecodeReader byteCnt: %d", DecodeReader.byteCount); + Dbprintf(" DecodeReader posCount: %d", DecodeReader.posCount); + Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); + Dbprintf(" Max behindBy: %d", max_behindBy); } // Initialize the proxmark as iso15k reader // (this might produces glitches that confuse some tags void Iso15693InitReader(void) { - LEDsoff(); - clear_trace(); - set_tracing(true); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Start from off (no field generated) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); SpinDelay(10); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // switch field on + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + LED_D_ON(); + + // initialize SSC and select proper AD input + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - // Give the tags time to energize - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(200); - - // Start the timer - StartCountSspClk(); - - LED_A_ON(); + // give tags some time to energize + SpinDelay(250); } /////////////////////////////////////////////////////////////////////// @@ -626,75 +1326,44 @@ void Iso15693InitReader(void) { // This section basicly contains transmission and receiving of bits /////////////////////////////////////////////////////////////////////// -// Encode (into the ToSend buffers) an identify request, which is the first +// Encode an identify request, which is the first // thing that you must send to a tag to get a response. // It expects "cmdout" to be at least CMD_ID_RESP large -static void BuildIdentifyRequest(uint8_t *cmdout) { - uint8_t cmd[CMD_ID_RESP] = {0, ISO15_CMD_INVENTORY, 0, 0, 0}; +// When READER: +static void BuildIdentifyRequest(uint8_t *cmd) { // flags cmd[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; - // no mask - cmd[2] = 0x00; + // inventory command code + cmd[1] = ISO15_CMD_INVENTORY; + // no mask + cmd[2] = 0x00; // CRC AddCrc15(cmd, 3); - // coding as high speed (1 out of 4) - CodeIso15693AsReader(cmd, CMD_ID_RESP); - memcpy(cmdout, cmd, CMD_ID_RESP); } // uid is in transmission order (which is reverse of display order) -/* -static void BuildReadBlockRequest(uint8_t **out, uint8_t *uid, uint8_t blockNumber ) { - uint8_t cmd[CMD_READ_RESP] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit, ADDR bit, OPTION bit - // READ BLOCK command code - cmd[1] = 0x20; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = uid[0]; - cmd[3] = uid[1]; - cmd[4] = uid[2]; - cmd[5] = uid[3]; - cmd[6] = uid[4]; - cmd[7] = uid[5]; - cmd[8] = uid[6]; - cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique) - // Block number to read - cmd[10] = blockNumber;//0x00; - // CRC - AddCrc15(cmd, 11); - CodeIso15693AsReader(cmd, CMD_READ_RESP); - memcpy(out, cmd, CMD_ID_RESP); -} -*/ -// Now the VICC>VCD responses when we are simulating a tag -// It expects "out" to be at least CMD_INV_RESP large -static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid) { +// When SIM: now the VICC>VCD responses when we are simulating a tag +static void BuildInventoryResponse(uint8_t *uid) { - uint8_t cmd[CMD_INV_RESP] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t cmd[CMD_INV_RESP] = {0}; - // one sub-carrier, inventory, 1 slot, fast rate - // AFI is at bit 5 (1<<4) when doing an INVENTORY - //(1 << 2) | (1 << 5) | (1 << 1); - cmd[0] = 0; // + cmd[0] = 0; // No error, no protocol format extension cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported + // 64-bit UID - cmd[2] = uid[7]; //0x32; - cmd[3] = uid[6]; //0x4b; - cmd[4] = uid[5]; //0x03; - cmd[5] = uid[4]; //0x01; - cmd[6] = uid[3]; //0x00; - cmd[7] = uid[2]; //0x10; - cmd[8] = uid[1]; //0x05; - cmd[9] = uid[0]; //0xe0; + cmd[2] = uid[7]; + cmd[3] = uid[6]; + cmd[4] = uid[5]; + cmd[5] = uid[4]; + cmd[6] = uid[3]; + cmd[7] = uid[2]; + cmd[8] = uid[1]; + cmd[9] = uid[0]; + // CRC AddCrc15(cmd, 10); - CodeIso15693AsReader(cmd, CMD_INV_RESP); - memcpy(cmdout, cmd, CMD_INV_RESP); + CodeIso15693AsTag(cmd, CMD_INV_RESP); } // Universal Method for sending to and recv bytes from a tag @@ -704,36 +1373,52 @@ static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid) { // If you do not need the answer use NULL for *recv[] // return: length of received data // logging enabled -static int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *outdata) { +int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv, + uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time) { - int t_samples = 0, wait = 0, elapsed = 0, answer_len = 0; + if (init) { + Iso15693InitReader(); + StartCountSspClk(); + } - LEDsoff(); + int answerLen = 0; - if (init) Iso15693InitReader(); + if (speed_fast) { + // high speed (1 out of 4) + CodeIso15693AsReader(send, sendlen); + } else { + // low speed (1 out of 256) + CodeIso15693AsReader256(send, sendlen); + } - LED_A_ON(); + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); + uint32_t end_time = start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF + LogTrace(send, sendlen, start_time*4, end_time*4, NULL, true); - if (!speed) - CodeIso15693AsReader256(send, sendlen); // low speed (1 out of 256) - else - CodeIso15693AsReader(send, sendlen); // high speed (1 out of 4) + // Now wait for a response + if (recv != NULL) { + answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + } - LED_A_INV(); + return answerLen; +} - uint32_t time_start = GetCountSspClk(); +int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time) { - TransmitTo15693Tag(ToSend, ToSendMax, &t_samples, &wait); - LogTrace(send, sendlen, time_start << 4, GetCountSspClk() << 4, NULL, true); + int answerLen = 0; - // Now wait for a response - if (outdata != NULL) { - LED_B_INV(); - answer_len = GetIso15693AnswerFromTag(outdata, &elapsed); - } + CodeIso15693AsReaderEOF(); - LEDsoff(); - return answer_len; + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); + uint32_t end_time = start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF + LogTrace(NULL, 0, start_time*4, end_time*4, NULL, true); + + // Now wait for a response + if (recv != NULL) { + answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + } + + return answerLen; } // -------------------------------------------------------------------- @@ -745,10 +1430,13 @@ static int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t static void DbdecodeIso15693Answer(int len, uint8_t *d) { if (len > 3) { + char status[DBD15STATLEN + 1] = {0}; - if (d[0] & (1 << 3)) + + if (d[0] & ISO15_RES_EXT) strncat(status, "ProtExt ", DBD15STATLEN - strlen(status)); - if (d[0] & 1) { + + if (d[0] & ISO15_RES_ERROR) { // error strncat(status, "Error ", DBD15STATLEN - strlen(status)); switch (d[1]) { @@ -788,9 +1476,9 @@ static void DbdecodeIso15693Answer(int len, uint8_t *d) { } if (CheckCrc15(d, len)) - strncat(status, "[+] crc OK", DBD15STATLEN - strlen(status)); + strncat(status, "[+] crc (" _GREEN_("OK") ")", DBD15STATLEN - strlen(status)); else - strncat(status, "[!] crc fail", DBD15STATLEN - strlen(status)); + strncat(status, "[!] crc (" _RED_("fail") ")", DBD15STATLEN - strlen(status)); if (DBGLEVEL >= DBG_ERROR) Dbprintf("%s", status); } @@ -807,41 +1495,35 @@ static void DbdecodeIso15693Answer(int len, uint8_t *d) { // ok // parameter is unused !?! void ReaderIso15693(uint32_t parameter) { - int answerLen1 = 0; - int tsamples = 0, wait = 0, elapsed = 0; - // set up device/fpga - Iso15693InitReader(); - uint8_t *answer1 = BigBuf_malloc(50); - uint8_t *answer2 = BigBuf_malloc(50); + LED_A_ON(); + set_tracing(true); - // Blank arrays - memset(answer1, 0x00, 50); - memset(answer2, 0x00, 50); + uint8_t *answer = BigBuf_malloc(ISO15693_MAX_RESPONSE_LENGTH); + memset(answer, 0x00, ISO15693_MAX_RESPONSE_LENGTH); - // Now send the IDENTIFY command - // FIRST WE RUN AN INVENTORY TO GET THE TAG UID - // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - uint32_t time_start = GetCountSspClk(); - uint8_t cmd[CMD_ID_RESP] = {0}; - BuildIdentifyRequest(cmd); - TransmitTo15693Tag(ToSend, ToSendMax, &tsamples, &wait); - LogTrace(cmd, CMD_ID_RESP, time_start << 4, GetCountSspClk() << 4, NULL, true); + // FIRST WE RUN AN INVENTORY TO GET THE TAG UID + // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - // Now wait for a response - answerLen1 = GetIso15693AnswerFromTag(answer1, &elapsed) ; + // Send the IDENTIFY command + uint8_t cmd[5] = {0}; + BuildIdentifyRequest(cmd); + uint32_t start_time = 0; + uint32_t eof_time; + int answerLen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; // we should do a better check than this - if (answerLen1 >= 12) { + if (answerLen >= 12) { uint8_t uid[8]; - uid[0] = answer1[9]; // always E0 - uid[1] = answer1[8]; // IC Manufacturer code - uid[2] = answer1[7]; - uid[3] = answer1[6]; - uid[4] = answer1[5]; - uid[5] = answer1[4]; - uid[6] = answer1[3]; - uid[7] = answer1[2]; + uid[0] = answer[9]; // always E0 + uid[1] = answer[8]; // IC Manufacturer code + uid[2] = answer[7]; + uid[3] = answer[6]; + uid[4] = answer[5]; + uid[5] = answer[4]; + uid[6] = answer[3]; + uid[7] = answer[2]; if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X", @@ -854,36 +1536,37 @@ void ReaderIso15693(uint32_t parameter) { // arg1 = len of response (12 bytes) // arg2 = rtf // asbytes = uid. - reply_old(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid)); + reply_mix(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid)); } if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("[+] %d octets read from IDENTIFY request:", answerLen1); - DbdecodeIso15693Answer(answerLen1, answer1); - Dbhexdump(answerLen1, answer1, true); + Dbprintf("[+] %d octets read from IDENTIFY request:", answerLen); + DbdecodeIso15693Answer(answerLen, answer); + Dbhexdump(answerLen, answer, true); } switch_off(); + BigBuf_free(); +} + +// When SIM: initialize the Proxmark3 as ISO15693 tag +static void Iso15693InitTag(void) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); + StartCountSspClk(); } // Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands // all demodulation performed in arm rather than host. - greg -void SimTagIso15693(uint32_t parameter, uint8_t *uid) { +void SimTagIso15693(uint8_t *uid) { LEDsoff(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + Iso15693InitTag(); LED_A_ON(); - uint32_t time_start; - int samples = 0, tsamples = 0; - int wait = 0, elapsed = 0; - Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]); uint8_t buf[ISO15_MAX_FRAME]; @@ -892,31 +1575,29 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) { LED_C_ON(); // Build a suitable reponse to the reader INVENTORY cocmmand - // not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. - uint8_t cmd[CMD_INV_RESP] = {0}; - BuildInventoryResponse(cmd, uid); + // not so obvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. + BuildInventoryResponse(uid); - while (!BUTTON_PRESS() && !data_available()) { + while (!BUTTON_PRESS()) { WDT_HIT(); // Listen to reader - int ans = GetIso15693AnswerFromSniff(buf, &samples, &elapsed) ; + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + uint32_t eof_time = 0, start_time = 0; + int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); - // we should do a better check than this - if (ans >= 1) { + if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { // TODO: check more flags + bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); + start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } - time_start = GetCountSspClk(); - TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait); - LogTrace(cmd, CMD_INV_RESP, time_start << 4, GetCountSspClk() << 4, NULL, true); - - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("[+] %d octets read from reader command: %x %x %x %x %x %x %x %x", ans, - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7] - ); - } + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf(" %d bytes read from reader:", cmd_len); + Dbhexdump(cmd_len, cmd, false); } - } + } + switch_off(); } @@ -924,12 +1605,8 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) { // (some manufactures offer a way to read the AFI, though) void BruteforceIso15693Afi(uint32_t speed) { - uint8_t data[7] = {0, 0, 0, 0, 0, 0, 0}; - uint8_t buf[ISO15_MAX_FRAME]; - memset(buf, 0x00, sizeof(buf)); - int datalen = 0, recvlen = 0; - bool aborted = false; - + uint8_t data[7] = {0}; + uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH]; Iso15693InitReader(); // first without AFI @@ -939,31 +1616,40 @@ void BruteforceIso15693Afi(uint32_t speed) { data[1] = ISO15_CMD_INVENTORY; data[2] = 0; // AFI AddCrc15(data, 3); - datalen = 5; - recvlen = SendDataTag(data, datalen, false, speed, buf); + + int datalen = 5; + uint32_t eof_time = 0; + uint32_t start_time = GetCountSspClk(); + int recvlen = SendDataTag(data, datalen, true, speed, recv, sizeof(recv), 0, ISO15693_READER_TIMEOUT, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); if (recvlen >= 12) { - Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, buf + 2)); + Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, recv + 2)); } // now with AFI data[0] |= ISO15_REQINV_AFI; - //data[1] = ISO15_CMD_INVENTORY; data[2] = 0; // AFI data[3] = 0; // mask length // 4 + 2crc datalen = 6; + bool aborted = false; for (uint16_t i = 0; i < 256; i++) { + data[2] = i & 0xFF; AddCrc15(data, 4); - recvlen = SendDataTag(data, datalen, false, speed, buf); + + recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time, ISO15693_READER_TIMEOUT, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + WDT_HIT(); + if (recvlen >= 12) { - Dbprintf("AFI = %i UID = %s", i, iso15693_sprintUID(NULL, buf + 2)); + Dbprintf("AFI = %i UID = %s", i, iso15693_sprintUID(NULL, recv + 2)); } aborted = BUTTON_PRESS(); @@ -985,34 +1671,129 @@ void BruteforceIso15693Afi(uint32_t speed) { } // Allows to directly send commands to the tag via the client -// Has to increase dialog between device and client. +// OBS: doesn't turn off rf field afterwards. void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data) { - bool init = true; - int buflen = 0; - uint8_t buf[ISO15_MAX_FRAME]; - memset(buf, 0x00, sizeof(buf)); + LED_A_ON(); - if (DBGLEVEL >= DBG_EXTENDED) { - DbpString("[+] SEND"); - Dbhexdump(datalen, data, true); - } + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + uint32_t eof_time; + uint16_t timeout; + bool request_answer = false; + + switch (data[1]) { + case ISO15_CMD_WRITE: + case ISO15_CMD_LOCK: + case ISO15_CMD_WRITEMULTI: + case ISO15_CMD_WRITEAFI: + case ISO15_CMD_LOCKAFI: + case ISO15_CMD_WRITEDSFID: + case ISO15_CMD_LOCKDSFID: + timeout = ISO15693_READER_TIMEOUT_WRITE; + request_answer = data[0] & ISO15_REQ_OPTION; + break; + default: + timeout = ISO15693_READER_TIMEOUT; + } - buflen = SendDataTag(data, datalen, init, speed, (recv ? buf : NULL)); + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("SEND:"); + Dbhexdump(datalen, data, false); + } + + recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), 0, timeout, &eof_time); + + // send a single EOF to get the tag response + if (request_answer) { + recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), 0, ISO15693_READER_TIMEOUT, &eof_time); + } + + // for the time being, switch field off to protect rdv4.0 + // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); if (recv) { - buflen = (buflen > ISO15_MAX_FRAME) ? ISO15_MAX_FRAME : buflen; - LED_B_ON(); - reply_old(CMD_ACK, buflen, 0, 0, buf, buflen); - LED_B_OFF(); + if (recvlen > ISO15693_MAX_RESPONSE_LENGTH) { + recvlen = ISO15693_MAX_RESPONSE_LENGTH; + } + reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); + + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("RECV:"); + if (recvlen > 0) { + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } + } + - if (DBGLEVEL >= DBG_EXTENDED) { - DbpString("[+] RECV"); - DbdecodeIso15693Answer(buflen, buf); - Dbhexdump(buflen, buf, true); - } } else { - reply_old(CMD_ACK, 1, 0, 0, 0, 0); + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); } } + + +//----------------------------------------------------------------------------- +// Work with "magic Chinese" card. +// +//----------------------------------------------------------------------------- + +// Set the UID on Magic ISO15693 tag (based on Iceman's LUA-script). +void SetTag15693Uid(uint8_t *uid) { + + LED_A_ON(); + + uint8_t cmd[4][9] = { + {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x3e, 0x00, 0x00, 0x00, 0x00}, + {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x3f, 0x69, 0x96, 0x00, 0x00}, + {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x38}, + {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x39} + }; + + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + uint32_t eof_time; + + // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) + cmd[2][3] = uid[7]; + cmd[2][4] = uid[6]; + cmd[2][5] = uid[5]; + cmd[2][6] = uid[4]; + + // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) + cmd[3][3] = uid[3]; + cmd[3][4] = uid[2]; + cmd[3][5] = uid[1]; + cmd[3][6] = uid[0]; + + AddCrc15(cmd[0], 7); + AddCrc15(cmd[1], 7); + AddCrc15(cmd[2], 7); + AddCrc15(cmd[3], 7); + + uint32_t start_time = 0; + + for (int i = 0; i < 4; i++) { + + recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), i == 0 ? true : false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("SEND:"); + Dbhexdump(sizeof(cmd[i]), cmd[i], false); + Dbprintf("RECV:"); + if (recvlen > 0) { + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } + } + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); +} diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 2233ba9fd..bc9b89eee 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -12,15 +12,32 @@ #define __ISO15693_H #include "common.h" - #include "pm3_cmd.h" // struct + + +// Delays in SSP_CLK ticks. +// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag +#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response + +//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16 +#define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response +#define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command + void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg -void SimTagIso15693(uint32_t parameter, uint8_t *uid); // simulate an ISO15693 tag - greg +void SimTagIso15693(uint8_t *uid); // simulate an ISO15693 tag - greg void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI - atrox void Iso15693InitReader(void); +void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string); + +int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv, + uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time); + +int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time); + +void SetTag15693Uid(uint8_t *uid); #endif From 8189809f4832572e3a9c259207b1ff3b9bf93098 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 2 Jul 2020 12:38:38 +0200 Subject: [PATCH 018/139] chg: adapt to fpga changes --- armsrc/iso14443a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 3b7b096a4..225337485 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2527,7 +2527,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Set up the synchronous serial port - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); // connect Demodulated Signal to ADC: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); From 2c0f595f865ad5407fcbc8f12f4b17d12e7247b3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 3 Jul 2020 14:59:10 +0200 Subject: [PATCH 019/139] no more snooping around --- fpga/fpga_felica.v | 2 +- fpga/fpga_hf.v | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fpga/fpga_felica.v b/fpga/fpga_felica.v index 461d90b02..7c1a95b93 100644 --- a/fpga/fpga_felica.v +++ b/fpga/fpga_felica.v @@ -26,7 +26,7 @@ `define FPGA_MAJOR_MODE_HF_READER 0 `define FPGA_MAJOR_MODE_HF_SIMULATOR 1 `define FPGA_MAJOR_MODE_HF_ISO14443A 2 -`define FPGA_MAJOR_MODE_HF_SNOOP 3 +`define FPGA_MAJOR_MODE_HF_SNIFF 3 `define FPGA_MAJOR_MODE_HF_ISO18092 4 `define FPGA_MAJOR_MODE_HF_GET_TRACE 5 `define FPGA_MAJOR_MODE_OFF 7 diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v index 5448219fc..35178a996 100644 --- a/fpga/fpga_hf.v +++ b/fpga/fpga_hf.v @@ -26,7 +26,7 @@ `define FPGA_MAJOR_MODE_HF_READER 0 `define FPGA_MAJOR_MODE_HF_SIMULATOR 1 `define FPGA_MAJOR_MODE_HF_ISO14443A 2 -`define FPGA_MAJOR_MODE_HF_SNOOP 3 +`define FPGA_MAJOR_MODE_HF_SNIFF 3 `define FPGA_MAJOR_MODE_HF_ISO18092 4 `define FPGA_MAJOR_MODE_HF_GET_TRACE 5 `define FPGA_MAJOR_MODE_OFF 7 From 7d1a27819720df273f59b03b6a8b98cbf7eba96b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 3 Jul 2020 21:33:17 +0200 Subject: [PATCH 020/139] merge hell p.x --- armsrc/fpgaloader.h | 8 +- armsrc/iclass.c | 2077 ++++++++------------------------------ armsrc/iclass.h | 3 +- armsrc/iso14443b.c | 841 ++++++++------- armsrc/iso14443b.h | 2 +- armsrc/iso15693.c | 30 +- armsrc/iso15693.h | 9 + client/src/cmdhf14b.c | 24 +- client/src/cmdhficlass.c | 31 +- include/pm3_cmd.h | 12 + 10 files changed, 919 insertions(+), 2118 deletions(-) diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 474c08e1a..17bd8bbc2 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -65,7 +65,7 @@ thres| x x x x x x x x #define FPGA_MAJOR_MODE_HF_READER (0<<6) // D #define FPGA_MAJOR_MODE_HF_SIMULATOR (1<<6) // D #define FPGA_MAJOR_MODE_HF_ISO14443A (2<<6) // D -#define FPGA_MAJOR_MODE_HF_SNOOP (3<<6) // D +#define FPGA_MAJOR_MODE_HF_SNIFF (3<<6) // D #define FPGA_MAJOR_MODE_HF_ISO18092 (4<<6) // D #define FPGA_MAJOR_MODE_HF_GET_TRACE (5<<6) // D @@ -87,9 +87,9 @@ thres| x x x x x x x x #define FPGA_HF_READER_MODE_RECEIVE_PHASE (2<<0) #define FPGA_HF_READER_MODE_SEND_FULL_MOD (3<<0) #define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD (4<<0) -#define FPGA_HF_READER_MODE_SNOOP_IQ (5<<0) -#define FPGA_HF_READER_MODE_SNOOP_AMPLITUDE (6<<0) -#define FPGA_HF_READER_MODE_SNOOP_PHASE (7<<0) +#define FPGA_HF_READER_MODE_SNIFF_IQ (5<<0) +#define FPGA_HF_READER_MODE_SNIFF_AMPLITUDE (6<<0) +#define FPGA_HF_READER_MODE_SNIFF_PHASE (7<<0) #define FPGA_HF_READER_MODE_SEND_JAM (8<<0) #define FPGA_HF_READER_SUBCARRIER_848_KHZ (0<<4) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 1e9bb671f..dbf759adf 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -54,6 +54,7 @@ #include "dbprint.h" #include "protocols.h" #include "ticks.h" +#include "iso15693.h" static int g_wait = 290; static int timeout = 5000; @@ -63,523 +64,33 @@ static uint32_t time_response = 0; static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay); int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); -#define MODE_SIM_CSN 0 -#define MODE_EXIT_AFTER_MAC 1 -#define MODE_FULLSIM 2 - -#ifndef ICLASS_DMA_BUFFER_SIZE -# define ICLASS_DMA_BUFFER_SIZE 256 -#endif - // The length of a received command will in most cases be no more than 18 bytes. -// 32 should be enough! +// we expect max 34 bytes as tag answer (response to READ4) #ifndef ICLASS_BUFFER_SIZE -#define ICLASS_BUFFER_SIZE 32 +#define ICLASS_BUFFER_SIZE 34 #endif +// iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after +// the reader command. This is measured from end of reader EOF to first modulation of the tag's SOF which starts with a 56,64us unmodulated period. +// 330us = 140 ssp_clk cycles @ 423,75kHz when simulating. +// 56,64us = 24 ssp_clk_cycles +#define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 24) + +// times in ssp_clk_cycles @ 3,3625MHz when acting as reader +#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER + +// times in samples @ 212kHz when acting as reader +#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us +#define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms +#define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us + #define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1) -//----------------------------------------------------------------------------- -// The software UART that receives commands from the reader, and its state -// variables. -//----------------------------------------------------------------------------- -/* -typedef struct { - enum { - STATE_UNSYNCD, - STATE_START_OF_COMMUNICATION, - STATE_RECEIVING - } state; - uint16_t shiftReg; - int bitCnt; - int byteCnt; -// int byteCntMax; - int posCnt; - int nOutOfCnt; - int OutOfCnt; - int syncBit; - int samples; - int highCnt; - int swapper; - int counter; - int bitBuffer; - int dropPosition; - uint8_t *output; -} tUartIc; -*/ -typedef struct { - enum { - DEMOD_IC_UNSYNCD, - DEMOD_IC_START_OF_COMMUNICATION, - DEMOD_IC_START_OF_COMMUNICATION2, - DEMOD_IC_START_OF_COMMUNICATION3, - DEMOD_IC_SOF_COMPLETE, - DEMOD_IC_MANCHESTER_D, - DEMOD_IC_MANCHESTER_E, - DEMOD_IC_END_OF_COMMUNICATION, - DEMOD_IC_END_OF_COMMUNICATION2, - DEMOD_IC_MANCHESTER_F, - DEMOD_IC_ERROR_WAIT - } state; - int bitCount; - int posCount; - int syncBit; - uint16_t shiftReg; - uint32_t buffer; - uint32_t buffer2; - uint32_t buffer3; - int buff; - int samples; - int len; - enum { - SUB_NONE, - SUB_FIRST_HALF, - SUB_SECOND_HALF, - SUB_BOTH - } sub; - uint8_t *output; -} tDemodIc; - -/* -* Abrasive's uart implementation -* https://github.com/abrasive/proxmark3/commit/2b8bff7daea8ae1193bf7ee29b1fa46e95218902 -*/ -// Static vars for UART -typedef struct { - bool synced; - bool frame; - bool frame_done; - uint8_t *buf; - int len; -} tUartIc; -static tUartIc Uart; - static void OnError(uint8_t reason) { reply_mix(CMD_ACK, 0, reason, 0, 0, 0); switch_off(); } -static void uart_reset(void) { - Uart.frame_done = false; - Uart.synced = false; - Uart.frame = false; -} - -static void uart_init(uint8_t *data) { - Uart.buf = data; - uart_reset(); -} - -static void uart_bit(uint8_t bit) { - static uint8_t buf = 0xff; - static uint8_t n_buf; - static int nmsg_byte; - buf <<= 1; - buf |= bit ? 1 : 0; - - if (!Uart.frame) { - if (buf == 0x7b) { // 0b0111 1011 - Uart.frame = true; - n_buf = 0; - Uart.len = 0; - nmsg_byte = 0; - } - } else { - static uint8_t msg_byte; - n_buf++; - if (n_buf == 8) { - msg_byte >>= 2; - switch (buf) { - case 0xbf: // 0 - 1011 1111 - break; - case 0xef: // 1 - 1110 1111 - msg_byte |= (1 << 6); - break; - case 0xfb: // 2 - 1111 1011 - msg_byte |= (2 << 6); - break; - case 0xfe: // 3 - 1111 1110 - msg_byte |= (3 << 6); - break; - case 0xdf: // eof - 1101 1111 - Uart.frame = false; - Uart.synced = false; - Uart.frame_done = true; - break; - default: - Uart.frame = false; - Uart.synced = false; - Dbprintf("[-] bad %02X at %d:%d", buf, Uart.len, nmsg_byte); - } - - if (Uart.frame) { // data bits - nmsg_byte += 2; - if (nmsg_byte >= 8) { - Uart.buf[Uart.len++] = msg_byte; - nmsg_byte = 0; - } - } - n_buf = 0; - buf = 0xff; - } - } -} - -static void uart_samples(uint8_t byte) { - static uint32_t buf; - static int window; - static int drop_next = 0; - - uint32_t falling; - int lz; - - if (!Uart.synced) { - if (byte == 0xFF) - return; - buf = 0xFFFFFFFF; - window = 0; - drop_next = 0; - Uart.synced = true; - } - - buf <<= 8; - buf |= byte; - - if (drop_next) { - drop_next = 0; - return; - } - -again: - falling = ~buf & ((buf >> 1) ^ buf) & (0xFF << window); - - uart_bit(!falling); - - if (!falling) - return; - - lz = __builtin_clz(falling) - 24 + window; - - // aim to get falling edge on fourth-leftmost bit of window - window += 3 - lz; - - if (window < 0) { - window += 8; - drop_next = 1; - } else if (window >= 8) { - window -= 8; - goto again; - } -} - - -/* -static void UartReset(){ - Uart.state = STATE_UNSYNCD; - Uart.shiftReg = 0; - Uart.bitCnt = 0; - Uart.byteCnt = 0; - Uart.posCnt = 0; - Uart.nOutOfCnt = 0; - Uart.OutOfCnt = 0; - Uart.syncBit = 0; - Uart.samples = 0; - Uart.highCnt = 0; - Uart.swapper = 0; - Uart.counter = 0; - Uart.bitBuffer = 0; - Uart.dropPosition = 0; -} -*/ - -/* -* READER TO CARD -* 1 out of 4 Decoding -* 1 out of 256 Decoding -*/ -/* -static RAMFUNC int OutOfNDecoding(int bit) { - //int error = 0; - int bitright; - - if (!Uart.bitBuffer) { - Uart.bitBuffer = bit ^ 0xFF0; - return false; - } else { - Uart.bitBuffer <<= 4; - Uart.bitBuffer ^= bit; - } - - // if (Uart.swapper) { - // Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF; - // Uart.byteCnt++; - // Uart.swapper = 0; - // if (Uart.byteCnt > 15) return true; - // } - // else { - // Uart.swapper = 1; - // } - - if (Uart.state != STATE_UNSYNCD) { - Uart.posCnt++; - - if ((Uart.bitBuffer & Uart.syncBit) ^ Uart.syncBit) - bit = 0; - else - bit = 1; - - if (((Uart.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) - bitright = 0; - else - bitright = 1; - - if(bit != bitright) - bit = bitright; - - - // So, now we only have to deal with *bit*, lets see... - if (Uart.posCnt == 1) { - // measurement first half bitperiod - if (!bit) { - // Drop in first half means that we are either seeing - // an SOF or an EOF. - - if (Uart.nOutOfCnt == 1) { - // End of Communication - Uart.state = STATE_UNSYNCD; - Uart.highCnt = 0; - if (Uart.byteCnt == 0) { - // Its not straightforward to show single EOFs - // So just leave it and do not return TRUE - Uart.output[0] = 0xf0; - Uart.byteCnt++; - } else { - return true; - } - } else if (Uart.state != STATE_START_OF_COMMUNICATION) { - // When not part of SOF or EOF, it is an error - Uart.state = STATE_UNSYNCD; - Uart.highCnt = 0; - //error = 4; - } - } - } else { - // measurement second half bitperiod - // Count the bitslot we are in... (ISO 15693) - Uart.nOutOfCnt++; - - if (!bit) { - if (Uart.dropPosition) { - if (Uart.state == STATE_START_OF_COMMUNICATION) { - //error = 1; - } else { - //error = 7; - } - // It is an error if we already have seen a drop in current frame - Uart.state = STATE_UNSYNCD; - Uart.highCnt = 0; - } else { - Uart.dropPosition = Uart.nOutOfCnt; - } - } - Uart.posCnt = 0; - - if (Uart.nOutOfCnt == Uart.OutOfCnt && Uart.OutOfCnt == 4) { - Uart.nOutOfCnt = 0; - - if (Uart.state == STATE_START_OF_COMMUNICATION) { - if (Uart.dropPosition == 4) { - Uart.state = STATE_RECEIVING; - Uart.OutOfCnt = 256; - } else if (Uart.dropPosition == 3) { - Uart.state = STATE_RECEIVING; - Uart.OutOfCnt = 4; - //Uart.output[Uart.byteCnt] = 0xdd; - //Uart.byteCnt++; - } else { - Uart.state = STATE_UNSYNCD; - Uart.highCnt = 0; - } - Uart.dropPosition = 0; - } else { - // RECEIVING DATA - // 1 out of 4 - if (!Uart.dropPosition) { - Uart.state = STATE_UNSYNCD; - Uart.highCnt = 0; - //error = 9; - } else { - Uart.shiftReg >>= 2; - - // Swap bit order - Uart.dropPosition--; - //if(Uart.dropPosition == 1) { Uart.dropPosition = 2; } - //else if(Uart.dropPosition == 2) { Uart.dropPosition = 1; } - - Uart.shiftReg ^= ((Uart.dropPosition & 0x03) << 6); - Uart.bitCnt += 2; - Uart.dropPosition = 0; - - if (Uart.bitCnt == 8) { - Uart.output[Uart.byteCnt] = (Uart.shiftReg & 0xff); - Uart.byteCnt++; - Uart.bitCnt = 0; - Uart.shiftReg = 0; - } - } - } - } else if (Uart.nOutOfCnt == Uart.OutOfCnt) { - // RECEIVING DATA - // 1 out of 256 - if (!Uart.dropPosition) { - Uart.state = STATE_UNSYNCD; - Uart.highCnt = 0; - //error = 3; - } else { - Uart.dropPosition--; - Uart.output[Uart.byteCnt] = (Uart.dropPosition & 0xff); - Uart.byteCnt++; - Uart.bitCnt = 0; - Uart.shiftReg = 0; - Uart.nOutOfCnt = 0; - Uart.dropPosition = 0; - } - } -*/ -/*if (error) { - Uart.output[Uart.byteCnt] = 0xAA; - Uart.byteCnt++; - Uart.output[Uart.byteCnt] = error & 0xFF; - Uart.byteCnt++; - Uart.output[Uart.byteCnt] = 0xAA; - Uart.byteCnt++; - Uart.output[Uart.byteCnt] = (Uart.bitBuffer >> 8) & 0xFF; - Uart.byteCnt++; - Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF; - Uart.byteCnt++; - Uart.output[Uart.byteCnt] = (Uart.syncBit >> 3) & 0xFF; - Uart.byteCnt++; - Uart.output[Uart.byteCnt] = 0xAA; - Uart.byteCnt++; - return true; -}*/ -/* - } - } else { - bit = Uart.bitBuffer & 0xf0; - bit >>= 4; - bit ^= 0x0F; // drops become 1s ;-) - if (bit) { - // should have been high or at least (4 * 128) / fc - // according to ISO this should be at least (9 * 128 + 20) / fc - if (Uart.highCnt == 8) { - // we went low, so this could be start of communication - // it turns out to be safer to choose a less significant - // syncbit... so we check whether the neighbour also represents the drop - Uart.posCnt = 1; // apparently we are busy with our first half bit period - Uart.syncBit = bit & 8; - Uart.samples = 3; - - if (!Uart.syncBit) { Uart.syncBit = bit & 4; Uart.samples = 2; } - else if (bit & 4) { Uart.syncBit = bit & 4; Uart.samples = 2; bit <<= 2; } - - if (!Uart.syncBit) { Uart.syncBit = bit & 2; Uart.samples = 1; } - else if (bit & 2) { Uart.syncBit = bit & 2; Uart.samples = 1; bit <<= 1; } - - if (!Uart.syncBit) { Uart.syncBit = bit & 1; Uart.samples = 0; - if (Uart.syncBit && (Uart.bitBuffer & 8)) { - Uart.syncBit = 8; - - // the first half bit period is expected in next sample - Uart.posCnt = 0; - Uart.samples = 3; - } - } else if (bit & 1) { Uart.syncBit = bit & 1; Uart.samples = 0; } - - Uart.syncBit <<= 4; - Uart.state = STATE_START_OF_COMMUNICATION; - Uart.bitCnt = 0; - Uart.byteCnt = 0; - Uart.nOutOfCnt = 0; - Uart.OutOfCnt = 4; // Start at 1/4, could switch to 1/256 - Uart.dropPosition = 0; - Uart.shiftReg = 0; - //error = 0; - } else { - Uart.highCnt = 0; - } - } else { - if (Uart.highCnt < 8) - Uart.highCnt++; - } - } - return false; -} -*/ -//============================================================================= -// Manchester -//============================================================================= -static tDemodIc Demod; -static void DemodIcReset(void) { - Demod.bitCount = 0; - Demod.posCount = 0; - Demod.syncBit = 0; - Demod.shiftReg = 0; - Demod.buffer = 0; - Demod.buffer2 = 0; - Demod.buffer3 = 0; - Demod.buff = 0; - Demod.samples = 0; - Demod.len = 0; - Demod.sub = SUB_NONE; - Demod.state = DEMOD_IC_UNSYNCD; -} -static void DemodIcInit(uint8_t *data) { - Demod.output = data; - DemodIcReset(); -} - -// UART debug -// it adds the debug values which will be put in the tracelog, -// visible on client when running 'hf list iclass' -/* -pm3 --> hf li iclass -Recorded Activity (TraceLen = 162 bytes) - Start | End | Src | Data (! denotes parity error) | CRC | Annotation | -------------|------------|-----|-----------------------------------------------------------------|-----|--------------------| - 0 | 0 | Rdr |0a | | ACTALL - 1280 | 1280 | Tag |bb! 33! bb! 01 02 04 08 bb! | ok | - 1280 | 1280 | Rdr |0c | | IDENTIFY - 1616 | 1616 | Tag |bb! 33! bb! 00! 02 00! 02 bb! | ok | - 1616 | 1616 | Rdr |0a | | ACTALL - 2336 | 2336 | Tag |bb! d4! bb! 02 08 00! 08 bb! | ok | - 2336 | 2336 | Rdr |0c | | IDENTIFY - 2448 | 2448 | Tag |bb! 33! bb! 00! 00! 00! 02 bb! | ok | - 2448 | 2448 | Rdr |0a | | ACTALL - 2720 | 2720 | Tag |bb! d4! bb! 08 0b 01 04 bb! | ok | - 2720 | 2720 | Rdr |0c | | IDENTIFY - 3232 | 3232 | Tag |bb! d4! bb! 02 02 08 04 bb! | ok | -*/ -static void uart_debug(int error, int bit) { - Demod.output[Demod.len] = 0xBB; - Demod.len++; - Demod.output[Demod.len] = error & 0xFF; - Demod.len++; - Demod.output[Demod.len] = 0xBB; - Demod.len++; - Demod.output[Demod.len] = bit & 0xFF; - Demod.len++; - Demod.output[Demod.len] = Demod.buffer & 0xFF; - Demod.len++; - // Look harder ;-) - Demod.output[Demod.len] = Demod.buffer2 & 0xFF; - Demod.len++; - Demod.output[Demod.len] = Demod.syncBit & 0xFF; - Demod.len++; - Demod.output[Demod.len] = 0xBB; - Demod.len++; -} - /* * CARD TO READER * in ISO15693-2 mode - Manchester @@ -596,568 +107,63 @@ static void uart_debug(int error, int bit) { * * So for current implementation in ISO15693, its 330 µs from end of reader, to start of card. */ -static RAMFUNC int ManchesterDecoding_iclass(uint32_t v) { - int bit; - int modulation; - int error = 0; - - bit = Demod.buffer; - Demod.buffer = Demod.buffer2; - Demod.buffer2 = Demod.buffer3; - Demod.buffer3 = v; - - // too few bits? - if (Demod.buff < 3) { - Demod.buff++; - return false; - } - - if (Demod.state == DEMOD_IC_UNSYNCD) { - Demod.output[Demod.len] = 0xfa; - Demod.syncBit = 0; - //Demod.samples = 0; - Demod.posCount = 1; // This is the first half bit period, so after syncing handle the second part - - if (bit & 0x08) - Demod.syncBit = 0x08; - - if (bit & 0x04) { - if (Demod.syncBit) - bit <<= 4; - - Demod.syncBit = 0x04; - } - - if (bit & 0x02) { - if (Demod.syncBit) - bit <<= 2; - - Demod.syncBit = 0x02; - } - - if (bit & 0x01 && Demod.syncBit) - Demod.syncBit = 0x01; - - if (Demod.syncBit) { - Demod.len = 0; - Demod.state = DEMOD_IC_START_OF_COMMUNICATION; - Demod.sub = SUB_FIRST_HALF; - Demod.bitCount = 0; - Demod.shiftReg = 0; - Demod.samples = 0; - - if (Demod.posCount) { - - switch (Demod.syncBit) { - case 0x08: - Demod.samples = 3; - break; - case 0x04: - Demod.samples = 2; - break; - case 0x02: - Demod.samples = 1; - break; - case 0x01: - Demod.samples = 0; - break; - } - // SOF must be long burst... otherwise stay unsynced!!! - if (!(Demod.buffer & Demod.syncBit) || !(Demod.buffer2 & Demod.syncBit)) - Demod.state = DEMOD_IC_UNSYNCD; - - } else { - // SOF must be long burst... otherwise stay unsynced!!! - if (!(Demod.buffer2 & Demod.syncBit) || !(Demod.buffer3 & Demod.syncBit)) { - Demod.state = DEMOD_IC_UNSYNCD; - error = 0x88; - uart_debug(error, bit); - return false; - } - } - } - return false; - } - - // state is DEMOD is in SYNC from here on. - - modulation = bit & Demod.syncBit; - modulation |= ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; - Demod.samples += 4; - - if (Demod.posCount == 0) { - Demod.posCount = 1; - Demod.sub = (modulation) ? SUB_FIRST_HALF : SUB_NONE; - return false; - } - - Demod.posCount = 0; - - if (modulation) { - - if (Demod.sub == SUB_FIRST_HALF) - Demod.sub = SUB_BOTH; - else - Demod.sub = SUB_SECOND_HALF; - } - - if (Demod.sub == SUB_NONE) { - if (Demod.state == DEMOD_IC_SOF_COMPLETE) { - Demod.output[Demod.len] = 0x0f; - Demod.len++; - Demod.state = DEMOD_IC_UNSYNCD; - return true; - } else { - Demod.state = DEMOD_IC_ERROR_WAIT; - error = 0x33; - } - } - - switch (Demod.state) { - - case DEMOD_IC_START_OF_COMMUNICATION: - if (Demod.sub == SUB_BOTH) { - - Demod.state = DEMOD_IC_START_OF_COMMUNICATION2; - Demod.posCount = 1; - Demod.sub = SUB_NONE; - } else { - Demod.output[Demod.len] = 0xab; - Demod.state = DEMOD_IC_ERROR_WAIT; - error = 0xd2; - } - break; - - case DEMOD_IC_START_OF_COMMUNICATION2: - if (Demod.sub == SUB_SECOND_HALF) { - Demod.state = DEMOD_IC_START_OF_COMMUNICATION3; - } else { - Demod.output[Demod.len] = 0xab; - Demod.state = DEMOD_IC_ERROR_WAIT; - error = 0xd3; - } - break; - - case DEMOD_IC_START_OF_COMMUNICATION3: - if (Demod.sub == SUB_SECOND_HALF) { - Demod.state = DEMOD_IC_SOF_COMPLETE; - } else { - Demod.output[Demod.len] = 0xab; - Demod.state = DEMOD_IC_ERROR_WAIT; - error = 0xd4; - } - break; - - case DEMOD_IC_SOF_COMPLETE: - case DEMOD_IC_MANCHESTER_D: - case DEMOD_IC_MANCHESTER_E: - // OPPOSITE FROM ISO14443 - 11110000 = 0 (1 in 14443) - // 00001111 = 1 (0 in 14443) - if (Demod.sub == SUB_SECOND_HALF) { // SUB_FIRST_HALF - Demod.bitCount++; - Demod.shiftReg = (Demod.shiftReg >> 1) ^ 0x100; - Demod.state = DEMOD_IC_MANCHESTER_D; - } else if (Demod.sub == SUB_FIRST_HALF) { // SUB_SECOND_HALF - Demod.bitCount++; - Demod.shiftReg >>= 1; - Demod.state = DEMOD_IC_MANCHESTER_E; - } else if (Demod.sub == SUB_BOTH) { - Demod.state = DEMOD_IC_MANCHESTER_F; - } else { - Demod.state = DEMOD_IC_ERROR_WAIT; - error = 0x55; - } - break; - - case DEMOD_IC_MANCHESTER_F: - // Tag response does not need to be a complete byte! - if (Demod.len > 0 || Demod.bitCount > 0) { - if (Demod.bitCount > 1) { // was > 0, do not interpret last closing bit, is part of EOF - Demod.shiftReg >>= (9 - Demod.bitCount); // right align data - Demod.output[Demod.len] = Demod.shiftReg & 0xff; - Demod.len++; - } - - Demod.state = DEMOD_IC_UNSYNCD; - return true; - } else { - Demod.output[Demod.len] = 0xad; - Demod.state = DEMOD_IC_ERROR_WAIT; - error = 0x03; - } - break; - - case DEMOD_IC_ERROR_WAIT: - Demod.state = DEMOD_IC_UNSYNCD; - break; - - default: - Demod.output[Demod.len] = 0xdd; - Demod.state = DEMOD_IC_UNSYNCD; - break; - } - - if (Demod.bitCount >= 8) { - Demod.shiftReg >>= 1; - Demod.output[Demod.len] = (Demod.shiftReg & 0xff); - Demod.len++; - Demod.bitCount = 0; - Demod.shiftReg = 0; - } - - if (error) { - uart_debug(error, bit); - return true; - } - - return false; -} //============================================================================= -// Finally, a `sniffer' for iClass communication +// a `sniffer' for iClass communication // Both sides of communication! //============================================================================= -static void iclass_setup_sniff(void) { - if (DBGLEVEL > 3) Dbprintf("iclass_setup_sniff Enter"); - - LEDsoff(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Set up the synchronous serial port - FpgaSetupSsc(); - - BigBuf_free(); - BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(true); - - // Initialize Demod and Uart structs - DemodIcInit(BigBuf_malloc(ICLASS_BUFFER_SIZE)); - - uart_init(BigBuf_malloc(ICLASS_BUFFER_SIZE)); - //UartIcInit(BigBuf_malloc(ICLASS_BUFFER_SIZE)); - - if (DBGLEVEL > 1) { - // Print debug information about the buffer sizes - Dbprintf("[+] Sniffing buffers initialized:"); - Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); - Dbprintf(" Reader -> tag: %i bytes", ICLASS_BUFFER_SIZE); - Dbprintf(" tag -> Reader: %i bytes", ICLASS_BUFFER_SIZE); - Dbprintf(" DMA: %i bytes", ICLASS_DMA_BUFFER_SIZE); - } - - // Set FPGA in the appropriate mode - // put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER); - SpinDelay(200); - - // Start the SSP timer - StartCountSspClk(); - - LED_A_ON(); - if (DBGLEVEL > 3) Dbprintf("[+] iclass_setup_sniff Exit"); +void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string) { + SniffIso15693(jam_search_len, jam_search_string); } -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// turn off afterwards -void RAMFUNC SniffIClass(void) { - - //int datalen = 0; - uint32_t previous_data = 0; - uint32_t time_0 = 0, time_start = 0, time_stop; - uint32_t sniffCounter = 0; - bool TagIsActive = false; - bool ReaderIsActive = false; - - iclass_setup_sniff(); - - // The DMA buffer, used to stream samples from the FPGA - // *dmaBuf is the start reference. - uint8_t *dmaBuf = BigBuf_malloc(ICLASS_DMA_BUFFER_SIZE); - // pointer to samples from fpga - uint8_t *data = dmaBuf; - - // Setup and start DMA. - if (!FpgaSetupSscDma(dmaBuf, ICLASS_DMA_BUFFER_SIZE)) { - if (DBGLEVEL > 1) DbpString("[-] FpgaSetupSscDma failed. Exiting"); - return; - } - - // time ZERO, the point from which it all is calculated. - time_0 = GetCountSspClk(); - - // loop and listen - // every sample (1byte in data), - // contains HIGH nibble = reader data - // contains LOW nibble = tag data - // so two bytes are needed in order to get 1byte of either reader or tag data. (ie 2 sample bytes) - // since reader data is manchester encoded, we need 2bytes of data in order to get one demoded byte. (ie: 4 sample bytes) - uint16_t checked = 0; - for (;;) { - WDT_HIT(); - - if (checked == 1000) { - if (BUTTON_PRESS() || data_available()) break; - checked = 0; - } - ++checked; - - previous_data <<= 8; - previous_data |= *data; - - sniffCounter++; - data++; - - if (data == dmaBuf + ICLASS_DMA_BUFFER_SIZE) { - data = dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = ICLASS_DMA_BUFFER_SIZE; - } - - // every odd sample - if (sniffCounter & 0x01) { - // no need to try decoding reader data if the tag is sending - // READER TO CARD - if (!TagIsActive) { - LED_C_INV(); - // HIGH nibble is always reader data. - uint8_t reader_byte = (previous_data & 0xF0) | (*data >> 4); - uart_samples(reader_byte); - if (Uart.frame_done) { - time_stop = GetCountSspClk() - time_0; - LogTrace(Uart.buf, Uart.len, time_start, time_stop, NULL, true); - DemodIcReset(); - uart_reset(); - } else { - time_start = GetCountSspClk() - time_0; - } - ReaderIsActive = Uart.frame_done; - } - } - // every four sample - if ((sniffCounter % 4) == 0) { - // need two samples to feed Manchester - // no need to try decoding tag data if the reader is sending - and we cannot afford the time - // CARD TO READER - if (!ReaderIsActive) { - LED_C_INV(); - // LOW nibble is always tag data. - /* - uint32_t tag_byte = - ((previous_data & 0x0F000000) >> 8 ) | - ((previous_data & 0x000F0000) >> 4 ) | - ((previous_data & 0x00000F00) ) | - ((previous_data & 0x0000000F) << 4 ) | - (*data & 0xF); - */ - - - uint8_t tag_byte = ((previous_data & 0xF) << 4) | (*data & 0xF); - if (ManchesterDecoding_iclass(tag_byte)) { - time_stop = GetCountSspClk() - time_0; - LogTrace(Demod.output, Demod.len, time_start, time_stop, NULL, false); - DemodIcReset(); - uart_reset(); - } else { - time_start = GetCountSspClk() - time_0; - } - TagIsActive = (Demod.state != DEMOD_IC_UNSYNCD); - } - } - } // end main loop - - /* - if (DBGLEVEL >= 1) { - DbpString("[+] Sniff statistics:"); - Dbhexdump(ICLASS_DMA_BUFFER_SIZE, data, false); - } - */ - switch_off(); +static void rotateCSN(uint8_t *original_csn, uint8_t *rotated_csn) { + for (uint8_t i = 0; i < 8; i++) + rotated_csn[i] = (original_csn[i] >> 3) | (original_csn[(i + 1) % 8] << 5); } -static void rotateCSN(uint8_t *originalCSN, uint8_t *rotatedCSN) { - int i; - for (i = 0; i < 8; i++) - rotatedCSN[i] = (originalCSN[i] >> 3) | (originalCSN[(i + 1) % 8] << 5); +// Encode SOF only +static void CodeIClassTagSOF(void) { + ToSendReset(); + ToSend[++ToSendMax] = 0x1D; + ToSendMax++; } -//----------------------------------------------------------------------------- -// SIMULATION -// Wait for commands from reader -// Stop when button is pressed -// Or return TRUE when command is captured -//----------------------------------------------------------------------------- -static bool GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) { - // 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(); - uart_init(received); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - (void)b; - - uint16_t checked = 0; - for (;;) { - - WDT_HIT(); - - if (checked == 1000) { - if (BUTTON_PRESS() || data_available()) return false; - checked = 0; - } - ++checked; - - // keep tx buffer in a defined state anyway. - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) - AT91C_BASE_SSC->SSC_THR = 0x00; - - // wait for byte to become available in rx holding register - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - uart_samples(b); - if (Uart.frame_done) { - *len = Uart.len; - return true; - } - } - } - return false; -} /* -static uint8_t encode4Bits(const uint8_t b) { - // OTA, the least significant bits first - // Manchester encoding added - // The columns are - // 1 - Bit value to send - // 2 - Reversed (big-endian) - // 3 - Machester Encoded - // 4 - Hex values + * SOF comprises 3 parts; + * * An unmodulated time of 56.64 us + * * 24 pulses of 423.75 kHz (fc/32) + * * A logic 1, which starts with an unmodulated time of 18.88us + * followed by 8 pulses of 423.75kHz (fc/32) + * + * + * EOF comprises 3 parts: + * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated + * time of 18.88us. + * - 24 pulses of fc/32 + * - An unmodulated time of 56.64 us + * + * + * A logic 0 starts with 8 pulses of fc/32 + * followed by an unmodulated time of 256/fc (~18,88us). + * + * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by + * 8 pulses of fc/32 (also 18.88us) + * + * The mode FPGA_HF_SIMULATOR_MODULATE_424K_8BIT which we use to simulate tag, + * works like this. + * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). + * - A 0-bit input to the FPGA becomes an unmodulated time of 18.88us + * + * In this mode + * SOF can be written as 00011101 = 0x1D + * EOF can be written as 10111000 = 0xb8 + * logic 1 be written as 01 = 0x1 + * logic 0 be written as 10 = 0x2 + * + * + */ - uint8_t c = b & 0xF; - switch (c) { - // 1 2 3 4 - case 15: - return 0x55; // 1111 -> 1111 -> 01010101 -> 0x55 - case 14: - return 0x95; // 1110 -> 0111 -> 10010101 -> 0x95 - case 13: - return 0x65; // 1101 -> 1011 -> 01100101 -> 0x65 - case 12: - return 0xa5; // 1100 -> 0011 -> 10100101 -> 0xa5 - case 11: - return 0x59; // 1011 -> 1101 -> 01011001 -> 0x59 - case 10: - return 0x99; // 1010 -> 0101 -> 10011001 -> 0x99 - case 9: - return 0x69; // 1001 -> 1001 -> 01101001 -> 0x69 - case 8: - return 0xa9; // 1000 -> 0001 -> 10101001 -> 0xa9 - case 7: - return 0x56; // 0111 -> 1110 -> 01010110 -> 0x56 - case 6: - return 0x96; // 0110 -> 0110 -> 10010110 -> 0x96 - case 5: - return 0x66; // 0101 -> 1010 -> 01100110 -> 0x66 - case 4: - return 0xa6; // 0100 -> 0010 -> 10100110 -> 0xa6 - case 3: - return 0x5a; // 0011 -> 1100 -> 01011010 -> 0x5a - case 2: - return 0x9a; // 0010 -> 0100 -> 10011010 -> 0x9a - case 1: - return 0x6a; // 0001 -> 1000 -> 01101010 -> 0x6a - default: - return 0xaa; // 0000 -> 0000 -> 10101010 -> 0xaa - } -} -*/ - -static uint8_t lut_enc[] = { 0xAA, 0x6A, 0x9A, 0x5A, 0xA6, 0x66, 0x96, 0x56, 0xA9, 0x69, 0x99, 0x59, 0xA5, 0x65, 0x95, 0x55 }; - -//----------------------------------------------------------------------------- -// Prepare tag messages -//----------------------------------------------------------------------------- -static void CodeIClassTagAnswer(const uint8_t *cmd, int len) { - /* - * SOF comprises 3 parts; - * * An unmodulated time of 56.64 us - * * 24 pulses of 423.75 kHz (fc/32) - * * A logic 1, which starts with an unmodulated time of 18.88us - * followed by 8 pulses of 423.75kHz (fc/32) - * - * - * EOF comprises 3 parts: - * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated - * time of 18.88us. - * - 24 pulses of fc/32 - * - An unmodulated time of 56.64 us - * - * - * A logic 0 starts with 8 pulses of fc/32 - * followed by an unmodulated time of 256/fc (~18,88us). - * - * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by - * 8 pulses of fc/32 (also 18.88us) - * - * The mode FPGA_HF_SIMULATOR_MODULATE_424K_8BIT which we use to simulate tag, - * works like this. - * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). - * - A 0-bit input to the FPGA becomes an unmodulated time of 18.88us - * - * In this mode - * SOF can be written as 00011101 = 0x1D - * EOF can be written as 10111000 = 0xb8 - * logic 1 be written as 01 = 0x1 - * logic 0 be written as 10 = 0x2 - * - * */ - ToSendReset(); - - // Send SOF - ToSend[++ToSendMax] = 0x1D; - - int i; - for (i = 0; i < len; i++) { - uint8_t b = cmd[i]; - ToSend[++ToSendMax] = lut_enc[b & 0xF]; // least significant half - ToSend[++ToSendMax] = lut_enc[(b >> 4) & 0xF]; // most significant half - } - - // Send EOF - ToSend[++ToSendMax] = 0xB8; - //lastProxToAirDuration = 8*ToSendMax - 3*8 - 3*8;//Not counting zeroes in the beginning or end - // Convert from last byte pos to length - ToSendMax++; -} - -// Only SOF -static void CodeIClassTagSOF(void) { - //So far a dummy implementation, not used - //int lastProxToAirDuration =0; - - ToSendReset(); - // Send SOF - ToSend[++ToSendMax] = 0x1D; - // lastProxToAirDuration = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning - - // Convert from last byte pos to length - ToSendMax++; -} /** * @brief SimulateIClass simulates an iClass card. @@ -1178,13 +184,8 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - // this will clear out bigbuf memory, the eload command must select this before! - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaSetupSsc(); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Enable and clear the trace + Iso15693InitTag(); + clear_trace(); set_tracing(true); @@ -1195,30 +196,29 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain uint8_t *emulator = BigBuf_get_EM_addr(); uint8_t mac_responses[PM3_CMD_DATA_SIZE] = { 0 }; - if (simType == 0) { + if (simType == ICLASS_SIM_MODE_CSN) { // Use the CSN from commandline memcpy(emulator, datain, 8); - doIClassSimulation(MODE_SIM_CSN, NULL); - } else if (simType == 1) { + doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); + } else if (simType == ICLASS_SIM_MODE_CSN_DEFAULT) { //Default CSN - uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; + uint8_t csn[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0 }; // Use the CSN from commandline - memcpy(emulator, csn_crc, 8); - doIClassSimulation(MODE_SIM_CSN, NULL); - } else if (simType == 2) { + memcpy(emulator, csn, 8); + doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); + } else if (simType == ICLASS_SIM_MODE_READER_ATTACK) { Dbprintf("[+] going into attack mode, %d CSNS sent", numberOfCSNS); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time // in order to collect MAC's from the reader. This can later be used in an offlne-attack // in order to obtain the keys, as in the "dismantling iclass"-paper. -#define EPURSE_MAC_SIZE 16 + #define EPURSE_MAC_SIZE 16 int i = 0; for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < PM3_CMD_DATA_SIZE; i++) { - // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. memcpy(emulator, datain + (i * 8), 8); - if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { + if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { // Button pressed reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i, 0, mac_responses, i * EPURSE_MAC_SIZE); goto out; @@ -1226,11 +226,11 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain } reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i, 0, mac_responses, i * EPURSE_MAC_SIZE); - } else if (simType == 3) { + } else if (simType == ICLASS_SIM_MODE_FULL) { //This is 'full sim' mode, where we use the emulator storage for data. //ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command - doIClassSimulation(MODE_FULLSIM, NULL); - } else if (simType == 4) { + doIClassSimulation(ICLASS_SIM_MODE_FULL, NULL); + } else if (simType == ICLASS_SIM_MODE_READER_ATTACK_KEYROLL) { // This is the KEYROLL version of sim 2. // the collected data (mac_response) is doubled out since we are trying to collect both keys in the keyroll process. @@ -1287,11 +287,16 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // free eventually allocated BigBuf memory BigBuf_free_keep_EM(); - State cipher_state; + uint16_t page_size = 32 * 8; + uint8_t current_page = 0; - uint8_t *csn = BigBuf_get_EM_addr(); - uint8_t *emulator = csn; - uint8_t sof_data[] = { 0x0F} ; + // maintain cipher states for both credit and debit key for each page + State cipher_state_KD[8]; + State cipher_state_KC[8]; + State *cipher_state = &cipher_state_KD[0]; + + uint8_t *emulator = BigBuf_get_EM_addr(); + uint8_t *csn = emulator; // CSN followed by two CRC bytes uint8_t anticoll_data[10] = { 0 }; @@ -1305,28 +310,75 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { AddCrc(anticoll_data, 8); AddCrc(csn_data, 8); - uint8_t diversified_key[8] = { 0 }; + uint8_t diversified_kd[8] = { 0 }; + uint8_t diversified_kc[8] = { 0 }; + uint8_t *diversified_key = diversified_kd; + + // configuration block + uint8_t conf_block[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; // e-Purse uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - //uint8_t card_challenge_data[8] = { 0 }; - if (simulationMode == MODE_FULLSIM) { - //The diversified key should be stored on block 3 - //Get the diversified key from emulator memory - memcpy(diversified_key, emulator + (8 * 3), 8); - //Card challenge, a.k.a e-purse is on block 2 - memcpy(card_challenge_data, emulator + (8 * 2), 8); + // AIA + uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; + + if (simulationMode == ICLASS_SIM_MODE_FULL) { - //Precalculate the cipher state, feeding it the CC - cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key); + memcpy(conf_block, emulator + (8 * 1), 8); // blk 1 + memcpy(card_challenge_data, emulator + (8 * 2), 8); // e-purse, blk 2 + memcpy(diversified_kd, emulator + (8 * 3), 8); // Kd, blk 3 + memcpy(diversified_kc, emulator + (8 * 4), 8); // Kc, blk 4 + + + // (iceman) this only works for 2KS / 16KS tags. + // Use application data from block 5 + memcpy(aia_data, emulator + (8 * 5), 8); + // older 2K / 16K tags has its application issuer data on block 2 } + + AddCrc(conf_block, 8); + AddCrc(aia_data, 8); + // set epurse of sim2,4 attack if (reader_mac_buf != NULL) { memcpy(reader_mac_buf, card_challenge_data, 8); } + if ((conf_block[5] & 0x80) == 0x80) { + page_size = 256 * 8; + } + + // From PicoPass DS: + // When the page is in personalization mode this bit is equal to 1. + // Once the application issuer has personalized and coded its dedicated areas, this bit must be set to 0: + // the page is then "in application mode". + bool personalization_mode = conf_block[7] & 0x80; + + // chip memory may be divided in 8 pages + uint8_t max_page = ((conf_block[4] & 0x10) == 0x10) ? 0 : 7; + + // Precalculate the cipher states, feeding it the CC + cipher_state_KD[0] = opt_doTagMAC_1(card_challenge_data, diversified_kd); + cipher_state_KC[0] = opt_doTagMAC_1(card_challenge_data, diversified_kc); + + if (simulationMode == ICLASS_SIM_MODE_FULL) { + + for (int i = 1; i < max_page; i++) { + + // does all pages has their own epurse??) + uint8_t *epurse = emulator + (i * page_size) + (8 * 2); + uint8_t *kd = emulator + (i * page_size) + (8 * 3); + uint8_t *kc = emulator + (i * page_size) + (8 * 4); + + cipher_state_KD[i] = opt_doTagMAC_1(epurse, kd); + cipher_state_KC[i] = opt_doTagMAC_1(epurse, kc); + } + } + int exitLoop = 0; + + // Anti-collision process: // Reader 0a // Tag 0f // Reader 0c @@ -1340,8 +392,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { int trace_data_size = 0; // Respond SOF -- takes 1 bytes - uint8_t *resp_sof = BigBuf_malloc(2); - int resp_sof_Len; + uint8_t *resp_sof = BigBuf_malloc(1); + int resp_sof_len; // Anticollision CSN (rotated CSN) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) @@ -1353,34 +405,27 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t *resp_csn = BigBuf_malloc(28); int resp_csn_len; - // configuration Picopass 2ks + // configuration (blk 1) PICOPASS 2ks uint8_t *resp_conf = BigBuf_malloc(28); int resp_conf_len; - uint8_t conf_data[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; - AddCrc(conf_data, 8); // e-Purse // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) uint8_t *resp_cc = BigBuf_malloc(28); int resp_cc_len; + // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only + uint8_t *resp_ff = BigBuf_malloc(22); + int resp_ff_len; + uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; + AddCrc(ff_data, 8); + // Application Issuer Area uint8_t *resp_aia = BigBuf_malloc(28); int resp_aia_len; - uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; - if (simulationMode == MODE_FULLSIM) { - - // (iceman) this only works for 2KS / 16KS tags. - // Use application data from block 5 - memcpy(aia_data, emulator + (8 * 5), 8); - - // older 2K / 16K tags has its application issuer data on block 2 - } - AddCrc(aia_data, 8); // receive command uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - int len = 0; // Prepare card messages ToSendMax = 0; @@ -1388,142 +433,153 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // First card answer: SOF CodeIClassTagSOF(); memcpy(resp_sof, ToSend, ToSendMax); - resp_sof_Len = ToSendMax; + resp_sof_len = ToSendMax; // Anticollision CSN - CodeIClassTagAnswer(anticoll_data, sizeof(anticoll_data)); + CodeIso15693AsTag(anticoll_data, sizeof(anticoll_data)); memcpy(resp_anticoll, ToSend, ToSendMax); resp_anticoll_len = ToSendMax; - // CSN - CodeIClassTagAnswer(csn_data, sizeof(csn_data)); + // CSN (block 0) + CodeIso15693AsTag(csn_data, sizeof(csn_data)); memcpy(resp_csn, ToSend, ToSendMax); resp_csn_len = ToSendMax; - // Configuration - CodeIClassTagAnswer(conf_data, sizeof(conf_data)); + // Configuration (block 1) + CodeIso15693AsTag(conf_block, sizeof(conf_block)); memcpy(resp_conf, ToSend, ToSendMax); resp_conf_len = ToSendMax; - // e-Purse - CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data)); + // e-Purse (block 2) + CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; - // Application Issuer Area - CodeIClassTagAnswer(aia_data, sizeof(aia_data)); + // Kd, Kc (blocks 3 and 4) + CodeIso15693AsTag(ff_data, sizeof(ff_data)); + memcpy(resp_ff, ToSend, ToSendMax); + resp_ff_len = ToSendMax; + + // Application Issuer Area (block 5) + CodeIso15693AsTag(aia_data, sizeof(aia_data)); memcpy(resp_aia, ToSend, ToSendMax); resp_aia_len = ToSendMax; //This is used for responding to READ-block commands or other data which is dynamically generated //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_malloc((8 * 4) + 2);//8 bytes data + 2byte CRC is max tag answer + uint8_t *data_generic_trace = BigBuf_malloc(32 + 2);//8 bytes data + 2byte CRC is max tag answer //Then storage for the modulated data //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) - uint8_t *data_response = BigBuf_malloc(((8 * 4) + 2) * 2 + 2); + uint8_t *data_response = BigBuf_malloc((32 + 2) * 2 + 2); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - SpinDelay(100); - StartCountSspClk(); + enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; - // To control where we are in the protocol - uint32_t time_0 = GetCountSspClk(); - uint32_t t2r_stime = 0, t2r_etime = 0; - uint32_t r2t_stime, r2t_etime = 0; - LED_A_ON(); - bool buttonPressed = false; + bool button_pressed = false; uint8_t cmd, options, block; + int len = 0; - while (!exitLoop) { + while (exitLoop == false) { WDT_HIT(); - - //Signal tracer, can be used to get a trigger for an oscilloscope.. - LED_B_OFF(); - LED_C_OFF(); - - r2t_stime = (GetCountSspClk() - time_0) << 4; - if (!GetIClassCommandFromReader(receivedCmd, &len, 0)) { - buttonPressed = true; + + uint32_t reader_eof_time = 0; + len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); + if (len < 0) { + button_pressed = true; exitLoop = true; continue; } - r2t_etime = ((GetCountSspClk() - time_0) << 4) - r2t_stime; - // 330us normal wait, adjusted for our execution - - LED_C_ON(); //Signal tracer + // Now look at the reader command and provide appropriate responses + // default is no response: + modulated_response = NULL; + modulated_response_size = 0; + trace_data = NULL; + trace_data_size = 0; + // extra response data cmd = receivedCmd[0] & 0xF; options = (receivedCmd[0] >> 4) & 0xFF; block = receivedCmd[1]; - if (cmd == ICLASS_CMD_ACTALL) { // 0x0A + if (cmd == ICLASS_CMD_ACTALL && len == 1) { // 0x0A // Reader in anticollission phase - modulated_response = resp_sof; - modulated_response_size = resp_sof_Len; //order = 1; - trace_data = sof_data; - trace_data_size = sizeof(sof_data); - // adjusted for 330 + (160*num of slot) - goto send; - } else if (cmd == ICLASS_CMD_READ_OR_IDENTIFY) { // 0x0C - if (len == 1) { - // Reader asks for anticollission CSN - modulated_response = resp_anticoll; - modulated_response_size = resp_anticoll_len; //order = 2; - trace_data = anticoll_data; - trace_data_size = sizeof(anticoll_data); + if (chip_state != HALTED) { + modulated_response = resp_sof; + modulated_response_size = resp_sof_len; //order = 1; + chip_state = ACTIVATED; goto send; } + } else if (cmd == ICLASS_CMD_READ_OR_IDENTIFY) { // 0x0C + if (len == 1) { + // Reader asks for anticollission CSN + if (chip_state == SELECTED || chip_state == ACTIVATED) { + modulated_response = resp_anticoll; + modulated_response_size = resp_anticoll_len; //order = 2; + trace_data = anticoll_data; + trace_data_size = sizeof(anticoll_data); + goto send; + } + } + if (len == 4) { - // block0,1,2,5 is always readable. - switch (block) { - case 0: // csn (0c 00) - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - goto send; - case 1: // configuration (0c 01) - modulated_response = resp_conf; - modulated_response_size = resp_conf_len; - trace_data = conf_data; - trace_data_size = sizeof(conf_data); - goto send; - case 2: // e-purse (0c 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - // set epurse of sim2,4 attack - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, card_challenge_data, 8); - } - goto send; - case 5:// Application Issuer Area (0c 05) - modulated_response = resp_aia; - modulated_response_size = resp_aia_len; - trace_data = aia_data; - trace_data_size = sizeof(aia_data); - goto send; - default : { - if (simulationMode == MODE_FULLSIM) { // 0x0C - //Read block - //Take the data... - memcpy(data_generic_trace, emulator + (block << 3), 8); - AddCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIClassTagAnswer(trace_data, trace_data_size); - memcpy(modulated_response, ToSend, ToSendMax); - modulated_response_size = ToSendMax; + if (chip_state == SELECTED) { + // block0,1,2,5 is always readable. + switch (block) { + case 0: // csn (0c 00) + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); goto send; + case 1: // configuration (0c 01) + modulated_response = resp_conf; + modulated_response_size = resp_conf_len; + trace_data = conf_data; + trace_data_size = sizeof(conf_data); + goto send; + case 2: // e-purse (0c 02) + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + // set epurse of sim2,4 attack + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, card_challenge_data, 8); + } + goto send; + case 3: + case 4: // Kd, Kc, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + goto send; + case 5:// Application Issuer Area (0c 05) + modulated_response = resp_aia; + modulated_response_size = resp_aia_len; + trace_data = aia_data; + trace_data_size = sizeof(aia_data); + goto send; + default : { + if (simulationMode == ICLASS_SIM_MODE_FULL) { // 0x0C + //Read block + //Take the data... + memcpy(data_generic_trace, emulator + (block << 3), 8); + AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIClassTagAnswer(trace_data, trace_data_size); + memcpy(modulated_response, ToSend, ToSendMax); + modulated_response_size = ToSendMax; + goto send; + } + break; } - break; - } - }//swith - }// if 4 + } // swith + } // selected + } // if 4 } else if (cmd == ICLASS_CMD_SELECT) { // 0x81 // Reader selects anticollission CSN. // Tag sends the corresponding real CSN @@ -1542,7 +598,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { goto send; } else if (cmd == ICLASS_CMD_CHECK) { // 0x05 // Reader random and reader MAC!!! - if (simulationMode == MODE_FULLSIM) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { // NR, from reader, is in receivedCmd +1 opt_doTagMAC_2(cipher_state, receivedCmd + 1, data_generic_trace, diversified_key); @@ -1579,24 +635,28 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } goto send; } else if (cmd == ICLASS_CMD_HALT && options == 0 && len == 1) { - // Reader ends the session - modulated_response = resp_sof; - modulated_response_size = 0; //order = 0; - trace_data = NULL; - trace_data_size = 0; - goto send; - } else if (simulationMode == MODE_FULLSIM && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06 - //Read block - //Take the data... - memcpy(data_generic_trace, emulator + (block << 3), 8 * 4); - AddCrc(data_generic_trace, 8 * 4); - trace_data = data_generic_trace; - trace_data_size = 34; - CodeIClassTagAnswer(trace_data, trace_data_size); - memcpy(modulated_response, ToSend, ToSendMax); - modulated_response_size = ToSendMax; - goto send; - } else if (simulationMode == MODE_FULLSIM && cmd == ICLASS_CMD_UPDATE) { + + if (chip_state == SELECTED) { + // Reader ends the session + modulated_response = resp_sof; + modulated_response_size = resp_sof_Len; + chip_state = HALTED; + goto send; + } + } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06 + + if (chip_state == SELECTED) { + //Read block + memcpy(data_generic_trace, emulator + (current_page * page_size) + (block * 8), 8 * 4); + AddCrc(data_generic_trace, 8 * 4); + trace_data = data_generic_trace; + trace_data_size = 34; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(modulated_response, ToSend, ToSendMax); + modulated_response_size = ToSendMax; + goto send; + } + } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_UPDATE) { //Probably the reader wants to update the nonce. Let's just ignore that for now. // OBS! If this is implemented, don't forget to regenerate the cipher_state @@ -1622,17 +682,12 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // It appears we're fine ignoring this. //Otherwise, we should answer 8bytes (block) + 2bytes CRC // } else if(receivedCmd[0] == ICLASS_CMD_DETECT) { // 0x0F + } else if (receivedCmd[0] == 0x26 && len == 5) { + // standard ISO15693 INVENTORY command. Ignore. } else { - //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 // Never seen this command before - if (DBGLEVEL == DBG_EXTENDED) + if (DBGLEVEL >= DBG_EXTENDED) print_result("[-] Unhandled command received ", receivedCmd, len); - - // Do not respond - modulated_response = resp_sof; - modulated_response_size = 0; //order = 0; - trace_data = NULL; - trace_data_size = 0; } send: @@ -1640,70 +695,20 @@ send: A legit tag has about 330us delay between reader EOT and tag SOF. **/ if (modulated_response_size > 0) { - t2r_stime = GetCountSspClkDelta(time_0) << 4; - SendIClassAnswer(modulated_response, modulated_response_size, 0); - t2r_etime = ((GetCountSspClk() - time_0) << 4) - t2r_stime; + uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM; + TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); + LogTrace(trace_data, trace_data_size, response_time*32, response_time*32 + modulated_response_size*32*64, NULL, false); } - - LogTrace(receivedCmd, len, r2t_stime, r2t_etime, NULL, true); - - if (trace_data != NULL) - LogTrace(trace_data, trace_data_size, t2r_stime, t2r_etime, NULL, false); } LEDsoff(); - if (buttonPressed) + if (button_pressed) DbpString("[+] button pressed"); - return buttonPressed; + return button_pressed; } -/** - * @brief sends our simulated tag answer - * @param resp - * @param respLen - * @param delay - */ -static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay) { - int i = 0; - volatile uint8_t b; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); - - AT91C_BASE_SSC->SSC_THR = 0x00; - - uint16_t checked = 0; - for (;;) { - - if (checked == 1000) { - if (BUTTON_PRESS() || data_available()) return 0; - checked = 0; - } - ++checked; - - // Prevent rx holding register from overflowing - if ((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) { - b = AT91C_BASE_SSC->SSC_RHR; - (void) b; - } - - // Put byte into tx holding register as soon as it is ready - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - b = 0x00; - if (i < respLen) { - b = resp[i]; - //Hack - //b = 0xAC; - } - i++; - AT91C_BASE_SSC->SSC_THR = b; - } -// if (i > respLen + 4) break; - if (i > respLen + 1) break; - } - return 0; -} /// THE READER CODE @@ -1754,194 +759,42 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *wait) { time_rdr = GetCountSspClk(); } -//----------------------------------------------------------------------------- -// Prepare iClass reader command to send to FPGA -//----------------------------------------------------------------------------- -static void CodeIClassCommand(const uint8_t *cmd, int len) { - int i, j, k; +static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) { - ToSendReset(); + CodeIso15693AsReader(frame, len); + TransmitTo15693Tag(ToSend, ToSendMax, start_time); + uint32_t end_time = *start_time + 32 * (8 * ToSendMax - 4); // substract the 4 padding bits after EOF - // (SOC) Start of Communication: 1 out of 4 - ToSend[++ToSendMax] = 0xf0; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x0f; - ToSend[++ToSendMax] = 0x00; - - // Modulate the bytes - for (i = 0; i < len; i++) { - uint8_t b = cmd[i]; - for (j = 0; j < 4; j++) { - for (k = 0; k < 4; k++) { - - if (k == (b & 3)) - ToSend[++ToSendMax] = 0x0f; - else - ToSend[++ToSendMax] = 0x00; - } - b >>= 2; - } - } - - // (EOC) End of Communication - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xf0; - ToSend[++ToSendMax] = 0x00; - - // Convert from last character reference to length - ToSendMax++; + LogTrace(frame, len, *start_time * 4, end_time * 4, NULL, true); } -static void ReaderTransmitIClass_ext(uint8_t *frame, int len, int wait) { +static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, + uint8_t expected_size, uint8_t tries, uint32_t start_time, + uint32_t timeout, uint32_t *eof_time) { + while (tries-- > 0) { - // This is tied to other size changes - CodeIClassCommand(frame, len); - - // Select the card - TransmitIClassCommand(ToSend, ToSendMax, &wait); - LED_A_ON(); - - LogTrace(frame, len, g_rsamples, g_rsamples, NULL, true); -} -static void ReaderTransmitIClass(uint8_t *frame, int len) { - ReaderTransmitIClass_ext(frame, len, 330); -} - -//----------------------------------------------------------------------------- -// Wait a certain time for tag response -// If a response is captured return TRUE -// If it takes too long return FALSE -//----------------------------------------------------------------------------- -static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *wait) { - // buffer needs to be 512 bytes - // maxLen is not used... - bool skip = false; - - LED_D_ON(); - // Set FPGA mode to "reader listen mode", no modulation (listen - // only, since we are receiving, not transmitting). - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); - - // Setup UART/DEMOD to receive - DemodIcInit(receivedResponse); - - SpinDelayUs(g_wait); //310 Tout= 330us (iso15603-2) (330/21.3) take consideration for clock increments. - - // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - (void)b; - - uint16_t checked = 0; - - uint32_t card_start = GetCountSspClk(); - for (;;) { - WDT_HIT(); - - if (checked == 1000) { - if (BUTTON_PRESS() || data_available()) return false; - checked = 0; - } - ++checked; - - // Wait for byte be become available in rx holding register - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - - b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - skip = !skip; - if (skip) continue; - - if (ManchesterDecoding_iclass(b & 0x0f)) { - time_response = GetCountSspClk() - card_start; - return true; - } else if (GetCountSspClkDelta(card_start) > timeout && Demod.state == DEMOD_IC_UNSYNCD) { - return false; - } - } - } - return false; -} - -static int ReaderReceiveIClass(uint8_t *receivedAnswer) { - - if (GetIClassAnswer(receivedAnswer, 0, NULL) == false) - return 0; - - LogTrace(receivedAnswer, Demod.len, g_rsamples, g_rsamples, NULL, false); - return Demod.len; -} - -static void setupIclassReader(void) { - - LEDsoff(); - - // Start from off (no field generated) - // Signal field is off with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - FpgaSetupSsc(); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - clear_trace(); - set_tracing(true); - - // Now give it time to spin up. - // Signal field is on with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - SpinDelay(500); - - StartCountSspClk(); - - LED_A_ON(); -} - -static bool sendCmdGetResponseWithRetries(uint8_t *command, size_t cmdsize, uint8_t *resp, uint8_t expected_size, int8_t retries) { - while (retries-- > 0) { - - ReaderTransmitIClass(command, cmdsize); - - //iceman - if received size is bigger than expected, we smash the stack here - // since its called with fixed sized arrays - - // update/write command takes 4ms to 15ms before responding - int old_wait = g_wait; - if ((command[0] & 0xF) == ICLASS_CMD_UPDATE) - g_wait = 3900; - - uint8_t got_n = ReaderReceiveIClass(resp); - - g_wait = old_wait; - - // 0xBB is the internal debug separator byte.. - if (expected_size != got_n || (resp[0] == 0xBB || resp[7] == 0xBB || resp[2] == 0xBB)) { - //try again -// SpinDelayUs(360); - continue; - } - - if (got_n == expected_size) + ReaderTransmitIClass(command, cmdsize, &start_time); + if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time)) { return true; + } } return false; } /** * @brief Talks to an iclass tag, sends the commands to get CSN and CC. - * @param card_data where the CSN and CC are stored for return - * @return 0 = fail - * 1 = Got CSN - * 2 = Got CSN and CC + * @param card_data where the CSN, CONFIG, CC are stored for return + * 8 bytes csn + 8 bytes config + 8 bytes CC + * @return false = fail + * true = Got all. */ -static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { +static bool selectIclassTag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { - // act_all... - static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; - static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; - static uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; + static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; + static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; + static uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; + static uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) willbe used // bit 7: parity. @@ -1950,58 +803,63 @@ static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; + + uint32_t start_time = GetCountSspClk(); - // Send act_all ( 330 timeout + 160 timeslot); - ReaderTransmitIClass_ext(act_all, 1, 330 + 180); + ReaderTransmitIClass(act_all, 1, &start_time); - // Card present? - if (ReaderReceiveIClass(resp) == 0) - return 0; + // card present? + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) + return false; - //Send Identify - ReaderTransmitIClass(identify, 1); + // send Identify + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + ReaderTransmitIClass(identify, 1, &start_time); - //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC - if (ReaderReceiveIClass(resp) != 10) - return 0; + // expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC + uint8_t len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); + if (len != 10) + return false; - //Copy the Anti-collision CSN to our select-packet + // copy the Anti-collision CSN to our select-packet memcpy(&select[1], resp, 8); - //Select the card - ReaderTransmitIClass(select, sizeof(select)); + // select the card + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + ReaderTransmitIClass(select, sizeof(select), &start_time); - //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC - if (ReaderReceiveIClass(resp) != 10) - return 0; + // expect a 10-byte response here, 8 byte CSN and 2 byte CRC + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); + if (len != 10) + return false; - // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) - // ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); - // if (ReaderReceiveIClass(resp) == 8) { - // //Save CC (e-purse) in response data - // memcpy(card_data+8, resp, 8); - // read_status++; - // } - - //Success - level 1, we got CSN //Save CSN in response data memcpy(card_data, resp, 8); - bool isBlk_2 = sendCmdGetResponseWithRetries(readcheck_cc, sizeof(readcheck_cc), resp, 8, 3); - - //Flag that we got to at least stage 1, read CSN - if (isBlk_2 == false) { - return 1; - } + // card selected, now read config (block1) (only 8 bytes no CRC) + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + ReaderTransmitIClass(read_conf, sizeof(read_conf), &start_time); + + // expect a 8-byte response here + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); + if (len != 8) + return false; //Save CC (e-purse) in response data memcpy(card_data + 8, resp, 8); - // we got all data; - return 2; -} -static uint8_t handshakeIclassTag(uint8_t *card_data) { - return handshakeIclassTag_ext(card_data, false); + // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); + + // expect a 8-byte response here + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); + if (len != 8) + return false; + + //Save CC (e-purse) in response data + memcpy(card_data + 16, resp, 8); + return true; } // Reader iClass Anticollission @@ -2015,129 +873,70 @@ void ReaderIClass(uint8_t arg0) { memset(card_data, 0xFF, sizeof(card_data)); memset(resp, 0xFF, sizeof(resp)); - //Read conf block CRC(0x01) => 0xfa 0x22 - uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; - - //Read App Issuer Area block CRC(0x05) => 0xde 0x64 - uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - - uint16_t tryCnt = 0; - bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; // flag to not to loop continuously, looking for tag bool use_credit_key = arg0 & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key - bool flagReadConfig = arg0 & FLAG_ICLASS_READER_CONF; // flag to read block1, configuration - bool flagReadCC = arg0 & FLAG_ICLASS_READER_CC; // flag to read block2, e-purse bool flagReadAIA = arg0 & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area - setupIclassReader(); + if (flags & FLAG_ICLASS_READER_INIT) { + Iso15693InitReader(); + } - uint16_t checked = 0; - bool userCancelled = BUTTON_PRESS() || data_available(); - while (!userCancelled) { + if (flags & FLAG_ICLASS_READER_CLEARTRACE) { + set_tracing(true); + clear_trace(); + StartCountSspClk(); + } - WDT_HIT(); + uint32_t start_time = 0; + uint32_t eof_time = 0; - // if only looking for one card try 2 times if we missed it the first time - if (try_once && tryCnt > 10) { - if (DBGLEVEL > 1) DbpString("Failed to find a tag"); - break; + int read_status = selectIclassTag(card_data, use_credit_key, &eof_time); + if (read_status == 0) { + reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); + switch_off(); + return; + } + + uint8_t result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC; + + //Read block 5, AIA + if (flagReadAIA) { + //Read App Issuer Area block CRC(0x05) => 0xde 0x64 + uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + + if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { + result_status |= FLAG_ICLASS_READER_AIA; + memcpy(card_data + (8 * 5), resp, 8); + } else { + if (DBGLEVEL >= DBG_EXTENDED) DbpString("Failed to dump AA block"); } + } - tryCnt++; - uint8_t result_status = 0; + // 0 : CSN + // 1 : Configuration + // 2 : e-purse + // 3 : kd / debit / aa2 (write-only) + // 4 : kc / credit / aa1 (write-only) + // 5 : AIA, Application issuer area + // + //Then we can 'ship' back the 6 * 8 bytes of data, + // with 0xFF:s in block 3 and 4. - int read_status = handshakeIclassTag_ext(card_data, use_credit_key); + LED_B_ON(); - if (read_status == 0) continue; - if (read_status == 1) result_status = FLAG_ICLASS_READER_CSN; - if (read_status == 2) result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC; - - // handshakeIclass returns CSN|CC, but the actual block - // layout is CSN|CONFIG|CC, so here we reorder the data, - // moving CC forward 8 bytes - memcpy(card_data + 16, card_data + 8, 8); - - //Read block 1, config - if (flagReadConfig) { - if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, 10, 5)) { - result_status |= FLAG_ICLASS_READER_CONF; - memcpy(card_data + 8, resp, 8); - } else { - if (DBGLEVEL > 1) DbpString("Failed to dump config block"); - } - } - - //Read block 5, AIA - if (flagReadAIA) { - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, 10, 5)) { - result_status |= FLAG_ICLASS_READER_AIA; - memcpy(card_data + (8 * 5), resp, 8); - } else { - if (DBGLEVEL > 1) DbpString("Failed to dump AA block"); - } - } - - // 0 : CSN - // 1 : Configuration - // 2 : e-purse - // 3 : kd / debit / aa2 (write-only) - // 4 : kc / credit / aa1 (write-only) - // 5 : AIA, Application issuer area - // - //Then we can 'ship' back the 6 * 8 bytes of data, - // with 0xFF:s in block 3 and 4. - - LED_B_ON(); - //Send back to client, but don't bother if we already sent this - - // only useful if looping in arm (not try_once && not abort_after_read) - if (memcmp(last_csn, card_data, 8) != 0) { - // If caller requires that we get Conf, CC, AA, continue until we got it - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("STATUS %02X | CSN %c | CONF %c | CC %c | AIA %c | ONCE %c | 1TRY %c", - result_status, - (result_status & FLAG_ICLASS_READER_CSN) ? 'Y' : 'N', - (result_status & FLAG_ICLASS_READER_CONF) ? 'Y' : 'N', - (result_status & FLAG_ICLASS_READER_CC) ? 'Y' : 'N', - (result_status & FLAG_ICLASS_READER_AIA) ? 'Y' : 'N' - ); - Dbprintf(" aar %c | to %c, | uc %c | frc %c | fra %c | cc %c", - abort_after_read ? 'Y' : 'N', - try_once ? 'Y' : 'N', - use_credit_key ? 'Y' : 'N', - flagReadConfig ? 'Y' : 'N', - flagReadAIA ? 'Y' : 'N', - flagReadCC ? 'Y' : 'N' - ); - } - - bool send = (result_status & FLAG_ICLASS_READER_CSN); - if (flagReadCC) - send |= (result_status & FLAG_ICLASS_READER_CC); - if (flagReadAIA) - send |= (result_status & FLAG_ICLASS_READER_AIA); - if (flagReadConfig) - send |= (result_status & FLAG_ICLASS_READER_CONF); - - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SEND %c", send ? 'y' : 'n'); - - if (send) { - reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); - if (abort_after_read) { - LED_B_OFF(); - return; - } - //Save that we already sent this.... - memcpy(last_csn, card_data, 8); + //Send back to client, but don't bother if we already sent this - + // only useful if looping in arm (not try_once && not abort_after_read) + if (memcmp(last_csn, card_data, 8) != 0) { + + if (send) { + reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + if (abort_after_read) { + LED_B_OFF(); + return; } } LED_B_OFF(); - - if (checked == 1000) { - userCancelled = BUTTON_PRESS() || data_available(); - checked = 0; - } - ++checked; } if (userCancelled) { @@ -2272,8 +1071,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { uint8_t readcheck[] = { keytype, blockno }; uint8_t resp[] = {0, 0, 0, 0, 0, 0, 0, 0}; - size_t isOK = 0; - isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 6); + bool isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); switch_off(); } @@ -2399,13 +1197,13 @@ out: // Tries to read block. // retries 10times. -bool iClass_ReadBlock(uint8_t blockno, uint8_t *data, uint8_t len) { +static bool iClass_ReadBlock(uint8_t blockno, uint8_t *data) { uint8_t resp[10]; uint8_t cmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; AddCrc(cmd + 1, 1); - // expect size 10, retry 5times - bool isOK = sendCmdGetResponseWithRetries(cmd, sizeof(cmd), resp, 10, 5); - memcpy(data, resp, len); + uint32_t eof_time; + bool isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd), resp, sizeof(resp), 10, 10, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + memcpy(data, resp, 8); return isOK; } @@ -2417,33 +1215,32 @@ void iClass_ReadBlk(uint8_t blockno) { uint8_t blockdata[8]; } PACKED result; - result.isOK = iClass_ReadBlock(blockno, result.blockdata, sizeof(result.blockdata)); + LED_A_ON(); + result.isOK = iClass_ReadBlock(blockno, result.blockdata); switch_off(); reply_ng(CMD_HF_ICLASS_READBL, PM3_SUCCESS, (uint8_t *)&result, sizeof(result)); } // turn off afterwards void iClass_Dump(uint8_t blockno, uint8_t numblks) { - uint8_t blockdata[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - bool isOK = false; - uint8_t blkCnt = 0; - BigBuf_free(); - uint8_t *dataout = BigBuf_malloc(255 * 8); + uint8_t *dataout = BigBuf_malloc(0xFF * 8); if (dataout == NULL) { DbpString("[!] fail to allocate memory"); OnError(1); return; } - // fill mem with 0xFF - memset(dataout, 0xFF, 255 * 8); + memset(dataout, 0xFF, 0xFF * 8); + uint8_t blockdata[8] = {0}; + uint8_t blkCnt = 0; + bool isOK; for (; blkCnt < numblks; blkCnt++) { - isOK = iClass_ReadBlock(blockno + blkCnt, blockdata, sizeof(blockdata)); + isOK = iClass_ReadBlock(blockno + blkCnt, blockdata); // 0xBB is the internal debug separator byte.. if (!isOK || (blockdata[0] == 0xBB || blockdata[7] == 0xBB || blockdata[2] == 0xBB)) { //try again - isOK = iClass_ReadBlock(blockno + blkCnt, blockdata, sizeof(blockdata)); + isOK = iClass_ReadBlock(blockno + blkCnt, blockdata); if (!isOK) { Dbprintf("[!] block %02X failed to read", blkCnt + blockno); break; @@ -2459,15 +1256,42 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { } static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { - uint8_t resp[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t write[] = { 0x80 | ICLASS_CMD_UPDATE, blockno, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; memcpy(write + 2, data, 12); // data + mac AddCrc(write + 1, 13); - return sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 5); + + uint8_t resp[10] = {0}; + uint32_t eof_time = 0; + bool isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10, 3, 0, ICLASS_READER_TIMEOUT_UPDATE, &eof_time); + if (isOK == false) { + return false; + } + + uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + if (blockNo == 2) { + // check response. e-purse update swaps first and second half + if (memcmp(data+4, resp, 4) || memcmp(data, resp+4, 4)) { + return false; + } + } else if (blockNo == 3 || blockNo == 4) { + // check response. Key updates always return 0xffffffffffffffff + if (memcmp(all_ff, resp, 8)) { + return false; + } + } else { + // check response. All other updates return unchanged data + if (memcmp(data, resp, 8)) { + return false; + } + } + + return true; } // turn off afterwards void iClass_WriteBlock(uint8_t blockno, uint8_t *data) { + LED_A_ON(); uint8_t isOK = iClass_WriteBlock_ext(blockno, data); switch_off(); reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); @@ -2475,23 +1299,20 @@ void iClass_WriteBlock(uint8_t blockno, uint8_t *data) { // turn off afterwards void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { - int i, written = 0; - int total_block = (endblock - startblock) + 1; - for (i = 0; i < total_block; i++) { - // block number - if (iClass_WriteBlock_ext(startblock + i, data + (i * 12))) { - Dbprintf("Write block [%02x] successful", startblock + i); + LED_A_ON(); + uint16_t written = 0; + uint16_t total_blocks = (endblock - startblock) + 1; + for (uint8_t b = startblock; b < total_blocks; b++) { + + if (iClass_WriteBlock_ext(b, data + ((b - startblock) * 12))) { + Dbprintf("Write block [%02x] successful", b); written++; } else { - Dbprintf("Write block [%02x] failed", startblock + i); + Dbprintf("Write block [%02x] failed", b); } } switch_off(); - - uint8_t isOK = 0; - if (written == total_block) - isOK = 1; - + uint8_t isOK = (written == total_blocks) ? 1 : 0; reply_ng(CMD_HF_ICLASS_CLONE, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); } diff --git a/armsrc/iclass.h b/armsrc/iclass.h index a9edbdfed..6ce23ceb7 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -13,7 +13,7 @@ #include "common.h" -void RAMFUNC SniffIClass(void); +void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string); void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void ReaderIClass(uint8_t arg0); void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac); @@ -21,7 +21,6 @@ void iClass_Authentication(uint8_t *mac); void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain); void iClass_WriteBlock(uint8_t blockno, uint8_t *data); void iClass_ReadBlk(uint8_t blockno); -bool iClass_ReadBlock(uint8_t blockno, uint8_t *data, uint8_t len); void iClass_Dump(uint8_t blockno, uint8_t numblks); void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); void iClass_ReadCheck(uint8_t blockno, uint8_t keytype); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 4999c4d85..4448d3570 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Jonathan Westhues, split Nov 2006 +// piwi 2018 // // 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 @@ -24,20 +25,19 @@ #include "dbprint.h" #include "ticks.h" -#ifndef FWT_TIMEOUT_14B -// defaults to 2000ms -# define FWT_TIMEOUT_14B 35312 -#endif + #ifndef ISO14443B_DMA_BUFFER_SIZE -# define ISO14443B_DMA_BUFFER_SIZE 512 //changed this from 256 +# define ISO14443B_DMA_BUFFER_SIZE 128 #endif #ifndef RECEIVE_MASK # define RECEIVE_MASK (ISO14443B_DMA_BUFFER_SIZE-1) #endif +#define RECEIVE_SAMPLES_TIMEOUT 64 + // Guard Time (per 14443-2) #ifndef TR0 -# define TR0 32 //this value equals 8 ETU = 32 ssp clk (w/ 424 khz) +# define TR0 64 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA #endif // Synchronization time (per 14443-2) @@ -51,30 +51,161 @@ // 4sample #define SEND4STUFFBIT(x) ToSendStuffBit(x);ToSendStuffBit(x);ToSendStuffBit(x);ToSendStuffBit(x); -//#define SEND4STUFFBIT(x) ToSendStuffBit(x); -// iceman, this threshold value, what makes 8 a good amplitude for this IQ values? -#ifndef SUBCARRIER_DETECT_THRESHOLD -# define SUBCARRIER_DETECT_THRESHOLD 8 -#endif static void iso14b_set_timeout(uint32_t timeout); static void iso14b_set_maxframesize(uint16_t size); // the block number for the ISO14443-4 PCB (used with APDUs) static uint8_t pcb_blocknum = 0; -static uint32_t iso14b_timeout = FWT_TIMEOUT_14B; +static uint32_t iso14b_timeout = TR0; + + +/* ISO 14443 B +* +* Reader to card | ASK - Amplitude Shift Keying Modulation (PCD to PICC for Type B) (NRZ-L encodig) +* Card to reader | BPSK - Binary Phase Shift Keying Modulation, (PICC to PCD for Type B) +* +* fc - carrier frequency 13.56 MHz +* TR0 - Guard Time per 14443-2 +* TR1 - Synchronization Time per 14443-2 +* TR2 - PICC to PCD Frame Delay Time (per 14443-3 Amendment 1) +* +* Elementary Time Unit (ETU) is +* - 128 Carrier Cycles (9.4395 µS) = 8 Subcarrier Units +* - 1 ETU = 1 bit +* - 10 ETU = 1 startbit, 8 databits, 1 stopbit (10bits length) +* - startbit is a 0 +* - stopbit is a 1 +* +* Start of frame (SOF) is +* - [10-11] ETU of ZEROS, unmodulated time +* - [2-3] ETU of ONES, +* +* End of frame (EOF) is +* - [10-11] ETU of ZEROS, unmodulated time +* +* -TO VERIFY THIS BELOW- +* The mode FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK which we use to simulate tag +* works like this: +* - A 1-bit input to the FPGA becomes 8 pulses at 847.5kHz (1.18µS / pulse) == 9.44us +* - A 0-bit input to the FPGA becomes an unmodulated time of 1.18µS or does it become 8 nonpulses for 9.44us +* +* FPGA doesn't seem to work with ETU. It seems to work with pulse / duration instead. +* +* Card sends data ub 847.e kHz subcarrier +* subcar |duration| FC division +* -------+--------+------------ +* 106kHz | 9.44µS | FC/128 +* 212kHz | 4.72µS | FC/64 +* 424kHz | 2.36µS | FC/32 +* 848kHz | 1.18µS | FC/16 +* -------+--------+------------ +* +* Reader data transmission: +* - no modulation ONES +* - SOF +* - Command, data and CRC_B +* - EOF +* - no modulation ONES +* +* Card data transmission +* - TR1 +* - SOF +* - data (each bytes is: 1startbit, 8bits, 1stopbit) +* - CRC_B +* - EOF +* +* FPGA implementation : +* At this point only Type A is implemented. This means that we are using a +* bit rate of 106 kbit/s, or fc/128. Oversample by 4, which ought to make +* things practical for the ARM (fc/32, 423.8 kbits/s, ~50 kbytes/s) +* +*/ + + //============================================================================= // An ISO 14443 Type B tag. We listen for commands from the reader, using -// a kind of thing that's implemented in software. When we get a +// 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 loop is TR1, per specification + // TR1 minimum must be > 80/fs + // TR1 maximum 200/fs + // 80/fs < TR1 < 200/fs + // 10 ETU < TR1 < 24 ETU + + // Send TR1. + // 10-11 ETU * 4times samples ONES + for (i = 0; i < 20; i++) { + SEND4STUFFBIT(1); + } + + // Send SOF. + // 10-11 ETU * 4times samples ZEROS + for (i = 0; i < 10; i++) { + SEND4STUFFBIT(0); + } + + // 2-3 ETU * 4times samples ONES + for (i = 0; i < 2; i++) { + SEND4STUFFBIT(1); + } + + // data + for (i = 0; i < len; i++) { + + // Start bit + SEND4STUFFBIT(0); + + // Data bits + uint8_t b = cmd[i]; + for (int j = 0; j < 8; j++) { + SEND4STUFFBIT(b & 1); + b >>= 1; + } + + // Stop bit + SEND4STUFFBIT(1); + + // Extra Guard bit + // For PICC it ranges 0-18us (1etu = 9us) + //SEND4STUFFBIT(1); + } + + // Send EOF. + // 10-11 ETU * 4 sample rate = ZEROS + for(i = 0; i < 10; i++) { + SEND4STUFFBIT(0); + } + + // why this? + for(i = 0; i < 2; i++) { + SEND4STUFFBIT(1); + } + + // Convert from last byte pos to length + ToSendMax++; +} //----------------------------------------------------------------------------- -// The software that receives commands from the reader, and its state variables. +// The software UART that receives commands from the reader, and its state +// variables. //----------------------------------------------------------------------------- static struct { enum { @@ -103,7 +234,6 @@ static void Uart14bReset(void) { static void Uart14bInit(uint8_t *data) { Uart.output = data; Uart14bReset(); -// memset(Uart.output, 0x00, MAX_FRAME_SIZE); } //----------------------------------------------------------------------------- @@ -121,10 +251,6 @@ static struct { uint16_t 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; uint16_t len; @@ -150,7 +276,6 @@ static void Demod14bReset(void) { static void Demod14bInit(uint8_t *data) { Demod.output = data; Demod14bReset(); - // memset(Demod.output, 0x00, MAX_FRAME_SIZE); } @@ -175,6 +300,7 @@ static void iso14b_set_timeout(uint32_t timeout) { iso14b_timeout = timeout; if (DBGLEVEL >= 3) Dbprintf("ISO14443B Timeout set to %ld fwt", iso14b_timeout); } + static void iso14b_set_maxframesize(uint16_t size) { if (size > 256) size = MAX_FRAME_SIZE; @@ -183,142 +309,6 @@ static void iso14b_set_maxframesize(uint16_t size) { if (DBGLEVEL >= 3) Dbprintf("ISO14443B Max frame size set to %d bytes", Uart.byteCntMax); } -//----------------------------------------------------------------------------- -// 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) { - /* ISO 14443 B - * - * Reader to card | ASK - Amplitude Shift Keying Modulation (PCD to PICC for Type B) (NRZ-L encodig) - * Card to reader | BPSK - Binary Phase Shift Keying Modulation, (PICC to PCD for Type B) - * - * fc - carrier frequency 13.56 MHz - * TR0 - Guard Time per 14443-2 - * TR1 - Synchronization Time per 14443-2 - * TR2 - PICC to PCD Frame Delay Time (per 14443-3 Amendment 1) - * - * Elementary Time Unit (ETU) is - * - 128 Carrier Cycles (9.4395 µS) = 8 Subcarrier Units - * - 1 ETU = 1 bit - * - 10 ETU = 1 startbit, 8 databits, 1 stopbit (10bits length) - * - startbit is a 0 - * - stopbit is a 1 - * - * Start of frame (SOF) is - * - [10-11] ETU of ZEROS, unmodulated time - * - [2-3] ETU of ONES, - * - * End of frame (EOF) is - * - [10-11] ETU of ZEROS, unmodulated time - * - * -TO VERIFY THIS BELOW- - * The mode FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK which we use to simulate tag - * works like this: - * - A 1-bit input to the FPGA becomes 8 pulses at 847.5kHz (1.18µS / pulse) == 9.44us - * - A 0-bit input to the FPGA becomes an unmodulated time of 1.18µS or does it become 8 nonpulses for 9.44us - * - * FPGA doesn't seem to work with ETU. It seems to work with pulse / duration instead. - * - * Card sends data ub 847.e kHz subcarrier - * subcar |duration| FC division - * -------+--------+------------ - * 106kHz | 9.44µS | FC/128 - * 212kHz | 4.72µS | FC/64 - * 424kHz | 2.36µS | FC/32 - * 848kHz | 1.18µS | FC/16 - * -------+--------+------------ - * - * Reader data transmission: - * - no modulation ONES - * - SOF - * - Command, data and CRC_B - * - EOF - * - no modulation ONES - * - * Card data transmission - * - TR1 - * - SOF - * - data (each bytes is: 1startbit, 8bits, 1stopbit) - * - CRC_B - * - EOF - * - * FPGA implementation : - * At this point only Type A is implemented. This means that we are using a - * bit rate of 106 kbit/s, or fc/128. Oversample by 4, which ought to make - * things practical for the ARM (fc/32, 423.8 kbits/s, ~50 kbytes/s) - * - */ - - ToSendReset(); - - // Transmit a burst of ones, as the initial thing that lets the - // reader get phase sync. - // This loop is TR1, per specification - // TR1 minimum must be > 80/fs - // TR1 maximum 200/fs - // 80/fs < TR1 < 200/fs - // 10 ETU < TR1 < 24 ETU - - // Send TR1. - // 10-11 ETU * 4times samples ONES - for (int i = 0; i < 10; i++) { SEND4STUFFBIT(1); } - - // Send SOF. - // 10-11 ETU * 4times samples ZEROS - for (int i = 0; i < 10; i++) { SEND4STUFFBIT(0); } - //for(i = 0; i < 10; i++) { ToSendStuffBit(0); } - - // 2-3 ETU * 4times samples ONES - for (int i = 0; i < 3; i++) { SEND4STUFFBIT(1); } - //for(i = 0; i < 3; i++) { ToSendStuffBit(1); } - - // data - for (int i = 0; i < len; ++i) { - - // Start bit - SEND4STUFFBIT(0); - //ToSendStuffBit(0); - - // Data bits - uint8_t b = cmd[i]; - for (int j = 0; j < 8; ++j) { - // if(b & 1) { - // SEND4STUFFBIT(1); - // //ToSendStuffBit(1); - // } else { - // SEND4STUFFBIT(0); - // //ToSendStuffBit(0); - // } - SEND4STUFFBIT(b & 1); - b >>= 1; - } - - // Stop bit - SEND4STUFFBIT(1); - //ToSendStuffBit(1); - - // Extra Guard bit - // For PICC it ranges 0-18us (1etu = 9us) - SEND4STUFFBIT(1); - //ToSendStuffBit(1); - } - - // Send EOF. - // 10-11 ETU * 4 sample rate = ZEROS - for (int i = 0; i < 10; i++) { SEND4STUFFBIT(0); } - //for(i = 0; i < 10; i++) { ToSendStuffBit(0); } - - // why this? - for (int i = 0; i < 2; i++) { SEND4STUFFBIT(1); } - //for(i = 0; i < 40; i++) { ToSendStuffBit(1); } - - // Convert from last byte pos to length - ++ToSendMax; -} - - /* Receive & handle a bit coming from the reader. * * This function is called 4 times per bit (every 2 subcarrier cycles). @@ -454,42 +444,16 @@ static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) { LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); - StartCountSspClk(); - - volatile uint8_t b; - - // clear receiving shift register and holding register - // What does this loop do? Is it TR1? - // loop is a wait/delay ? - /* - for(uint8_t c = 0; c < 10;) { - - // keep tx buffer in a defined state anyway. - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xFF; - ++c; - } - } - */ // Now run a `software UART' on the stream of incoming samples. Uart14bInit(received); - uint8_t mask; - while (!BUTTON_PRESS()) { + while (BUTTON_PRESS() == false) { WDT_HIT(); - // keep tx buffer in a defined state anyway. - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; - } - - // Wait for byte be become available in rx holding register - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - - b = (uint8_t) AT91C_BASE_SSC->SSC_RHR; - - for (mask = 0x80; mask != 0; mask >>= 1) { - if (Handle14443bReaderUartBit(b & mask)) { + 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 (Handle14443bReaderUartBit(b & mask)) { *len = Uart.byteCnt; return true; } @@ -499,57 +463,16 @@ static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) { return false; } -void ClearFpgaShiftingRegisters(void) { - - volatile uint8_t b; - - // clear receiving shift register and holding register - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) {}; - - b = AT91C_BASE_SSC->SSC_RHR; - (void) b; - - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) {}; - - b = AT91C_BASE_SSC->SSC_RHR; - (void) b; - - // wait for the FPGA to signal fdt_indicator == 1 (the FPGA is ready to queue new data in its delay line) - for (uint8_t j = 0; j < 5; j++) { // allow timeout - better late than never - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) {}; - if (AT91C_BASE_SSC->SSC_RHR) break; - } - - // Clear TXRDY: - //AT91C_BASE_SSC->SSC_THR = 0xFF; -} - -void WaitForFpgaDelayQueueIsEmpty(uint16_t delay) { - // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again: - uint8_t fpga_queued_bits = delay >> 3; // twich /8 ?? >>3, - for (uint8_t i = 0; i <= fpga_queued_bits / 8 + 1;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xFF; - i++; - } - } -} static void TransmitFor14443b_AsTag(uint8_t *response, uint16_t len) { - volatile uint32_t b; - // Signal field is off with the appropriate LED LED_D_OFF(); - //uint16_t fpgasendQueueDelay = 0; // Modulate BPSK FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); - SpinDelay(40); - - ClearFpgaShiftingRegisters(); - - FpgaSetupSsc(); + AT91C_BASE_SSC->SSC_THR = 0xFF; + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); // Transmit the response. for (uint16_t i = 0; i < len;) { @@ -561,13 +484,10 @@ static void TransmitFor14443b_AsTag(uint8_t *response, uint16_t len) { // Prevent rx holding register from overflowing if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = AT91C_BASE_SSC->SSC_RHR; + volatile uint32_t b = AT91C_BASE_SSC->SSC_RHR; (void)b; } } - - //WaitForFpgaDelayQueueIsEmpty(fpgasendQueueDelay); - AT91C_BASE_SSC->SSC_THR = 0xFF; } //----------------------------------------------------------------------------- // Main loop of simulated tag: receive commands from reader, decide what @@ -575,41 +495,26 @@ static void TransmitFor14443b_AsTag(uint8_t *response, uint16_t len) { //----------------------------------------------------------------------------- void SimulateIso14443bTag(uint32_t pupi) { - // setup device. - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Set up the synchronous serial port - FpgaSetupSsc(); - - // allocate command receive buffer - BigBuf_free(); - BigBuf_Clear_ext(false); - - clear_trace(); //sim - set_tracing(true); - - uint16_t len, cmdsReceived = 0; - int cardSTATE = SIM_NOFIELD; - int vHf = 0; // in mV - // uint32_t time_0 = 0; - // uint32_t t2r_time = 0; - // uint32_t r2t_time = 0; - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - - // the only commands we understand is WUPB, AFI=0, Select All, N=1: -// static const uint8_t cmdWUPB[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; // WUPB - // ... and REQB, AFI=0, Normal Request, N=1: -// static const uint8_t cmdREQB[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xFF }; // REQB - // ... and ATTRIB -// static const uint8_t cmdATTRIB[] = { ISO14443B_ATTRIB, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // ATTRIB + LED_A_ON(); + // the only commands we understand is WUPB, AFI=0, Select All, N=1: +// static const uint8_t cmdWUPB[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; // WUPB + // ... and REQB, AFI=0, Normal Request, N=1: +// static const uint8_t cmdREQB[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xFF }; // REQB + // ... and HLTB +// static const uint8_t cmdHLTB[] = { 0x50, 0xff, 0xff, 0xff, 0xff }; // HLTB + // ... and ATTRIB +// static const uint8_t cmdATTRIB[] = { ISO14443B_ATTRIB, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // ATTRIB // ... if not PUPI/UID is supplied 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: - uint8_t respATQB[] = { 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, - 0x22, 0x00, 0x21, 0x85, 0x5e, 0xd7 - }; + uint8_t respATQB[] = { + 0x50, + 0x82, 0x0d, 0xe1, 0x74, + 0x20, 0x38, 0x19, + 0x22, 0x00, 0x21, 0x85, + 0x5e, 0xd7 + }; // response to HLTB and ATTRIB static const uint8_t respOK[] = {0x00, 0x78, 0xF0}; @@ -619,6 +524,26 @@ void SimulateIso14443bTag(uint32_t pupi) { num_to_bytes(pupi, 4, respATQB + 1); AddCrc14B(respATQB, 12); } + + // setup device. + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Set up the synchronous serial port + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); + + // allocate command receive buffer + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); + + uint16_t len, cmdsReceived = 0; + int cardSTATE = SIM_NOFIELD; + int vHf = 0; // in mV + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); // prepare "ATQB" tag answer (encoded): CodeIso14443bAsTag(respATQB, sizeof(respATQB)); @@ -663,7 +588,7 @@ void SimulateIso14443bTag(uint32_t pupi) { // WUP in HALTED state if (len == 5) { if ((receivedCmd[0] == ISO14443B_REQB && (receivedCmd[2] & 0x8) == 0x8 && cardSTATE == SIM_HALTED) || - receivedCmd[0] == ISO14443B_REQB) { + receivedCmd[0] == ISO14443B_REQB) { LogTrace(receivedCmd, len, 0, 0, NULL, true); cardSTATE = SIM_SELECTING; } @@ -714,15 +639,21 @@ void SimulateIso14443bTag(uint32_t pupi) { // - SLOT MARKER // - ISO7816 // - emulate with a memory dump - Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived); + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived); // CRC Check if (len >= 3) { // if crc exists - if (!check_crc(CRC_14443_B, receivedCmd, len)) - DbpString("+++CRC fail"); - else - DbpString("CRC passes"); + if (!check_crc(CRC_14443_B, receivedCmd, len)) { + if (DBGLEVEL >= DBG_DEBUG) { + DbpString("CRC fail"); + } + } + } else { + if (DBGLEVEL >= DBG_DEBUG) { + DbpString("CRC passed"); + } } cardSTATE = SIM_IDLE; } @@ -734,9 +665,11 @@ void SimulateIso14443bTag(uint32_t pupi) { ++cmdsReceived; } - if (DBGLEVEL >= 2) + + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen()); - switch_off(); //simulate + + switch_off(); //simulate } //============================================================================= @@ -780,37 +713,8 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(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_old(void) { \ - 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); \ - } \ - } \ - } \ - } + +#define SUBCARRIER_DETECT_THRESHOLD 8 //note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow #define CHECK_FOR_SUBCARRIER(void) { v = MAX(myI, myQ) + (MIN(myI, myQ) >> 1); } @@ -859,7 +763,9 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { Demod.posCount = 0; // start of SOF sequence } else { // maximum length of TR1 = 200 1/fs - if (Demod.posCount > 200 / 4) Demod.state = DEMOD_UNSYNCD; + if (Demod.posCount > 200 / 4){ + Demod.state = DEMOD_UNSYNCD; + } } Demod.posCount++; break; @@ -877,6 +783,7 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { LED_C_ON(); // Got SOF Demod.state = DEMOD_AWAITING_START_BIT; Demod.posCount = 0; + Demod.bitCount = 0; Demod.len = 0; } } else { @@ -895,8 +802,12 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { if (v > 0) { if (Demod.posCount > 6 * 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(); + LED_C_OFF(); + if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass + return true; + } else { + Demod.state = DEMOD_UNSYNCD; + } } } else { // start bit detected Demod.bitCount = 0; @@ -932,11 +843,12 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { uint16_t s = Demod.shiftReg; // stop bit == '1', start bit == '0' - if ((s & 0x200) && (s & 0x001) == 0) { + if ((s & 0x200) && ((s & 0x001) == 0)) { // left shift to drop the startbit uint8_t b = (s >> 1); Demod.output[Demod.len] = b; - ++Demod.len; + Demod.len++; + Demod.bitCount = 0; Demod.state = DEMOD_AWAITING_START_BIT; } else { // this one is a bit hard, either its a correc byte or its unsynced. @@ -964,99 +876,114 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { * Demodulate the samples we received from the tag, also log to tracebuffer * quiet: set to 'TRUE' to disable debug output */ -static void GetTagSamplesFor14443bDemod(void) { - bool finished = false; -// int lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; +static int GetTagSamplesFor14443bDemod(int timeout) { + int ret = 0; + int maxBehindBy = 0; + int lastRxCounter, samples = 0; + int8_t ci, cq; uint32_t time_0 = 0, time_stop = 0; 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 + uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); // Set up the demodulator for tag -> reader responses. - Demod14bInit(BigBuf_malloc(MAX_FRAME_SIZE)); + Demod14bInit(receivedResponse); - // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t *) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); - int8_t *upTo = dmaBuf; + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) // Setup and start DMA. - if (!FpgaSetupSscDma((uint8_t *) dmaBuf, ISO14443B_DMA_BUFFER_SIZE)) { + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + if (FpgaSetupSscDma((uint8_t *) dmaBuf, ISO14443B_DMA_BUFFER_SIZE) == false) { if (DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); - return; + return -1; } + uint16_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); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); - // get current clock - time_0 = GetCountSspClk(); + for(;;) { + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1); + if (behindBy > maxBehindBy) { + maxBehindBy = behindBy; + } - // rx counter - dma counter? (how much?) & (mod) mask > 2. (since 2bytes at the time is read) - while (!finished) { + if (behindBy < 1) continue; - LED_A_INV(); - WDT_HIT(); + ci = *upTo >> 8; + cq = *upTo; + upTo++; + lastRxCounter--; + if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; + } - // LSB is a fpga signal bit. - int ci = upTo[0]; - int cq = upTo[1]; - upTo += 2; -// lastRxCounter -= 2; + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers + } + samples++; - // restart DMA buffer to receive again. - if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { - upTo = dmaBuf; -// lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; - } + if (Handle14443bTagSamplesDemod(ci, cq)) { + ret = Demod.len; + break; + } - // https://github.com/Proxmark/proxmark3/issues/103 - bool gotFrame = Handle14443bTagSamplesDemod(ci, cq); - time_stop = GetCountSspClk() - time_0; - - finished = (time_stop > iso14b_timeout || gotFrame); + if(samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) { + ret = -1; + LED_C_OFF(); + break; + } } FpgaDisableSscDma(); - if (upTo) - upTo = NULL; + if (ret < 0) { + return ret; + } - if (Demod.len > 0) - LogTrace(Demod.output, Demod.len, time_0, time_stop, NULL, false); + if (Demod.len > 0) { + LogTrace(Demod.output, Demod.len, time_0, time_stop, NULL, false); + } + + return ret; } //----------------------------------------------------------------------------- // Transmit the command (to the tag) that was placed in ToSend[]. //----------------------------------------------------------------------------- static void TransmitFor14443b_AsReader(void) { - int c; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); - SpinDelay(60); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); - // What does this loop do? Is it TR1? - // 0xFF = 8 bits of 1. 1 bit == 1Etu,.. - // loop 10 * 8 = 80 ETU of delay, with a non modulated signal. why? - // 80*9 = 720us. + LED_B_ON(); - for (c = 0; c < 50;) { + for (int c = 0; c < ToSendMax; c++) { + uint8_t data = ToSend[c]; + for (int i = 0; i < 8; i++) { + uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; + + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + + AT91C_BASE_SSC->SSC_THR = send_word; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xFF; - c++; - } + data <<= 1; + } + WDT_HIT(); } - - // Send frame loop - for (c = 0; c < ToSendMax;) { - - // Put byte into tx holding register as soon as it is ready - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ToSend[c++]; - } - } - WDT_HIT(); + LED_B_OFF(); } //----------------------------------------------------------------------------- @@ -1083,28 +1010,21 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { // Send SOF // 10-11 ETUs of ZERO - for (int i = 0; i < 10; ++i) ToSendStuffBit(0); + for (int i = 0; i < 10; i++) + ToSendStuffBit(0); + // 2-3 ETUs of ONE ToSendStuffBit(1); ToSendStuffBit(1); -// ToSendStuffBit(1); // Sending cmd, LSB // from here we add BITS - for (int i = 0; i < len; ++i) { + for (int i = 0; i < len; i++) { // Start bit ToSendStuffBit(0); // Data bits uint8_t b = cmd[i]; - // if ( b & 1 ) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>1) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>2) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>3) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>4) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>5) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>6) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>7) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); ToSendStuffBit(b & 1); ToSendStuffBit((b >> 1) & 1); @@ -1119,20 +1039,24 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { ToSendStuffBit(1); // EGT extra guard time // For PCD it ranges 0-57us (1etu = 9us) - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); +// ToSendStuffBit(1); +// ToSendStuffBit(1); +// ToSendStuffBit(1); } // Send EOF // 10-11 ETUs of ZERO - for (int i = 0; i < 10; ++i) ToSendStuffBit(0); + for (int i = 0; i < 10; i++) + ToSendStuffBit(0); // Transition time. TR0 - guard time // 8ETUS minum? // Per specification, Subcarrier must be stopped no later than 2 ETUs after EOF. // I'm guessing this is for the FPGA to be able to send all bits before we switch to listening mode - for (int i = 0; i < 24 ; ++i) ToSendStuffBit(1); + + // ensure that last byte is filled up + for (int i = 0; i < 8 ; ++i) + ToSendStuffBit(1); // TR1 - Synchronization time // Convert from last character reference to length @@ -1147,11 +1071,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) { uint32_t time_start = GetCountSspClk(); CodeIso14443bAsReader(cmd, len); - TransmitFor14443b_AsReader(); - - if (g_trigger) LED_A_ON(); - LogTrace(cmd, len, time_start, GetCountSspClk(), NULL, true); } @@ -1159,7 +1079,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) { * TODO: check CRC and preamble */ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) { - + LED_A_ON(); uint8_t message_frame[message_length + 4]; // PCB message_frame[0] = 0x0A | pcb_blocknum; @@ -1171,18 +1091,20 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r // EDC (CRC) AddCrc14B(message_frame, message_length + 2); // send - CodeAndTransmit14443bAsReader(message_frame, message_length + 4); //no + CodeAndTransmit14443bAsReader(message_frame, message_length + 4); // get response - GetTagSamplesFor14443bDemod(); //no + int ret = GetTagSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT); FpgaDisableTracing(); - if (Demod.len < 3) - return 0; + if (ret < 3) { + LED_A_OFF(); + return 0; + } // VALIDATE CRC if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) { - if (DBGLEVEL > 3) Dbprintf("crc fail ICE"); + if (DBGLEVEL > 3) DbpString("CRC fail"); return 0; } // copy response contents @@ -1190,6 +1112,7 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r memcpy(response, Demod.output, Demod.len); return Demod.len; + LED_A_OFF(); } /** @@ -1202,12 +1125,14 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { uint8_t select_srx[] = { ISO14443B_SELECT, 0x00, 0x00, 0x00}; CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx)); - GetTagSamplesFor14443bDemod(); //no + int ret = GetTagSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT); FpgaDisableTracing(); - if (Demod.len == 0) + if (Demod.len == 0 || ret < 0) return 2; + Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x [%02x %02x]", Demod.output[0], Demod.output[1], Demod.output[2]); + // Randomly generated Chip ID if (card) card->chipid = Demod.output[0]; @@ -1216,10 +1141,10 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { AddCrc14B(select_srx, 2); CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx)); - GetTagSamplesFor14443bDemod(); //no + ret = GetTagSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT); FpgaDisableTracing(); - if (Demod.len != 3) + if (Demod.len != 3 || ret < 0) return 2; // Check the CRC of the answer: @@ -1235,10 +1160,10 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { AddCrc14B(select_srx, 1); CodeAndTransmit14443bAsReader(select_srx, 3); // Only first three bytes for this one - GetTagSamplesFor14443bDemod(); //no + ret = GetTagSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT); FpgaDisableTracing(); - if (Demod.len != 10) + if (Demod.len != 10 || ret < 0) return 2; // The check the CRC of the answer @@ -1258,7 +1183,7 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { * TODO: Support multiple cards (perform anticollision) * TODO: Verify CRC checksums */ -uint8_t iso14443b_select_card(iso14b_card_select_t *card) { +int iso14443b_select_card(iso14b_card_select_t *card) { // WUPB command (including CRC) // Note: WUPB wakes up all tags, REQB doesn't wake up tags in HALT state static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; @@ -1267,16 +1192,16 @@ uint8_t iso14443b_select_card(iso14b_card_select_t *card) { // first, wake up the tag CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); - GetTagSamplesFor14443bDemod(); //select_card + int ret = GetTagSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT); FpgaDisableTracing(); // ATQB too short? - if (Demod.len < 14) - return 2; + if (ret < 14) + return -1; // VALIDATE CRC if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) - return 3; + return -2; if (card) { card->uidlen = 4; @@ -1292,16 +1217,16 @@ uint8_t iso14443b_select_card(iso14b_card_select_t *card) { AddCrc14B(attrib, 9); CodeAndTransmit14443bAsReader(attrib, sizeof(attrib)); - GetTagSamplesFor14443bDemod();//select_card + ret = GetTagSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT); FpgaDisableTracing(); // Answer to ATTRIB too short? - if (Demod.len < 3) - return 2; + if (ret < 3) + return -1; // VALIDATE CRC if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) - return 3; + return -2; if (card) { @@ -1344,10 +1269,10 @@ void iso14443b_setup(void) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Set up the synchronous serial port - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // Signal field is on with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); SpinDelay(100); // Start the timer @@ -1369,21 +1294,22 @@ static bool ReadSTBlock(uint8_t block) { uint8_t cmd[] = {ISO14443B_READ_BLK, block, 0x00, 0x00}; AddCrc14B(cmd, 2); CodeAndTransmit14443bAsReader(cmd, sizeof(cmd)); - GetTagSamplesFor14443bDemod(); + int res = GetTagSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT); FpgaDisableTracing(); // Check if we got an answer from the tag - if (Demod.len != 6) { + if (Demod.len != 6 || res < 0) { DbpString("[!] expected 6 bytes from tag, got less..."); return false; } // The check the CRC of the answer if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) { - DbpString("[!] CRC Error block!"); + DbpString("CRC fail"); return false; } return true; } + void ReadSTMemoryIso14443b(uint8_t numofblocks) { // Make sure that we start from off, since the tags are stateful; // confusing things will happen if we don't reset them between reads. @@ -1427,6 +1353,9 @@ void ReadSTMemoryIso14443b(uint8_t numofblocks) { if (i == 0xff) break; ++i; } + + // Todo: iceman: send back read data to client. + // reply_ng(..., ); out: switch_off(); // disconnect raw @@ -1459,10 +1388,10 @@ static void iso1444b_setup_sniff(void) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup for the DMA. - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // Set 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); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_SNIFF_IQ); SpinDelay(20); // Start the SSP timer @@ -1497,10 +1426,17 @@ void RAMFUNC SniffIso14443b(void) { bool ReaderIsActive = false; iso1444b_setup_sniff(); - + // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t *) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); - int8_t *data = dmaBuf; + uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); + uint16_t *upTo = dmaBuf; + int lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + int8_t 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; // Setup and start DMA. if (!FpgaSetupSscDma((uint8_t *) dmaBuf, ISO14443B_DMA_BUFFER_SIZE)) { @@ -1513,25 +1449,48 @@ void RAMFUNC SniffIso14443b(void) { time_0 = GetCountSspClk(); // loop and listen - while (!BUTTON_PRESS()) { - WDT_HIT(); + for(;;) { - int ci = data[0]; - int cq = data[1]; - data += 2; + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE - 1); + if (behindBy > maxBehindBy) { + maxBehindBy = behindBy; + } - if (data >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { - data = dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; - } + if (behindBy < 1) continue; + + ci = *upTo >> 8; + cq = *upTo; + upTo++; + lastRxCounter--; + if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning again + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; + if (behindBy > (9 * ISO14443B_DMA_BUFFER_SIZE / 10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + break; + } + } + + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers + + WDT_HIT(); + if (BUTTON_PRESS()) { + DbpString("Button pressed, cancelled"); + break; + } + } + + samples++; // no need to try decoding reader data if the tag is sending - if (!TagIsActive) { + if (TagIsActive == false) { LED_A_INV(); if (Handle14443bReaderUartBit(ci & 0x01)) { + time_stop = GetCountSspClk() - time_0; LogTrace(Uart.output, Uart.byteCnt, time_start, time_stop, NULL, true); Uart14bReset(); @@ -1556,7 +1515,7 @@ void RAMFUNC SniffIso14443b(void) { // is this | 0x01 the error? & 0xfe in https://github.com/Proxmark/proxmark3/issues/103 // LSB is a fpga signal bit. - if (Handle14443bTagSamplesDemod(ci, cq)) { + if (Handle14443bTagSamplesDemod(ci/2, cq/2) >= 0) { time_stop = GetCountSspClk() - time_0; LogTrace(Demod.output, Demod.len, time_start, time_stop, NULL, false); Uart14bReset(); @@ -1568,6 +1527,7 @@ void RAMFUNC SniffIso14443b(void) { } } + FpgaDisableSscDma(); if (DBGLEVEL >= 2) { DbpString("[+] Sniff statistics:"); Dbprintf("[+] uart State: %x ByteCount: %i ByteCountMax: %i", Uart.state, Uart.byteCnt, Uart.byteCntMax); @@ -1593,12 +1553,14 @@ static void iso14b_set_trigger(bool enable) { * */ void SendRawCommand14443B_Ex(PacketCommandNG *c) { + iso14b_command_t param = c->oldarg[0]; size_t len = c->oldarg[1] & 0xffff; uint32_t timeout = c->oldarg[2]; uint8_t *cmd = c->data.asBytes; - uint8_t status; + int status; uint32_t sendlen = sizeof(iso14b_card_select_t); + uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00}; if (DBGLEVEL > 3) Dbprintf("14b raw: param, %04x", param); @@ -1620,22 +1582,22 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { iso14b_card_select_t *card = (iso14b_card_select_t *)buf; status = iso14443b_select_card(card); - reply_mix(CMD_ACK, status, sendlen, 0, buf, sendlen); - // 0: OK 2: attrib fail, 3:crc fail, - if (status > 0) goto out; + reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, buf, sendlen); + // 0: OK -1: attrib fail, -2:crc fail, + if (status != 0) goto out; } if ((param & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) { iso14b_card_select_t *card = (iso14b_card_select_t *)buf; status = iso14443b_select_srx_card(card); - reply_mix(CMD_ACK, status, sendlen, 0, buf, sendlen); + reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, buf, sendlen); // 0: OK 2: demod fail, 3:crc fail, if (status > 0) goto out; } if ((param & ISO14B_APDU) == ISO14B_APDU) { status = iso14443b_apdu(cmd, len, buf); - reply_mix(CMD_ACK, status, status, 0, buf, status); + reply_mix(CMD_HF_ISO14443B_COMMAND, status, status, 0, buf, status); } if ((param & ISO14B_RAW) == ISO14B_RAW) { @@ -1645,12 +1607,11 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { } CodeAndTransmit14443bAsReader(cmd, len); // raw - GetTagSamplesFor14443bDemod(); // raw + status = GetTagSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT); // raw FpgaDisableTracing(); sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); - status = (Demod.len > 0) ? 0 : 1; - reply_old(CMD_ACK, status, sendlen, 0, Demod.output, sendlen); + reply_old(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen); } out: diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h index 62dbd6590..0013ad313 100644 --- a/armsrc/iso14443b.h +++ b/armsrc/iso14443b.h @@ -28,7 +28,7 @@ void iso14443b_setup(void); uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response); -uint8_t iso14443b_select_card(iso14b_card_select_t *card); +int iso14443b_select_card(iso14b_card_select_t *card); uint8_t iso14443b_select_card_srx(iso14b_card_select_t *card); void SimulateIso14443bTag(uint32_t pupi); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index a82bb9a07..51dc7fac8 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -76,7 +76,7 @@ #define DELAY_ARM_TO_TAG 16 #define DELAY_TAG_TO_ARM 32 -//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when snooping. All values should be multiples of 16 +//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when sniffing. All values should be multiples of 16 #define DELAY_TAG_TO_ARM_SNIFF 32 #define DELAY_READER_TO_ARM_SNIFF 32 @@ -122,7 +122,7 @@ static void BuildInventoryResponse(uint8_t *uid); // resulting data rate is 26.48 kbit/s (fc/512) // cmd ... data // n ... length of data -static void CodeIso15693AsReader(uint8_t *cmd, int n) { +void CodeIso15693AsReader(uint8_t *cmd, int n) { ToSendReset(); @@ -195,7 +195,7 @@ static void CodeIso15693AsReader256(uint8_t *cmd, int n) { static const uint8_t encode_4bits[16] = { 0xaa, 0x6a, 0x9a, 0x5a, 0xa6, 0x66, 0x96, 0x56, 0xa9, 0x69, 0x99, 0x59, 0xa5, 0x65, 0x95, 0x55 }; -static void CodeIso15693AsTag(uint8_t *cmd, size_t len) { +void CodeIso15693AsTag(uint8_t *cmd, size_t len) { /* * SOF comprises 3 parts; * * An unmodulated time of 56.64 us @@ -241,7 +241,7 @@ static void CodeIso15693AsTag(uint8_t *cmd, size_t len) { } // Transmit the command (to the tag) that was placed in cmd[]. -static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { +void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); @@ -279,7 +279,7 @@ static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time //----------------------------------------------------------------------------- // Transmit the command (to the reader) that was placed in cmd[]. //----------------------------------------------------------------------------- -static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow) { +void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow) { // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); @@ -617,7 +617,7 @@ static void DecodeTagReset(DecodeTag_t *DecodeTag) { /* * Receive and decode the tag response, also log to tracebuffer */ -static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { +int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { int samples = 0; int ret = 0; @@ -966,7 +966,7 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR DecodeReader->posCount++; if (DecodeReader->Coding == CODING_1_OUT_OF_4) { if (DecodeReader->posCount == 7*16) { // 7 bits jammed - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); // stop jamming + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming // FpgaDisableTracing(); LED_D_OFF(); } else if (DecodeReader->posCount == 8*16) { @@ -976,7 +976,7 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR } } else { if (DecodeReader->posCount == 7*256) { // 7 bits jammend - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); // stop jamming + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming LED_D_OFF(); } else if (DecodeReader->posCount == 8*256) { DecodeReader->posCount = 0; @@ -1005,7 +1005,7 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR // correctly. //----------------------------------------------------------------------------- -static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) { +int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) { int samples = 0; bool gotFrame = false; uint8_t b; @@ -1167,7 +1167,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { Dbprintf("Sniff started. Press PM3 Button to stop."); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); LED_D_OFF(); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); @@ -1197,7 +1197,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { dma_start_time = GetCountSspClk() & 0xfffffff0; } - uint16_t snoopdata = *upTo++; + uint16_t sniffdata = *upTo++; if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. upTo = dmaBuf; // start reading the circular buffer from the beginning @@ -1218,7 +1218,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { } if (!TagIsActive) { // no need to try decoding reader data if the tag is sending - if (Handle15693SampleFromReader(snoopdata & 0x02, &DecodeReader)) { + if (Handle15693SampleFromReader(sniffdata & 0x02, &DecodeReader)) { uint32_t eof_time = dma_start_time + samples*16 + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF if (DecodeReader.byteCount > 0) { @@ -1236,7 +1236,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { ReaderIsActive = false; ExpectTagAnswer = true; - } else if (Handle15693SampleFromReader(snoopdata & 0x01, &DecodeReader)) { + } else if (Handle15693SampleFromReader(sniffdata & 0x01, &DecodeReader)) { uint32_t eof_time = dma_start_time + samples*16 + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF if (DecodeReader.byteCount > 0) { @@ -1261,7 +1261,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { } if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet - if (Handle15693SamplesFromTag(snoopdata >> 2, &DecodeTag)) { + if (Handle15693SamplesFromTag(sniffdata >> 2, &DecodeTag)) { uint32_t eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM_SNIFF; // end of EOF if (DecodeTag.lastBit == SOF_PART2) { @@ -1550,7 +1550,7 @@ void ReaderIso15693(uint32_t parameter) { } // When SIM: initialize the Proxmark3 as ISO15693 tag -static void Iso15693InitTag(void) { +void Iso15693InitTag(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index bc9b89eee..1b5405b13 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -23,6 +23,15 @@ #define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response #define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command +void Iso15693InitReader(void); +void Iso15693InitTag(void); +void CodeIso15693AsReader(uint8_t *cmd, int n); +void CodeIso15693AsTag(uint8_t *cmd, size_t len); + +void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow); +int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); +void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time); +int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time); void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index bfb19323b..141fefda5 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -134,7 +134,7 @@ static bool waitCmd14b(bool verbose) { PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if ((resp.oldarg[0] & 0xFF) > 0) return false; @@ -314,7 +314,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); - if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { uint8_t status = resp.oldarg[0]; if (status == 0) { @@ -330,7 +330,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); - if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { uint8_t status = resp.oldarg[0]; if (status == 0) { @@ -515,7 +515,7 @@ static bool HF14B_Std_Info(bool verbose) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); switch_off_field_14b(); return false; @@ -556,7 +556,7 @@ static bool HF14B_ST_Info(bool verbose) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); return false; } @@ -611,7 +611,7 @@ static bool HF14B_ST_Reader(bool verbose) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); return false; } @@ -651,7 +651,7 @@ static bool HF14B_Std_Reader(bool verbose) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); return false; } @@ -695,7 +695,7 @@ static bool HF14B_Other_Reader(void) { // clearCommandBuffer(); // SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, 0, data, datalen); // PacketResponseNG resp; - // WaitForResponse(CMD_ACK,&resp); + // WaitForResponse(CMD_HF_ISO14443B_COMMAND,&resp); // if (datalen > 2 ) { // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); @@ -709,7 +709,7 @@ static bool HF14B_Other_Reader(void) { // clearCommandBuffer(); // SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1); // PacketResponseNG resp; - // WaitForResponse(CMD_ACK, &resp); + // WaitForResponse(CMD_HF_ISO14443B_COMMAND, &resp); // if (datalen > 0) { // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); @@ -723,7 +723,7 @@ static bool HF14B_Other_Reader(void) { // clearCommandBuffer(); // SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1); // PacketResponseNG resp; - // WaitForResponse(CMD_ACK, &resp); + // WaitForResponse(CMD_HF_ISO14443B_COMMAND, &resp); // if (datalen > 0) { // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); @@ -899,7 +899,7 @@ static int CmdHF14BDump(const char *Cmd) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR, 0, 0, NULL, 0); //select - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) { if (resp.oldarg[0]) { PrintAndLogEx(INFO, "failed to select %" PRId64 " | %" PRId64, resp.oldarg[0], resp.oldarg[1]); goto out; @@ -915,7 +915,7 @@ static int CmdHF14BDump(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APPEND_CRC | ISO14B_RAW, 2, 0, req, sizeof(req)); - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) { uint8_t status = resp.oldarg[0] & 0xFF; if (status > 0) { diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 501190170..639519c30 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -529,21 +529,19 @@ static int CmdHFiClassSim(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_iclass_sim(); - uint8_t simType = 0; uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t sim_type = param_get8ex(Cmd, 0, 0, 10); - simType = param_get8ex(Cmd, 0, 0, 10); - - if (simType == 0) { + if (sim_type == 0) { if (param_gethex(Cmd, 1, CSN, 16)) { PrintAndLogEx(ERR, "A CSN should consist of 16 HEX symbols"); return usage_hf_iclass_sim(); } - PrintAndLogEx(INFO, " simtype: %02x CSN: %s", simType, sprint_hex(CSN, 8)); + PrintAndLogEx(INFO, " simtype: %02x CSN: %s", sim_type, sprint_hex(CSN, 8)); } - if (simType > 4) { - PrintAndLogEx(ERR, "Undefined simptype %d", simType); + if (sim_type > 4) { + PrintAndLogEx(ERR, "Undefined simtype %d", sim_type); return usage_hf_iclass_sim(); } @@ -575,14 +573,14 @@ static int CmdHFiClassSim(const char *Cmd) { **/ uint8_t tries = 0; - switch (simType) { + switch (sim_type) { - case 2: { + case ICLASS_SIM_MODE_READER_ATTACK: { PrintAndLogEx(INFO, "Starting iCLASS sim 2 attack (elite mode)"); - PrintAndLogEx(INFO, "press Enter to cancel"); + PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ICLASS_SIMULATE, simType, NUM_CSNS, 0, csns, 8 * NUM_CSNS); + SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, NUM_CSNS, 0, csns, 8 * NUM_CSNS); while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { tries++; @@ -625,13 +623,13 @@ static int CmdHFiClassSim(const char *Cmd) { free(dump); break; } - case 4: { + case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL: { // reader in key roll mode, when it has two keys it alternates when trying to verify. PrintAndLogEx(INFO, "Starting iCLASS sim 4 attack (elite mode, reader in key roll mode)"); PrintAndLogEx(INFO, "press Enter to cancel"); PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ICLASS_SIMULATE, simType, NUM_CSNS, 0, csns, 8 * NUM_CSNS); + SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, NUM_CSNS, 0, csns, 8 * NUM_CSNS); while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { tries++; @@ -689,12 +687,13 @@ static int CmdHFiClassSim(const char *Cmd) { free(dump); break; } - case 1: - case 3: + case ICLASS_SIM_MODE_CSN: + case ICLASS_SIM_MODE_CSN_DEFAULT: + case ICLASS_SIM_MODE_FULL: default: { uint8_t numberOfCSNs = 0; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ICLASS_SIMULATE, simType, numberOfCSNs, 0, CSN, 8); + SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 0, CSN, 8); break; } } diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 117eea672..0d24d5bae 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -588,6 +588,18 @@ typedef struct { #define FLAG_ICLASS_READER_ONE_TRY 0x20 #define FLAG_ICLASS_READER_CEDITKEY 0x40 +// iCLASS simulation modes +#define ICLASS_SIM_MODE_CSN 0 +#define ICLASS_SIM_MODE_CSN_DEFAULT 1 +#define ICLASS_SIM_MODE_READER_ATTACK 2 +#define ICLASS_SIM_MODE_FULL 3 +#define ICLASS_SIM_MODE_READER_ATTACK_KEYROLL 4 +#define ICLASS_SIM_MODE_EXIT_AFTER_MAC 5 // note: device internal only + +#define MODE_SIM_CSN 0 +#define MODE_EXIT_AFTER_MAC 1 +#define MODE_FULLSIM 2 + // Dbprintf flags #define FLAG_RAWPRINT 0x00 #define FLAG_LOG 0x01 From d83a45f0cb1860ac70d1588b016e587d97f3c7b3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Jul 2020 15:16:00 +0200 Subject: [PATCH 021/139] fpga merge changes --- armsrc/felica.c | 2 +- armsrc/hfsnoop.c | 4 +- armsrc/iclass.c | 274 +++++++++++++++++++++------------------ client/src/cmdhficlass.c | 34 +++-- include/pm3_cmd.h | 18 ++- include/protocols.h | 2 +- 6 files changed, 180 insertions(+), 154 deletions(-) diff --git a/armsrc/felica.c b/armsrc/felica.c index f8375f0cc..d61719c33 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -336,7 +336,7 @@ static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) { } static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) { - uint8_t flags = FPGA_MAJOR_MODE_HF_ISO18092; + uint16_t flags = FPGA_MAJOR_MODE_HF_ISO18092; if (power) flags |= FPGA_HF_ISO18092_FLAG_READER; if (highspeed) diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index 177a1f99e..e14be0858 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -41,12 +41,12 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Set up the synchronous serial port - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SNIFF); // Setting Frame Mode For better performance on high speed data transfer. AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNIFF); SpinDelay(100); *len = (BigBuf_max_traceLen() & 0xFFFE); diff --git a/armsrc/iclass.c b/armsrc/iclass.c index dbf759adf..a42cdf8f1 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -3,6 +3,7 @@ // Hagen Fritsch - June 2010 // Gerhard de Koning Gans - May 2011 // Gerhard de Koning Gans - June 2012 - Added iClass card and reader emulation +// piwi - 2019 // // 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 @@ -10,7 +11,6 @@ //----------------------------------------------------------------------------- // Routines to support iClass. //----------------------------------------------------------------------------- -// Based on ISO14443a implementation. Still in experimental phase. // Contribution made during a security research at Radboud University Nijmegen // // Please feel free to contribute and extend iClass support!! @@ -56,11 +56,6 @@ #include "ticks.h" #include "iso15693.h" -static int g_wait = 290; -static int timeout = 5000; -static uint32_t time_rdr = 0; -static uint32_t time_response = 0; - static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay); int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); @@ -117,8 +112,9 @@ void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string) { } static void rotateCSN(uint8_t *original_csn, uint8_t *rotated_csn) { - for (uint8_t i = 0; i < 8; i++) + for (uint8_t i = 0; i < 8; i++) { rotated_csn[i] = (original_csn[i] >> 3) | (original_csn[(i + 1) % 8] << 5); + } } // Encode SOF only @@ -376,8 +372,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } } - int exitLoop = 0; - // Anti-collision process: // Reader 0a // Tag 0f @@ -409,7 +403,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t *resp_conf = BigBuf_malloc(28); int resp_conf_len; - // e-Purse + // e-Purse (blk 2) // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) uint8_t *resp_cc = BigBuf_malloc(28); int resp_cc_len; @@ -420,7 +414,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; AddCrc(ff_data, 8); - // Application Issuer Area + // Application Issuer Area (blk 5) uint8_t *resp_aia = BigBuf_malloc(28); int resp_aia_len; @@ -467,7 +461,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { //This is used for responding to READ-block commands or other data which is dynamically generated //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_malloc(32 + 2);//8 bytes data + 2byte CRC is max tag answer + uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer //Then storage for the modulated data //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) @@ -479,14 +473,15 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t cmd, options, block; int len = 0; - while (exitLoop == false) { + bool exit_loop = 0; + while (exit_loop == false) { WDT_HIT(); uint32_t reader_eof_time = 0; len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); if (len < 0) { button_pressed = true; - exitLoop = true; + exit_loop = true; continue; } @@ -506,7 +501,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // Reader in anticollission phase if (chip_state != HALTED) { modulated_response = resp_sof; - modulated_response_size = resp_sof_len; //order = 1; + modulated_response_size = resp_sof_len; chip_state = ACTIVATED; goto send; } @@ -527,19 +522,21 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { if (chip_state == SELECTED) { // block0,1,2,5 is always readable. switch (block) { - case 0: // csn (0c 00) + case 0: { // csn (0c 00) modulated_response = resp_csn; modulated_response_size = resp_csn_len; trace_data = csn_data; trace_data_size = sizeof(csn_data); goto send; - case 1: // configuration (0c 01) + } + case 1: { // configuration (0c 01) modulated_response = resp_conf; modulated_response_size = resp_conf_len; - trace_data = conf_data; - trace_data_size = sizeof(conf_data); + trace_data = conf_block; + trace_data_size = sizeof(conf_block); goto send; - case 2: // e-purse (0c 02) + } + case 2: {// e-purse (0c 02) modulated_response = resp_cc; modulated_response_size = resp_cc_len; trace_data = card_challenge_data; @@ -549,19 +546,22 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(reader_mac_buf, card_challenge_data, 8); } goto send; + } case 3: - case 4: // Kd, Kc, always respond with 0xff bytes + case 4: { // Kd, Kc, always respond with 0xff bytes modulated_response = resp_ff; modulated_response_size = resp_ff_len; trace_data = ff_data; trace_data_size = sizeof(ff_data); goto send; - case 5:// Application Issuer Area (0c 05) + } + case 5: { // Application Issuer Area (0c 05) modulated_response = resp_aia; modulated_response_size = resp_aia_len; trace_data = aia_data; trace_data_size = sizeof(aia_data); goto send; + } default : { if (simulationMode == ICLASS_SIM_MODE_FULL) { // 0x0C //Read block @@ -570,7 +570,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { AddCrc(data_generic_trace, 8); trace_data = data_generic_trace; trace_data_size = 10; - CodeIClassTagAnswer(trace_data, trace_data_size); + CodeIso15693AsTag(trace_data, trace_data_size); memcpy(modulated_response, ToSend, ToSendMax); modulated_response_size = ToSendMax; goto send; @@ -588,23 +588,33 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = csn_data; trace_data_size = sizeof(csn_data); goto send; + } else if (cmd == ICLASS_CMD_READCHECK) { // 0x88 // Read e-purse KD (88 02) KC (18 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; //order = 4; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - LED_B_ON(); - goto send; + if (chip_state == SELECTED) { + if ( ICLASS_DEBIT(cmd) ){ + cipher_state = &cipher_state_KD[current_page]; + diversified_key = diversified_kd; + } else { + cipher_state = &cipher_state_KC[current_page]; + diversified_key = diversified_kc; + } + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + goto send; + } + } else if (cmd == ICLASS_CMD_CHECK) { // 0x05 // Reader random and reader MAC!!! if (simulationMode == ICLASS_SIM_MODE_FULL) { // NR, from reader, is in receivedCmd +1 - opt_doTagMAC_2(cipher_state, receivedCmd + 1, data_generic_trace, diversified_key); + opt_doTagMAC_2(*cipher_state, receivedCmd + 1, data_generic_trace, diversified_key); trace_data = data_generic_trace; trace_data_size = 4; - CodeIClassTagAnswer(trace_data, trace_data_size); + CodeIso15693AsTag(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; @@ -628,21 +638,24 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { Dbprintf("[+] CSN: %02x .... %02x OK", csn[0], csn[7]); } if (reader_mac_buf != NULL) { + // save NR and MAC for sim 2,4 memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); } - exitLoop = true; + exit_loop = true; } } goto send; + } else if (cmd == ICLASS_CMD_HALT && options == 0 && len == 1) { if (chip_state == SELECTED) { // Reader ends the session modulated_response = resp_sof; - modulated_response_size = resp_sof_Len; + modulated_response_size = resp_sof_len; chip_state = HALTED; goto send; } + } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06 if (chip_state == SELECTED) { @@ -656,31 +669,86 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { modulated_response_size = ToSendMax; goto send; } - } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_UPDATE) { - //Probably the reader wants to update the nonce. Let's just ignore that for now. - // OBS! If this is implemented, don't forget to regenerate the cipher_state - //We're expected to respond with the data+crc, exactly what's already in the receivedcmd - //receivedcmd is now UPDATE 1b | ADDRESS 1b| DATA 8b| Signature 4b or CRC 2b| + } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { - //Take the data... - memcpy(data_generic_trace, receivedCmd + 2, 8); - AddCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIClassTagAnswer(trace_data, trace_data_size); + // We're expected to respond with the data+crc, exactly what's already in the receivedCmd + // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b + if (chip_state == SELECTED) { - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; -// response_delay = 4600 * 1.5; // tPROG 4-15ms + if (block == 2) { // update e-purse + memcpy(card_challenge_data, receivedCmd + 2, 8); + CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); + memcpy(resp_cc, ToSend, ToSendMax); + resp_cc_len = ToSendMax; + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); + cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); + + } else if (block == 3) { // update Kd + for (int i = 0; i < 8; i++) { + if (personalization_mode) { + diversified_kd[i] = receivedCmd[2 + i]; + } else { + diversified_kd[i] ^= receivedCmd[2 + i]; + } + } + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); + + } else if (block == 4) { // update Kc + for (int i = 0; i < 8; i++) { + if (personalization_mode) { + diversified_kc[i] = receivedCmd[2 + i]; + } else { + diversified_kc[i] ^= receivedCmd[2 + i]; + } + } + cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); + } + + // update emulator + memcpy(emulator + (current_page * page_size) + (8 * block), receivedCmd + 2, 8); + + memcpy(data_generic_trace, receivedCmd + 2, 8); + AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } goto send; -// } else if(receivedCmd[0] == ICLASS_CMD_PAGESEL) { // 0x84 - //Pagesel - //Pagesel enables to select a page in the selected chip memory and return its configuration block - //Chips with a single page will not answer to this command - // It appears we're fine ignoring this. - //Otherwise, we should answer 8bytes (block) + 2bytes CRC + + } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { // 0x84 + // Pagesel, + // - enables to select a page in the selected chip memory and return its configuration block + // Chips with a single page will not answer to this command + // Otherwise, we should answer 8bytes (conf block 1) + 2bytes CRC + if (chip_state == SELECTED) { + + if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { + + current_page = receivedCmd[1]; + + memcpy(data_generic_trace, emulator + (current_page * page_size) + (8 * 1), 8); + memcpy(diversified_kd, emulator + (current_page * page_size) + (8 * 3), 8); + memcpy(diversified_kc, emulator + (current_page * page_size) + (8 * 4), 8); + + cipher_state = &cipher_state_KD[current_page]; + + personalization_mode = data_generic_trace[7] & 0x80; + AddCrc(data_generic_trace, 8); + + trace_data = data_generic_trace; + trace_data_size = 10; + + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } + } + // } else if(receivedCmd[0] == ICLASS_CMD_DETECT) { // 0x0F } else if (receivedCmd[0] == 0x26 && len == 5) { // standard ISO15693 INVENTORY command. Ignore. @@ -697,7 +765,7 @@ send: if (modulated_response_size > 0) { uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM; TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); - LogTrace(trace_data, trace_data_size, response_time*32, response_time*32 + modulated_response_size*32*64, NULL, false); + LogTrace(trace_data, trace_data_size, response_time * 32, (response_time * 32) + (modulated_response_size * 32 * 64), NULL, false); } } @@ -711,54 +779,6 @@ send: /// THE READER CODE - -//----------------------------------------------------------------------------- -// Transmit the command (to the tag) that was placed in ToSend[]. -//----------------------------------------------------------------------------- -static void TransmitIClassCommand(const uint8_t *cmd, int len, int *wait) { - - int c = 0; - bool firstpart = true; - uint8_t sendbyte; - - time_rdr = 0; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - - AT91C_BASE_SSC->SSC_THR = 0x00; - - // make sure we timeout previous comms. - if (*wait) - SpinDelayUs(*wait); - - for (;;) { - - WDT_HIT(); - - // Put byte into tx holding register as soon as it is ready - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - - // DOUBLE THE SAMPLES! - if (firstpart) { - sendbyte = (cmd[c] & 0xf0) | (cmd[c] >> 4); - } else { - sendbyte = (cmd[c] & 0x0f) | (cmd[c] << 4); - c++; - } - - if (sendbyte == 0xff) - sendbyte = 0xfe; - - AT91C_BASE_SSC->SSC_THR = sendbyte; - firstpart = !firstpart; - - if (c >= len) break; - } - } - - time_rdr = GetCountSspClk(); -} - static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) { CodeIso15693AsReader(frame, len); @@ -800,7 +820,7 @@ static bool selectIclassTag(uint8_t *card_data, bool use_credit_key, uint32_t *e // bit 7: parity. if (use_credit_key) - readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK; + read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; @@ -850,7 +870,7 @@ static bool selectIclassTag(uint8_t *card_data, bool use_credit_key, uint32_t *e // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); + ReaderTransmitIClass(read_check_cc, sizeof(read_check_cc), &start_time); // expect a 8-byte response here len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); @@ -864,25 +884,24 @@ static bool selectIclassTag(uint8_t *card_data, bool use_credit_key, uint32_t *e // Reader iClass Anticollission // turn off afterwards -void ReaderIClass(uint8_t arg0) { +void ReaderIClass(uint8_t flags) { - uint8_t card_data[6 * 8] = {0}; + uint8_t card_data[6 * 8] = {0xFF}; uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t resp[ICLASS_BUFFER_SIZE]; - memset(card_data, 0xFF, sizeof(card_data)); +// memset(card_data, 0xFF, sizeof(card_data)); memset(resp, 0xFF, sizeof(resp)); - bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully - bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; // flag to not to loop continuously, looking for tag - bool use_credit_key = arg0 & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key - bool flagReadAIA = arg0 & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area + bool flag_readonce = flags & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully + bool use_credit_key = flags & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key + bool flag_read_aia = flags & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area - if (flags & FLAG_ICLASS_READER_INIT) { + if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) { Iso15693InitReader(); } - if (flags & FLAG_ICLASS_READER_CLEARTRACE) { + if ((flags & FLAG_ICLASS_READER_CLEARTRACE) == FLAG_ICLASS_READER_CLEARTRACE) { set_tracing(true); clear_trace(); StartCountSspClk(); @@ -890,7 +909,6 @@ void ReaderIClass(uint8_t arg0) { uint32_t start_time = 0; uint32_t eof_time = 0; - int read_status = selectIclassTag(card_data, use_credit_key, &eof_time); if (read_status == 0) { reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); @@ -898,18 +916,18 @@ void ReaderIClass(uint8_t arg0) { return; } - uint8_t result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC; + uint8_t result_status = FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC; //Read block 5, AIA - if (flagReadAIA) { + if (flag_read_aia) { //Read App Issuer Area block CRC(0x05) => 0xde 0x64 - uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + uint8_t read_aa[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { - result_status |= FLAG_ICLASS_READER_AIA; + if (sendCmdGetResponseWithRetries(read_aa, sizeof(read_aa), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { + result_status |= FLAG_ICLASS_AIA; memcpy(card_data + (8 * 5), resp, 8); } else { - if (DBGLEVEL >= DBG_EXTENDED) DbpString("Failed to dump AA block"); + if (DBGLEVEL >= DBG_EXTENDED) DbpString("Failed to dump AIA block"); } } @@ -929,12 +947,10 @@ void ReaderIClass(uint8_t arg0) { // only useful if looping in arm (not try_once && not abort_after_read) if (memcmp(last_csn, card_data, 8) != 0) { - if (send) { - reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); - if (abort_after_read) { - LED_B_OFF(); - return; - } + reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + if (flag_readonce) { + LED_B_OFF(); + return; } LED_B_OFF(); } @@ -1269,12 +1285,12 @@ static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { } uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - if (blockNo == 2) { + if (blockno == 2) { // check response. e-purse update swaps first and second half if (memcmp(data+4, resp, 4) || memcmp(data, resp+4, 4)) { return false; } - } else if (blockNo == 3 || blockNo == 4) { + } else if (blockno == 3 || blockno == 4) { // check response. Key updates always return 0xffffffffffffffff if (memcmp(all_ff, resp, 8)) { return false; diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 639519c30..21ad93997 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1101,7 +1101,7 @@ static void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) { PacketResponseNG resp; - uint8_t flags = FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_ONE_TRY; + uint8_t flags = FLAG_ICLASS_READER_ONLY_ONCE; if (use_credit_key) flags |= FLAG_ICLASS_READER_CEDITKEY; @@ -1279,9 +1279,12 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { // if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work) if (!have_debit_key && have_credit_key) use_credit_key = true; - uint32_t flags = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC | - FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE | - FLAG_ICLASS_READER_ONE_TRY; + uint32_t flags = ( + FLAG_ICLASS_READER_INIT | + FLAG_ICLASS_READER_CLEARTRACE | + FLAG_ICLASS_READER_ONLY_ONCE + ); + //get config and first 3 blocks PacketResponseNG resp; @@ -1305,7 +1308,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { return PM3_ESOFT; } - if (readStatus & (FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC)) { + if (readStatus & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC)) { memcpy(tag_data, data, 8 * 3); blockno += 2; // 2 to force re-read of block 2 later. (seems to respond differently..) numblks = data[8]; @@ -2927,9 +2930,12 @@ int CmdHFiClass(const char *Cmd) { int readIclass(bool loop, bool verbose) { bool tagFound = false; - uint32_t flags = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_AIA | - FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE | - FLAG_ICLASS_READER_ONE_TRY; + uint32_t flags = ( + FLAG_ICLASS_READER_INIT | + FLAG_ICLASS_READER_CLEARTRACE | + FLAG_ICLASS_READER_ONLY_ONCE | + FLAG_ICLASS_READER_AIA + ); uint32_t res = PM3_ETIMEOUT; // loop in client not device - else on windows have a communication error @@ -2960,35 +2966,35 @@ int readIclass(bool loop, bool verbose) { PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " --------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); - if (readStatus & FLAG_ICLASS_READER_CSN) { + if (readStatus & FLAG_ICLASS_CSN) { PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn))); tagFound = true; } - if (readStatus & FLAG_ICLASS_READER_CONF) { + if (readStatus & FLAG_ICLASS_CONF) { PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); } - if (readStatus & FLAG_ICLASS_READER_CC) { + if (readStatus & FLAG_ICLASS_CC) { PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); } PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); - if (readStatus & FLAG_ICLASS_READER_AIA) { + if (readStatus & FLAG_ICLASS_AIA) { // PrintAndLogEx(INFO, "--------- " _CYAN_("AIA") " ---------"); PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); } - if (readStatus & FLAG_ICLASS_READER_CONF) { + if (readStatus & FLAG_ICLASS_CONF) { printIclassDumpInfo(data); } // if CSN ends with FF12E0, it's inside HID CSN range. bool isHidRange = (memcmp((uint8_t *)(data + 5), "\xFF\x12\xE0", 3) == 0); - if (readStatus & FLAG_ICLASS_READER_AIA) { + if (readStatus & FLAG_ICLASS_AIA) { bool legacy = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); bool se_enabled = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 0d24d5bae..bf16aaca6 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -579,14 +579,18 @@ typedef struct { #define FLAG_FORCED_ATQA 0x800 #define FLAG_FORCED_SAK 0x1000 -//Iclass reader flags -#define FLAG_ICLASS_READER_ONLY_ONCE 0x01 -#define FLAG_ICLASS_READER_CC 0x02 -#define FLAG_ICLASS_READER_CSN 0x04 -#define FLAG_ICLASS_READER_CONF 0x08 +// iCLASS reader flags +#define FLAG_ICLASS_READER_INIT 0x01 +#define FLAG_ICLASS_READER_CLEARTRACE 0x02 +#define FLAG_ICLASS_READER_ONLY_ONCE 0x04 +#define FLAG_ICLASS_READER_CEDITKEY 0x08 #define FLAG_ICLASS_READER_AIA 0x10 -#define FLAG_ICLASS_READER_ONE_TRY 0x20 -#define FLAG_ICLASS_READER_CEDITKEY 0x40 + +// iCLASS reader status flags +#define FLAG_ICLASS_CSN 0x01 +#define FLAG_ICLASS_CC 0x02 +#define FLAG_ICLASS_CONF 0x04 +#define FLAG_ICLASS_AIA 0x08 // iCLASS simulation modes #define ICLASS_SIM_MODE_CSN 0 diff --git a/include/protocols.h b/include/protocols.h index 682f57eff..18e580b54 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -135,7 +135,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define ICLASS_CMD_ACT 0xE #define ICLASS_CREDIT(x) (((x) & 0x10) == 0x10) -#define ICLASS_DEBIT(x) !(ICLASS_CREDIT(x)) +#define ICLASS_DEBIT(x) (((x) & 0x80) == 0x80) #define ISO14443A_CMD_REQA 0x26 From 6948ccff3af42a47a02da7935a6d9f36fcb37d0a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Jul 2020 22:33:38 +0200 Subject: [PATCH 022/139] fpga iclass... --- armsrc/iclass.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index a42cdf8f1..e02975041 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -922,7 +922,6 @@ void ReaderIClass(uint8_t flags) { if (flag_read_aia) { //Read App Issuer Area block CRC(0x05) => 0xde 0x64 uint8_t read_aa[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - if (sendCmdGetResponseWithRetries(read_aa, sizeof(read_aa), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { result_status |= FLAG_ICLASS_AIA; memcpy(card_data + (8 * 5), resp, 8); @@ -993,7 +992,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { //for now replay captured auth (as cc not updated) memcpy(check + 5, mac, 4); - if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 5)) { + if (sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time) == false) { DbpString("Error: Authentication Fail!"); continue; } @@ -1002,7 +1001,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { read[1] = 1; AddCrc(read + 1, 1); - if (!sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 5)) { + if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time) == false) { DbpString("Dump config (block 1) failed"); continue; } @@ -1028,7 +1027,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { read[1] = block; AddCrc(read + 1, 1); - if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 5)) { + if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", block, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5], @@ -1038,6 +1037,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { //Fill up the buffer memcpy(card_data + stored_data_length, resp, 8); stored_data_length += 8; + if (stored_data_length + 8 > PM3_CMD_DATA_SIZE) { //Time to send this off and start afresh reply_old(CMD_ACK, @@ -1086,7 +1086,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { // turn off afterwards void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { uint8_t readcheck[] = { keytype, blockno }; - uint8_t resp[] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t resp[8] = {0}; + uint32_t eof_time; bool isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); switch_off(); @@ -1104,9 +1105,8 @@ void iClass_Authentication(uint8_t *mac) { check[7] = mac[2]; check[8] = mac[3]; //memcpy(check+5, mac, 4); - - // 6 retries - uint8_t isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 6); + uint32_t eof_time; + bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); } @@ -1187,7 +1187,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { check[8] = keys[i].mac[3]; // expect 4bytes, 3 retries times.. - isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 3); + isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); if (isOK) goto out; From 7c15e4b7ff73dce83292858bdf0ee995de2927d9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Jul 2020 22:43:11 +0200 Subject: [PATCH 023/139] fpga more iclass --- armsrc/iclass.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index e02975041..02b73a2ba 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -971,6 +971,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; uint8_t card_data[PM3_CMD_DATA_SIZE] = {0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; + uint32_t eof_time = 0; static struct memory_t { int k16; @@ -980,8 +981,6 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { int keyaccess; } memory; - setupIclassReader(); - while (!BUTTON_PRESS()) { WDT_HIT(); @@ -993,7 +992,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { memcpy(check + 5, mac, 4); if (sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time) == false) { - DbpString("Error: Authentication Fail!"); + if (DBGLEVEL >= DBG_EXTENDED) DbpString("Error: Authentication Fail!"); continue; } @@ -1002,22 +1001,24 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { AddCrc(read + 1, 1); if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time) == false) { - DbpString("Dump config (block 1) failed"); + if (DBGLEVEL >= DBG_EXTENDED) DbpString("Dump config (block 1) failed"); continue; } mem = resp[5]; - memory.k16 = (mem & 0x80); - memory.book = (mem & 0x20); - memory.k2 = (mem & 0x8); - memory.lockauth = (mem & 0x2); - memory.keyaccess = (mem & 0x1); + memory.k16 = ((mem & 0x80) == 0x80); + memory.book = ((mem & 0x20) == 0x20); + memory.k2 = ((mem & 0x08) == 0x08); + memory.lockauth = ((mem & 0x02) == 0x02); + memory.keyaccess = ((mem & 0x01) == 0x01); cardsize = memory.k16 ? 255 : 32; WDT_HIT(); - //Set card_data to all zeroes, we'll fill it with data - memset(card_data, 0x0, PM3_CMD_DATA_SIZE); + + // set card_data to 0xFF... + memset(card_data, 0xFF, PM3_CMD_DATA_SIZE); + uint8_t failedRead = 0; uint32_t stored_data_length = 0; @@ -1028,11 +1029,13 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { AddCrc(read + 1, 1); if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { - Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", - block, resp[0], resp[1], resp[2], - resp[3], resp[4], resp[5], - resp[6], resp[7] - ); + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", + block, + resp[0], resp[1], resp[2], resp[3], + resp[4], resp[5], resp[6], resp[7] + ); + } //Fill up the buffer memcpy(card_data + stored_data_length, resp, 8); @@ -1054,7 +1057,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { } else { failedRead = 1; stored_data_length += 8;//Otherwise, data becomes misaligned - Dbprintf("Failed to dump block %d", block); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Failed to dump block %d", block); } } @@ -1087,7 +1090,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { uint8_t readcheck[] = { keytype, blockno }; uint8_t resp[8] = {0}; - uint32_t eof_time; + uint32_t eof_time = 0; bool isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); switch_off(); @@ -1122,9 +1125,12 @@ typedef struct iclass_premac { * to cover debit and credit key. (AA1/AA2) */ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { + uint8_t i = 0, isOK = 0; + uint8_t lastChunk = ((arg0 >> 8) & 0xFF); bool use_credit_key = ((arg0 >> 16) & 0xFF); + uint8_t keyCount = arg1 & 0xFF; uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t resp[ICLASS_BUFFER_SIZE]; @@ -1143,11 +1149,10 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { switch_off(); SpinDelay(20); - setupIclassReader(); - uint16_t checked = 0; int read_status = 0; uint8_t startup_limit = 10; + uint32_t eof_time = 0; while (read_status != 2) { if (checked == 1000) { From 2502d4581b20ff79ebf2054c49ab010527d8e6b7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 7 Jul 2020 12:32:56 +0200 Subject: [PATCH 024/139] iclass merges --- armsrc/iclass.c | 64 +++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 02b73a2ba..0fb0a4f53 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -954,12 +954,13 @@ void ReaderIClass(uint8_t flags) { LED_B_OFF(); } - if (userCancelled) { - reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); - switch_off(); - } else { +// if (userCancelled) { +// reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); +// switch_off(); +// } else { reply_mix(CMD_ACK, 0, 0, 0, card_data, 0); - } +// } + switch_off(); } // turn off afterwards @@ -971,6 +972,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; uint8_t card_data[PM3_CMD_DATA_SIZE] = {0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; + + uint32_t start_time = 0; uint32_t eof_time = 0; static struct memory_t { @@ -1108,7 +1111,7 @@ void iClass_Authentication(uint8_t *mac) { check[7] = mac[2]; check[8] = mac[3]; //memcpy(check+5, mac, 4); - uint32_t eof_time; + uint32_t eof_time = 0; bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); } @@ -1220,10 +1223,10 @@ out: // retries 10times. static bool iClass_ReadBlock(uint8_t blockno, uint8_t *data) { uint8_t resp[10]; - uint8_t cmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; - AddCrc(cmd + 1, 1); - uint32_t eof_time; - bool isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd), resp, sizeof(resp), 10, 10, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; + AddCrc(c + 1, 1); + uint32_t eof_time = 0; + bool isOK = sendCmdGetResponseWithRetries(c, sizeof(c), resp, sizeof(resp), 10, 10, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); memcpy(data, resp, 8); return isOK; } @@ -1241,44 +1244,49 @@ void iClass_ReadBlk(uint8_t blockno) { switch_off(); reply_ng(CMD_HF_ICLASS_READBL, PM3_SUCCESS, (uint8_t *)&result, sizeof(result)); } + +// Dump command seems to dump a block related portion of card memory. +// I suppose it will need to do an authentatication to AA1, read its blocks by calling this. +// then authenticate AA2, and read those blocks by calling this. +// By the looks at it only 2K cards is supported, or first page dumps on larger cards. +// turn off afterwards +void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { -// turn off afterwards -void iClass_Dump(uint8_t blockno, uint8_t numblks) { - BigBuf_free(); - uint8_t *dataout = BigBuf_malloc(0xFF * 8); + BigBuf_free(); + + uint8_t *dataout = BigBuf_malloc(0xFF * 8); if (dataout == NULL) { - DbpString("[!] fail to allocate memory"); + DbpString("fail to allocate memory"); OnError(1); return; } memset(dataout, 0xFF, 0xFF * 8); - uint8_t blockdata[8] = {0}; - uint8_t blkCnt = 0; bool isOK; - for (; blkCnt < numblks; blkCnt++) { - isOK = iClass_ReadBlock(blockno + blkCnt, blockdata); + uint8_t blkcnt = 0; + for (; blkcnt < numblks; blkcnt++) { + isOK = iClass_ReadBlock(start_blockno + blkcnt, dataout + (8 * blkcnt)); - // 0xBB is the internal debug separator byte.. - if (!isOK || (blockdata[0] == 0xBB || blockdata[7] == 0xBB || blockdata[2] == 0xBB)) { //try again - isOK = iClass_ReadBlock(blockno + blkCnt, blockdata); + if (!isOK) { + isOK = iClass_ReadBlock(start_blockno + blkcnt, dataout + (8 * blkcnt)); if (!isOK) { - Dbprintf("[!] block %02X failed to read", blkCnt + blockno); + Dbprintf("failed to read block %02X", start_blockno + blkcnt); break; } } - memcpy(dataout + (blkCnt * 8), blockdata, 8); } switch_off(); - //return pointer to dump memory in arg3 - reply_mix(CMD_ACK, isOK, blkCnt, BigBuf_max_traceLen(), 0, 0); + + // return pointer to dump memory in arg3 + // iceman: why not return | dataout - getbigbuf ? Should give exact location. + reply_mix(CMD_ACK, isOK, blkcnt, BigBuf_max_traceLen(), 0, 0); BigBuf_free(); } static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { - uint8_t write[] = { 0x80 | ICLASS_CMD_UPDATE, blockno, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; memcpy(write + 2, data, 12); // data + mac AddCrc(write + 1, 13); @@ -1292,7 +1300,7 @@ static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; if (blockno == 2) { // check response. e-purse update swaps first and second half - if (memcmp(data+4, resp, 4) || memcmp(data, resp+4, 4)) { + if (memcmp(data + 4, resp, 4) || memcmp(data, resp + 4, 4)) { return false; } } else if (blockno == 3 || blockno == 4) { From b775b68e4e9a7603169dd55dd6dd86b2bbf59576 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 7 Jul 2020 13:18:53 +0200 Subject: [PATCH 025/139] fpga iclass --- armsrc/appmain.c | 13 ++++++++++-- armsrc/felica.c | 2 +- armsrc/hfsnoop.c | 2 +- armsrc/iclass.c | 53 ++++++++++++++++++++---------------------------- armsrc/iclass.h | 2 ++ 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index a252bbe8e..963d36c78 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1048,7 +1048,11 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ISO15693_SIMULATE: { - SimTagIso15693(packet->oldarg[0], packet->data.asBytes); + struct p { + uint8_t uid[10]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + SimTagIso15693(payload->uid); break; } #endif @@ -1376,7 +1380,12 @@ static void PacketReceived(PacketCommandNG *packet) { #ifdef WITH_ICLASS // Makes use of ISO14443a FPGA Firmware case CMD_HF_ICLASS_SNIFF: { - SniffIClass(); + struct p { + uint8_t jam_search_len; + uint8_t jam_search_string[]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + SniffIClass(payload->jam_search_len, payload->jam_search_string); break; } case CMD_HF_ICLASS_SIMULATE: { diff --git a/armsrc/felica.c b/armsrc/felica.c index d61719c33..944b89ffe 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -464,7 +464,7 @@ static void iso18092_setup(uint8_t fpga_minor_mode) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Set up the synchronous serial port - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO18092); // LSB transfer. Remember to set it back to MSB with AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index e14be0858..1b87d857a 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -119,7 +119,7 @@ void HfPlotDownload(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaSetupSsc(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_GET_TRACE); AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) this_buf; // start transfer to this memory address diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 0fb0a4f53..99976566c 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -56,9 +56,6 @@ #include "ticks.h" #include "iso15693.h" -static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay); -int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); - // The length of a received command will in most cases be no more than 18 bytes. // we expect max 34 bytes as tag answer (response to READ4) #ifndef ICLASS_BUFFER_SIZE @@ -808,7 +805,7 @@ static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint * @return false = fail * true = Got all. */ -static bool selectIclassTag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { +static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; @@ -909,7 +906,7 @@ void ReaderIClass(uint8_t flags) { uint32_t start_time = 0; uint32_t eof_time = 0; - int read_status = selectIclassTag(card_data, use_credit_key, &eof_time); + int read_status = select_iclass_tag(card_data, use_credit_key, &eof_time); if (read_status == 0) { reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); switch_off(); @@ -973,8 +970,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { uint8_t card_data[PM3_CMD_DATA_SIZE] = {0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; - uint32_t start_time = 0; - uint32_t eof_time = 0; + bool use_credit_key = false; static struct memory_t { int k16; @@ -984,12 +980,14 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { int keyaccess; } memory; - while (!BUTTON_PRESS()) { + uint32_t start_time = 0; + uint32_t eof_time = 0; + while (BUTTON_PRESS() == false) { WDT_HIT(); - uint8_t read_status = handshakeIclassTag(card_data); - if (read_status < 2) continue; + bool read_status = select_iclass_tag(card_data, use_credit_key, &eof_time); + if (read_status == false) continue; //for now replay captured auth (as cc not updated) memcpy(check + 5, mac, 4); @@ -1130,7 +1128,6 @@ typedef struct iclass_premac { void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { uint8_t i = 0, isOK = 0; - uint8_t lastChunk = ((arg0 >> 8) & 0xFF); bool use_credit_key = ((arg0 >> 16) & 0xFF); @@ -1152,28 +1149,21 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { switch_off(); SpinDelay(20); - uint16_t checked = 0; - int read_status = 0; - uint8_t startup_limit = 10; + + bool read_status = false; + uint32_t start_time = 0; uint32_t eof_time = 0; - while (read_status != 2) { + uint8_t tries = 10; + while (tries-- > 0 || read_status == false) { + read_status = select_iclass_tag(card_data, use_credit_key, &eof_time); + } - if (checked == 1000) { - if (BUTTON_PRESS() || !data_available()) goto out; - checked = 0; - } - ++checked; + // failed to select card 10 times. return fail to client + if (read_status == false) + goto out; - read_status = handshakeIclassTag_ext(card_data, use_credit_key); - if (startup_limit-- == 0) { - Dbprintf("[-] Handshake status | %d (fail 10)", read_status); - isOK = 99; - goto out; - } - }; - // since handshakeIclassTag_ext call sends s readcheck, we start with sending first response. - - checked = 0; + // since select_iclass_tag call sends s readcheck, we start with sending first response. + uint16_t checked = 0; // Keychunk loop for (i = 0; i < keyCount; i++) { @@ -1199,9 +1189,10 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { if (isOK) goto out; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; // Auth Sequence MUST begin with reading e-purse. (block2) // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); LED_B_OFF(); } diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 6ce23ceb7..20a862535 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -25,4 +25,6 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks); void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); void iClass_ReadCheck(uint8_t blockno, uint8_t keytype); + +int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); #endif From ce24e6acbbc754a4c56a26dc4920f34199356b9b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 8 Jul 2020 09:45:49 +0200 Subject: [PATCH 026/139] fpga merge hell, all compiles --- armsrc/appmain.c | 9 +++++++-- armsrc/iso15693.h | 2 +- client/src/cmdhf15.c | 7 +++---- include/pm3_cmd.h | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 963d36c78..2ed5811fa 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1031,8 +1031,13 @@ static void PacketReceived(PacketCommandNG *packet) { AcquireRawAdcSamplesIso15693(); break; } - case CMD_HF_ISO15693_RAWADC: { - RecordRawAdcSamplesIso15693(); + case CMD_HF_ISO15693_SNIFF: { + struct p { + uint8_t jam_search_len; + uint8_t jam_search_string[]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + SniffIso15693(payload->jam_search_len, payload->jam_search_string); break; } case CMD_HF_ISO15693_COMMAND: { diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 1b5405b13..fcca9491c 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -33,7 +33,7 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time); int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time); -void RecordRawAdcSamplesIso15693(void); +//void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg void SimTagIso15693(uint8_t *uid); // simulate an ISO15693 tag - greg diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 2b8812d33..ad69d5615 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -973,12 +973,12 @@ static int CmdHF15Info(const char *Cmd) { // Record Activity without enabling carrier //helptext -static int CmdHF15Record(const char *Cmd) { +static int CmdHF15Sniff(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_15_record(); clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO15693_RAWADC, NULL, 0); + SendCommandNG(CMD_HF_ISO15693_SNIFF, NULL, 0); return PM3_SUCCESS; } @@ -1841,9 +1841,8 @@ static command_t CommandTable[] = { {"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"}, {"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"}, {"info", CmdHF15Info, IfPm3Iso15693, "Tag information"}, -// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"}, + {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"}, {"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"}, - {"record", CmdHF15Record, IfPm3Iso15693, "Record Samples (ISO15693)"}, {"read", CmdHF15Read, IfPm3Iso15693, "Read a block"}, {"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"}, {"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"}, diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index bf16aaca6..492eca798 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -431,7 +431,7 @@ typedef struct { #define CMD_HF_ISO14443B_COMMAND 0x0305 #define CMD_HF_ISO15693_READER 0x0310 #define CMD_HF_ISO15693_SIMULATE 0x0311 -#define CMD_HF_ISO15693_RAWADC 0x0312 +#define CMD_HF_ISO15693_SNIFF 0x0312 #define CMD_HF_ISO15693_COMMAND 0x0313 #define CMD_HF_ISO15693_FINDAFI 0x0315 #define CMD_LF_SNIFF_RAW_ADC 0x0317 From 0d4c537eded79faa9e46b2efa6910ad7be8ae519 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 8 Jul 2020 11:05:04 +0200 Subject: [PATCH 027/139] version info for FeliCa fpga image --- tools/fpga_compress/fpga_compress.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/fpga_compress/fpga_compress.c b/tools/fpga_compress/fpga_compress.c index b03caabf4..5da59f2db 100644 --- a/tools/fpga_compress/fpga_compress.c +++ b/tools/fpga_compress/fpga_compress.c @@ -50,10 +50,13 @@ static int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile) { if (total_size >= num_infiles * FPGA_CONFIG_SIZE) { fprintf(stderr, "Input files too big (total > %li bytes). These are probably not PM3 FPGA config files.\n" - , num_infiles * FPGA_CONFIG_SIZE); + , num_infiles * FPGA_CONFIG_SIZE + ); + for (uint16_t j = 0; j < num_infiles; j++) { fclose(infile[j]); } + free(fpga_config); return (EXIT_FAILURE); } @@ -188,8 +191,10 @@ static int zlib_decompress(FILE *infile, FILE *outfile) { * length. */ static int bitparse_find_section(FILE *infile, char section_name, unsigned int *section_length) { - int result = 0; + #define MAX_FPGA_BIT_STREAM_HEADER_SEARCH 100 // maximum number of bytes to search for the requested section + + int result = 0; uint16_t numbytes = 0; while (numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) { char current_name = (char)fgetc(infile); @@ -252,6 +257,8 @@ static int FpgaGatherVersion(FILE *infile, char *infile_name, char *dst, int len strncat(dst, "LF", len - strlen(dst) - 1); else if (!memcmp("fpga_hf", basename(infile_name), 7)) strncat(dst, "HF", len - strlen(dst) - 1); + else if (!memcmp("fpga_felica", basename(infile_name), 7)) + strncat(dst, "HF FeliCa", len - strlen(dst) - 1); strncat(dst, " image built", len - strlen(dst) - 1); if (bitparse_find_section(infile, 'b', &fpga_info_len)) { From 2a30f3b1657bde7bbeeb6695f66d8908d13dd513 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 8 Jul 2020 11:05:54 +0200 Subject: [PATCH 028/139] fgpa felica --- armsrc/fpgaloader.c | 4 +++- armsrc/fpgaloader.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 8313404bf..f76d1a189 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -351,8 +351,10 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp co * length. */ static int bitparse_find_section(int bitstream_version, char section_name, uint32_t *section_length, lz4_streamp compressed_fpga_stream, uint8_t *output_buffer) { - int result = 0; + #define MAX_FPGA_BIT_STREAM_HEADER_SEARCH 100 // maximum number of bytes to search for the requested section + + int result = 0; uint16_t numbytes = 0; while (numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) { char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer); diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 17bd8bbc2..530dc21b4 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -20,6 +20,7 @@ // definitions for multiple FPGA config files support #define FPGA_BITSTREAM_LF 1 #define FPGA_BITSTREAM_HF 2 +#define FPGA_BITSTREAM_HF_FELICA 3 /* Communication between ARM / FPGA is done inside armsrc/fpgaloader.c (function FpgaSendCommand) From ec1c72d73cf257be544bc0fbefde4fc856f63a2d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 8 Jul 2020 23:11:11 +0200 Subject: [PATCH 029/139] fix felica image --- fpga/fpga_felica.bit | Bin 42179 -> 42179 bytes fpga/fpga_felica.v | 2 -- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/fpga_lf.bit | Bin 42175 -> 42175 bytes 4 files changed, 2 deletions(-) diff --git a/fpga/fpga_felica.bit b/fpga/fpga_felica.bit index dc68b740b025bee0adeee9d72a787e1216b84b5c..3b222908030eefbd6206997787560745d21124d8 100644 GIT binary patch literal 42179 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 literal 42179 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 Date: Wed, 8 Jul 2020 23:11:29 +0200 Subject: [PATCH 030/139] felica fixes --- armsrc/felica.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/felica.c b/armsrc/felica.c index 944b89ffe..53f78d17b 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -445,7 +445,7 @@ static void iso18092_setup(uint8_t fpga_minor_mode) { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Start iso18092_setup"); LEDsoff(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF_FELICA); // allocate command receive buffer BigBuf_free(); From 246144df2a19640660294a1cf0dd4dec31edf43e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 8 Jul 2020 23:11:50 +0200 Subject: [PATCH 031/139] amiboo default pack --- armsrc/iso14443a.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 225337485..836360740 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1499,10 +1499,13 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { uint8_t pwd[4]; emlGetMemBt(pwd, (pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(pwd)); if (memcmp(receivedCmd + 1, pwd, 4) == 0) { - uint8_t cmd[4]; - emlGetMemBt(cmd, pages * 4 + MFU_DUMP_PREFIX_LENGTH, 2); - AddCrc14A(cmd, sizeof(cmd) - 2); - EmSendCmd(cmd, sizeof(cmd)); + uint8_t pack[4]; + emlGetMemBt(pack, pages * 4 + MFU_DUMP_PREFIX_LENGTH, 2); + if (memcmp(pack, "\x00\x00\x00\x00", 4) == 0) { + memcpy(pack, "\x80\x80\x00\x00", 4); + } + AddCrc14A(pack, sizeof(pack) - 2); + EmSendCmd(pack, sizeof(pack)); } else { EmSend4bit(CARD_NACK_NA); if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Auth attempt: %08x", bytes_to_num(receivedCmd + 1, 4)); From a76679f7e6e2bd36546e8af4bb0e2289b76884ba Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Jul 2020 00:20:52 +0200 Subject: [PATCH 032/139] hf iclass reader --- armsrc/iclass.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 99976566c..e01c5a217 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -884,13 +884,13 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t void ReaderIClass(uint8_t flags) { uint8_t card_data[6 * 8] = {0xFF}; - uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +// uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t resp[ICLASS_BUFFER_SIZE]; // memset(card_data, 0xFF, sizeof(card_data)); memset(resp, 0xFF, sizeof(resp)); - bool flag_readonce = flags & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully +// bool flag_readonce = flags & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully bool use_credit_key = flags & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key bool flag_read_aia = flags & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area @@ -938,9 +938,11 @@ void ReaderIClass(uint8_t flags) { // with 0xFF:s in block 3 and 4. LED_B_ON(); - + reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + //Send back to client, but don't bother if we already sent this - // only useful if looping in arm (not try_once && not abort_after_read) + /* if (memcmp(last_csn, card_data, 8) != 0) { reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); @@ -950,12 +952,13 @@ void ReaderIClass(uint8_t flags) { } LED_B_OFF(); } + */ // if (userCancelled) { // reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); // switch_off(); // } else { - reply_mix(CMD_ACK, 0, 0, 0, card_data, 0); +// reply_mix(CMD_ACK, result_status, 0, 0, card_data, 0); // } switch_off(); } From d67bc94e2004301f01d428361ad279a10ebe508f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Jul 2020 00:21:26 +0200 Subject: [PATCH 033/139] hf iclass sniff --- client/src/cmdhficlass.c | 60 +++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 21ad93997..f11d65945 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2,6 +2,7 @@ // Copyright (C) 2010 iZsh , Hagen Fritsch // Copyright (C) 2011 Gerhard de Koning Gans // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende +// Copyright (C) 2019 piwi // Copyright (C) 2020 Iceman // // This code is licensed to you under the terms of the GNU GPL, version 2 or, @@ -13,6 +14,7 @@ #include "cmdhficlass.h" #include +#include "cliparser.h" #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN #include "cmdtrace.h" @@ -272,15 +274,7 @@ static int usage_hf_iclass_replay(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_hf_iclass_sniff(void) { - PrintAndLogEx(NORMAL, "Sniff the communication between reader and tag\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass sniff [h]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h Show this help"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass sniff")); - return PM3_SUCCESS; -} + static int usage_hf_iclass_loclass(void) { PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack"); PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of"); @@ -518,9 +512,35 @@ static int CmdHFiClassList(const char *Cmd) { } static int CmdHFiClassSniff(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_iclass_sniff(); - SendCommandNG(CMD_HF_ICLASS_SNIFF, NULL, 0); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass sniff", + "Sniff the communication reader and tag", + "Usage:\n" + _YELLOW_("\thf iclass sniff") "\n" + _YELLOW_("\thf iclass sniff -j") " -> jam e-purse updates\n" + ); + + void* argtable[] = { + arg_param_begin, + arg_lit0("j", "jam", "Jam (prevent) e-purse updates"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool jam_epurse_update = arg_get_lit(ctx, 1); + const uint8_t update_epurse_sequence[2] = {0x87, 0x02}; + + struct { + uint8_t jam_search_len; + uint8_t jam_search_string[2]; + } PACKED payload; + + if (jam_epurse_update) { + payload.jam_search_len = sizeof(update_epurse_sequence); + memcpy(payload.jam_search_string, update_epurse_sequence, sizeof(payload.jam_search_string)); + } + SendCommandNG(CMD_HF_ICLASS_SNIFF, (uint8_t *)&payload, sizeof(payload)); return PM3_SUCCESS; } @@ -2245,9 +2265,9 @@ static int printKeys(void) { PrintAndLogEx(NORMAL, ""); for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++) { if (memcmp(iClass_Key_Table[i], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) - PrintAndLogEx(NORMAL, "%u: %s", i, sprint_hex(iClass_Key_Table[i], 8)); + PrintAndLogEx(INFO, "%u: %s", i, sprint_hex(iClass_Key_Table[i], 8)); else - PrintAndLogEx(NORMAL, "%u: "_YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8)); + PrintAndLogEx(INFO, "%u: "_YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8)); } PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; @@ -2866,12 +2886,14 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { bool isReverse = false; int len = 0; char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_iclass_permutekey(); + if (strlen(Cmd) == 0 || cmdp == 'h') + return usage_hf_iclass_permutekey(); isReverse = (cmdp == 'r'); param_gethex_ex(Cmd, 1, data, &len); - if (len % 2) return usage_hf_iclass_permutekey(); + if (len % 2) + return usage_hf_iclass_permutekey(); len >>= 1; @@ -2881,12 +2903,12 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { generate_rev(data, len); uint8_t key_std_format[8] = {0}; permutekey_rev(key, key_std_format); - PrintAndLogEx(SUCCESS, "holiman iclass key | %s \n", sprint_hex(key_std_format, 8)); + PrintAndLogEx(SUCCESS, "Standard NIST format key " _YELLOW_("%s") " \n", sprint_hex(key_std_format, 8)); } else { generate(data, len); uint8_t key_iclass_format[8] = {0}; permutekey(key, key_iclass_format); - PrintAndLogEx(SUCCESS, "holiman std key | %s \n", sprint_hex(key_iclass_format, 8)); + PrintAndLogEx(SUCCESS, "HID permuted iCLASS format: %s \n", sprint_hex(key_iclass_format, 8)); } return PM3_SUCCESS; } @@ -2959,7 +2981,7 @@ int readIclass(bool loop, bool verbose) { picopass_hdr *hdr = (picopass_hdr *)data; uint16_t length = resp.length; - if ( length != sizeof(picopass_hdr)) + if (length != sizeof(picopass_hdr)) continue; PrintAndLogEx(NORMAL, ""); From ed5471a895040369fc3aa07299235eadc3196345 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Jul 2020 19:40:54 +0200 Subject: [PATCH 034/139] fpga --- armsrc/BigBuf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index f41801a26..4642d0079 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -158,7 +158,10 @@ uint32_t BigBuf_get_traceLen(void) { annotation of commands/responses. **/ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) { - if (!tracing) return false; + if (tracing == false) { + if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("trace is turned off"); } + return false; + } uint8_t *trace = BigBuf_get_addr(); tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + traceLen); @@ -168,6 +171,7 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ // Return when trace is full if (TRACELOG_HDR_LEN + iLen + num_paritybytes >= BigBuf_max_traceLen() - traceLen) { tracing = false; // don't trace any more + if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("trace is full"); } return false; } From 05299373fa42119a8e7e802510cdb2f8b221448b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Jul 2020 19:41:52 +0200 Subject: [PATCH 035/139] fpga --- armsrc/iclass.c | 118 +++++++++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index e01c5a217..478bafa43 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -775,8 +775,9 @@ send: } -/// THE READER CODE -static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) { +// THE READER CODE +// logs. +static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time) { CodeIso15693AsReader(frame, len); TransmitTo15693Tag(ToSend, ToSendMax, start_time); @@ -785,12 +786,16 @@ static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) LogTrace(frame, len, *start_time * 4, end_time * 4, NULL, true); } -static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, +static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* resp, size_t max_resp_size, uint8_t expected_size, uint8_t tries, uint32_t start_time, uint32_t timeout, uint32_t *eof_time) { while (tries-- > 0) { - ReaderTransmitIClass(command, cmdsize, &start_time); + iclass_send_as_reader(cmd, cmdsize, &start_time); + + if (resp == NULL) + return true; + if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time)) { return true; } @@ -812,30 +817,31 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t static uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; static uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; - // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) willbe used + // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used // bit 7: parity. if (use_credit_key) read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; - - uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; uint32_t start_time = GetCountSspClk(); - - ReaderTransmitIClass(act_all, 1, &start_time); + iclass_send_as_reader(act_all, sizeof(act_all), &start_time); // card present? - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) + int len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time); + if (len < 0) { + Dbprintf("Fail act all (%d)", len); return false; + } // send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(identify, 1, &start_time); + iclass_send_as_reader(identify, 1, &start_time); // expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC - uint8_t len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); + if (len != 10) return false; // copy the Anti-collision CSN to our select-packet @@ -843,11 +849,11 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t // select the card start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(select, sizeof(select), &start_time); + iclass_send_as_reader(select, sizeof(select), &start_time); // expect a 10-byte response here, 8 byte CSN and 2 byte CRC len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) + if (len != 10) return false; //Save CSN in response data @@ -855,23 +861,23 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t // card selected, now read config (block1) (only 8 bytes no CRC) start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(read_conf, sizeof(read_conf), &start_time); + iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time); // expect a 8-byte response here len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 8) + if (len != 10) return false; - //Save CC (e-purse) in response data + //Save CONF in response data memcpy(card_data + 8, resp, 8); // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(read_check_cc, sizeof(read_check_cc), &start_time); + iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time); // expect a 8-byte response here len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 8) + if (len != 8) return false; //Save CC (e-purse) in response data @@ -895,31 +901,32 @@ void ReaderIClass(uint8_t flags) { bool flag_read_aia = flags & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) { + switch_off(); Iso15693InitReader(); - } - - if ((flags & FLAG_ICLASS_READER_CLEARTRACE) == FLAG_ICLASS_READER_CLEARTRACE) { - set_tracing(true); - clear_trace(); StartCountSspClk(); } + + if ((flags & FLAG_ICLASS_READER_CLEARTRACE) == FLAG_ICLASS_READER_CLEARTRACE) { + clear_trace(); + } - uint32_t start_time = 0; uint32_t eof_time = 0; - int read_status = select_iclass_tag(card_data, use_credit_key, &eof_time); - if (read_status == 0) { + bool status = select_iclass_tag(card_data, use_credit_key, &eof_time); + if (status == false) { reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); switch_off(); return; } - - uint8_t result_status = FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC; + + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + uint8_t result_status = (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC); //Read block 5, AIA if (flag_read_aia) { //Read App Issuer Area block CRC(0x05) => 0xde 0x64 uint8_t read_aa[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - if (sendCmdGetResponseWithRetries(read_aa, sizeof(read_aa), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { + status = iclass_send_cmd_with_retries(read_aa, sizeof(read_aa), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + if (status) { result_status |= FLAG_ICLASS_AIA; memcpy(card_data + (8 * 5), resp, 8); } else { @@ -994,8 +1001,9 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { //for now replay captured auth (as cc not updated) memcpy(check + 5, mac, 4); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - if (sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time) == false) { + if (iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time) == false) { if (DBGLEVEL >= DBG_EXTENDED) DbpString("Error: Authentication Fail!"); continue; } @@ -1004,7 +1012,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { read[1] = 1; AddCrc(read + 1, 1); - if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time) == false) { + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if (iclass_send_cmd_with_retries(read, sizeof(read), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time) == false) { if (DBGLEVEL >= DBG_EXTENDED) DbpString("Dump config (block 1) failed"); continue; } @@ -1032,7 +1041,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { read[1] = block; AddCrc(read + 1, 1); - if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if (iclass_send_cmd_with_retries(read, sizeof(read), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", block, @@ -1095,7 +1105,7 @@ void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { uint8_t readcheck[] = { keytype, blockno }; uint8_t resp[8] = {0}; uint32_t eof_time = 0; - bool isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + bool isOK = iclass_send_cmd_with_retries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); switch_off(); } @@ -1103,17 +1113,33 @@ void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { // used with function select_and_auth (cmdhficlass.c) // which needs to authenticate before doing more things like read/write void iClass_Authentication(uint8_t *mac) { - uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t resp[ICLASS_BUFFER_SIZE]; + + Iso15693InitReader(); + StartCountSspClk(); + + uint8_t card_data[3 * 8] = {0xFF}; + bool use_credit_key = false; + uint32_t eof_time = 0; + + bool isOK = select_iclass_tag(card_data, use_credit_key, &eof_time); + if (isOK == false) { + reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); + return; + } + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + uint8_t check[9] = { ICLASS_CMD_CHECK }; +// uint8_t mac[4]; +// opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, mac ) // copy MAC to check command (readersignature) check[5] = mac[0]; check[6] = mac[1]; check[7] = mac[2]; check[8] = mac[3]; - //memcpy(check+5, mac, 4); - uint32_t eof_time = 0; - bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + + uint8_t resp[ICLASS_BUFFER_SIZE]; + isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); } @@ -1133,9 +1159,9 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { uint8_t i = 0, isOK = 0; uint8_t lastChunk = ((arg0 >> 8) & 0xFF); bool use_credit_key = ((arg0 >> 16) & 0xFF); - uint8_t keyCount = arg1 & 0xFF; - uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + uint8_t check[9] = { ICLASS_CMD_CHECK }; uint8_t resp[ICLASS_BUFFER_SIZE]; uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; @@ -1188,14 +1214,14 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { check[8] = keys[i].mac[3]; // expect 4bytes, 3 retries times.. - isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); if (isOK) goto out; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; // Auth Sequence MUST begin with reading e-purse. (block2) // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); + iclass_send_as_reader(readcheck_cc, sizeof(readcheck_cc), &start_time); LED_B_OFF(); } @@ -1220,7 +1246,7 @@ static bool iClass_ReadBlock(uint8_t blockno, uint8_t *data) { uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; AddCrc(c + 1, 1); uint32_t eof_time = 0; - bool isOK = sendCmdGetResponseWithRetries(c, sizeof(c), resp, sizeof(resp), 10, 10, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 10, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); memcpy(data, resp, 8); return isOK; } @@ -1286,7 +1312,7 @@ static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { uint8_t resp[10] = {0}; uint32_t eof_time = 0; - bool isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10, 3, 0, ICLASS_READER_TIMEOUT_UPDATE, &eof_time); + bool isOK = iclass_send_cmd_with_retries(write, sizeof(write), resp, sizeof(resp), 10, 3, 0, ICLASS_READER_TIMEOUT_UPDATE, &eof_time); if (isOK == false) { return false; } From 57d1ff931648559c99116b2e56a294f34aa04d4a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Jul 2020 19:41:57 +0200 Subject: [PATCH 036/139] fpga --- armsrc/iso15693.c | 2231 +++++++++++++++++++++++---------------------- 1 file changed, 1120 insertions(+), 1111 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 51dc7fac8..f8214b5e4 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -66,7 +66,7 @@ #include "ticks.h" #include "BigBuf.h" #include "crc16.h" - + // Delays in SSP_CLK ticks. // SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag #define DELAY_READER_TO_ARM 8 @@ -124,43 +124,43 @@ static void BuildInventoryResponse(uint8_t *uid); // n ... length of data void CodeIso15693AsReader(uint8_t *cmd, int n) { - ToSendReset(); + ToSendReset(); - // SOF for 1of4 - ToSend[++ToSendMax] = 0x84; //10000100 + // SOF for 1of4 + ToSend[++ToSendMax] = 0x84; //10000100 - // data - for (int i = 0; i < n; i++) { - for (int j = 0; j < 8; j += 2) { - int these = (cmd[i] >> j) & 0x03; - switch(these) { - case 0: - ToSend[++ToSendMax] = 0x40; //01000000 - break; - case 1: - ToSend[++ToSendMax] = 0x10; //00010000 - break; - case 2: - ToSend[++ToSendMax] = 0x04; //00000100 - break; - case 3: - ToSend[++ToSendMax] = 0x01; //00000001 - break; - } - } - } + // data + for (int i = 0; i < n; i++) { + for (int j = 0; j < 8; j += 2) { + int these = (cmd[i] >> j) & 0x03; + switch(these) { + case 0: + ToSend[++ToSendMax] = 0x40; //01000000 + break; + case 1: + ToSend[++ToSendMax] = 0x10; //00010000 + break; + case 2: + ToSend[++ToSendMax] = 0x04; //00000100 + break; + case 3: + ToSend[++ToSendMax] = 0x01; //00000001 + break; + } + } + } - // EOF - ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding + // EOF + ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - ToSendMax++; + ToSendMax++; } // Encode EOF only static void CodeIso15693AsReaderEOF(void) { - ToSendReset(); - ToSend[++ToSendMax] = 0x20; - ToSendMax++; + ToSendReset(); + ToSend[++ToSendMax] = 0x20; + ToSendMax++; } @@ -169,164 +169,164 @@ static void CodeIso15693AsReaderEOF(void) { // is designed for more robust communication over longer distances static void CodeIso15693AsReader256(uint8_t *cmd, int n) { - ToSendReset(); + ToSendReset(); - // SOF for 1of256 - ToSend[++ToSendMax] = 0x81; //10000001 + // SOF for 1of256 + ToSend[++ToSendMax] = 0x81; //10000001 - // data - for(int i = 0; i < n; i++) { - for (int j = 0; j <= 255; j++) { - if (cmd[i] == j) { - ToSendStuffBit(0); - ToSendStuffBit(1); - } else { - ToSendStuffBit(0); - ToSendStuffBit(0); - } - } - } + // data + for(int i = 0; i < n; i++) { + for (int j = 0; j <= 255; j++) { + if (cmd[i] == j) { + ToSendStuffBit(0); + ToSendStuffBit(1); + } else { + ToSendStuffBit(0); + ToSendStuffBit(0); + } + } + } - // EOF - ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding + // EOF + ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - ToSendMax++; + ToSendMax++; } static const uint8_t encode_4bits[16] = { 0xaa, 0x6a, 0x9a, 0x5a, 0xa6, 0x66, 0x96, 0x56, 0xa9, 0x69, 0x99, 0x59, 0xa5, 0x65, 0x95, 0x55 }; void CodeIso15693AsTag(uint8_t *cmd, size_t len) { - /* - * SOF comprises 3 parts; - * * An unmodulated time of 56.64 us - * * 24 pulses of 423.75 kHz (fc/32) - * * A logic 1, which starts with an unmodulated time of 18.88us - * followed by 8 pulses of 423.75kHz (fc/32) - * - * EOF comprises 3 parts: - * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated - * time of 18.88us. - * - 24 pulses of fc/32 - * - An unmodulated time of 56.64 us - * - * A logic 0 starts with 8 pulses of fc/32 - * followed by an unmodulated time of 256/fc (~18,88us). - * - * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by - * 8 pulses of fc/32 (also 18.88us) - * - * A bit here becomes 8 pulses of fc/32. Therefore: - * The SOF can be written as 00011101 = 0x1D - * The EOF can be written as 10111000 = 0xb8 - * A logic 1 is 01 - * A logic 0 is 10 - * - * */ + /* + * SOF comprises 3 parts; + * * An unmodulated time of 56.64 us + * * 24 pulses of 423.75 kHz (fc/32) + * * A logic 1, which starts with an unmodulated time of 18.88us + * followed by 8 pulses of 423.75kHz (fc/32) + * + * EOF comprises 3 parts: + * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated + * time of 18.88us. + * - 24 pulses of fc/32 + * - An unmodulated time of 56.64 us + * + * A logic 0 starts with 8 pulses of fc/32 + * followed by an unmodulated time of 256/fc (~18,88us). + * + * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by + * 8 pulses of fc/32 (also 18.88us) + * + * A bit here becomes 8 pulses of fc/32. Therefore: + * The SOF can be written as 00011101 = 0x1D + * The EOF can be written as 10111000 = 0xb8 + * A logic 1 is 01 + * A logic 0 is 10 + * + * */ - ToSendReset(); + ToSendReset(); - // SOF - ToSend[++ToSendMax] = 0x1D; // 00011101 + // SOF + ToSend[++ToSendMax] = 0x1D; // 00011101 - // data - for (int i = 0; i < len; i++) { - ToSend[++ToSendMax] = encode_4bits[cmd[i] & 0xF]; - ToSend[++ToSendMax] = encode_4bits[cmd[i] >> 4]; - } + // data + for (int i = 0; i < len; i++) { + ToSend[++ToSendMax] = encode_4bits[cmd[i] & 0xF]; + ToSend[++ToSendMax] = encode_4bits[cmd[i] >> 4]; + } - // EOF - ToSend[++ToSendMax] = 0xB8; // 10111000 + // EOF + ToSend[++ToSendMax] = 0xB8; // 10111000 - ToSendMax++; + ToSendMax++; } // Transmit the command (to the tag) that was placed in cmd[]. void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); - if (*start_time < DELAY_ARM_TO_TAG) { - *start_time = DELAY_ARM_TO_TAG; - } + if (*start_time < DELAY_ARM_TO_TAG) { + *start_time = DELAY_ARM_TO_TAG; + } - *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; + *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; - if (GetCountSspClk() > *start_time) { // we may miss the intended time - *start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time - } + if (GetCountSspClk() > *start_time) { // we may miss the intended time + *start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time + } - while (GetCountSspClk() < *start_time) - /* wait */ ; + while (GetCountSspClk() < *start_time) + /* wait */ ; - LED_B_ON(); - for (int c = 0; c < len; c++) { - uint8_t data = cmd[c]; - for (int i = 0; i < 8; i++) { - uint16_t send_word = (data & 0x80) ? 0xffff : 0x0000; - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - AT91C_BASE_SSC->SSC_THR = send_word; - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - AT91C_BASE_SSC->SSC_THR = send_word; - data <<= 1; - } - WDT_HIT(); - } - LED_B_OFF(); + LED_B_ON(); + for (int c = 0; c < len; c++) { + uint8_t data = cmd[c]; + for (int i = 0; i < 8; i++) { + uint16_t send_word = (data & 0x80) ? 0xffff : 0x0000; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; + data <<= 1; + } + WDT_HIT(); + } + LED_B_OFF(); - *start_time = *start_time + DELAY_ARM_TO_TAG; + *start_time = *start_time + DELAY_ARM_TO_TAG; } //----------------------------------------------------------------------------- -// Transmit the command (to the reader) that was placed in cmd[]. +// Transmit the tag response (to the reader) that was placed in cmd[]. //----------------------------------------------------------------------------- void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow) { - // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); + // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); - uint32_t modulation_start_time = *start_time - DELAY_ARM_TO_READER + 3 * 8; // no need to transfer the unmodulated start of SOF + uint32_t modulation_start_time = *start_time - DELAY_ARM_TO_READER + 3 * 8; // no need to transfer the unmodulated start of SOF - while (GetCountSspClk() > (modulation_start_time & 0xfffffff8) + 3) { // we will miss the intended time - if (slot_time) { - modulation_start_time += slot_time; // use next available slot - } else { - modulation_start_time = (modulation_start_time & 0xfffffff8) + 8; // next possible time - } - } + while (GetCountSspClk() > (modulation_start_time & 0xfffffff8) + 3) { // we will miss the intended time + if (slot_time) { + modulation_start_time += slot_time; // use next available slot + } else { + modulation_start_time = (modulation_start_time & 0xfffffff8) + 8; // next possible time + } + } - while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) - /* wait */ ; + while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) + /* wait */ ; - uint8_t shift_delay = modulation_start_time & 0x00000007; + uint8_t shift_delay = modulation_start_time & 0x00000007; - *start_time = modulation_start_time + DELAY_ARM_TO_READER - 3 * 8; + *start_time = modulation_start_time + DELAY_ARM_TO_READER - 3 * 8; - LED_C_ON(); - uint8_t bits_to_shift = 0x00; - uint8_t bits_to_send = 0x00; - for (size_t c = 0; c < len; c++) { - for (int i = (c==0?4:7); i >= 0; i--) { - uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; - for (int j = 0; j < (slow?4:1); ) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; - AT91C_BASE_SSC->SSC_THR = bits_to_send; - bits_to_shift = cmd_bits; - j++; - } - } - } - WDT_HIT(); - } - // send the remaining bits, padded with 0: - bits_to_send = bits_to_shift << (8 - shift_delay); - for ( ; ; ) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = bits_to_send; - break; - } - } - LED_C_OFF(); + LED_C_ON(); + uint8_t bits_to_shift = 0x00; + uint8_t bits_to_send = 0x00; + for (size_t c = 0; c < len; c++) { + for (int i = (c==0?4:7); i >= 0; i--) { + uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; + for (int j = 0; j < (slow?4:1); ) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; + AT91C_BASE_SSC->SSC_THR = bits_to_send; + bits_to_shift = cmd_bits; + j++; + } + } + } + WDT_HIT(); + } + // send the remaining bits, padded with 0: + bits_to_send = bits_to_shift << (8 - shift_delay); + for ( ; ; ) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = bits_to_send; + break; + } + } + LED_C_OFF(); } //============================================================================= @@ -347,270 +347,271 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, #define MAX_PREVIOUS_AMPLITUDE (-1 - NOISE_THRESHOLD) typedef struct DecodeTag { - enum { - STATE_TAG_SOF_LOW, - STATE_TAG_SOF_RISING_EDGE, - STATE_TAG_SOF_HIGH, - STATE_TAG_SOF_HIGH_END, - STATE_TAG_RECEIVING_DATA, - STATE_TAG_EOF, - STATE_TAG_EOF_TAIL - } state; - int bitCount; - int posCount; - enum { - LOGIC0, - LOGIC1, - SOF_PART1, - SOF_PART2 - } lastBit; - uint16_t shiftReg; - uint16_t max_len; - uint8_t *output; - int len; - int sum1, sum2; - int threshold_sof; - int threshold_half; - uint16_t previous_amplitude; + enum { + STATE_TAG_SOF_LOW, + STATE_TAG_SOF_RISING_EDGE, + STATE_TAG_SOF_HIGH, + STATE_TAG_SOF_HIGH_END, + STATE_TAG_RECEIVING_DATA, + STATE_TAG_EOF, + STATE_TAG_EOF_TAIL + } state; + int bitCount; + int posCount; + enum { + LOGIC0, + LOGIC1, + SOF_PART1, + SOF_PART2 + } lastBit; + uint16_t shiftReg; + uint16_t max_len; + uint8_t *output; + int len; + int sum1; + int sum2; + int threshold_sof; + int threshold_half; + uint16_t previous_amplitude; } DecodeTag_t; //----------------------------------------------------------------------------- // DEMODULATE tag answer //----------------------------------------------------------------------------- static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { - switch (DecodeTag->state) { - case STATE_TAG_SOF_LOW: - // waiting for a rising edge - if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) { - if (DecodeTag->posCount > 10) { - DecodeTag->threshold_sof = amplitude - DecodeTag->previous_amplitude; // to be divided by 2 - DecodeTag->threshold_half = 0; - DecodeTag->state = STATE_TAG_SOF_RISING_EDGE; - } else { - DecodeTag->posCount = 0; - } - } else { - DecodeTag->posCount++; - DecodeTag->previous_amplitude = amplitude; - } - break; + switch (DecodeTag->state) { + case STATE_TAG_SOF_LOW: + // waiting for a rising edge + if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) { + if (DecodeTag->posCount > 10) { + DecodeTag->threshold_sof = amplitude - DecodeTag->previous_amplitude; // to be divided by 2 + DecodeTag->threshold_half = 0; + DecodeTag->state = STATE_TAG_SOF_RISING_EDGE; + } else { + DecodeTag->posCount = 0; + } + } else { + DecodeTag->posCount++; + DecodeTag->previous_amplitude = amplitude; + } + break; - case STATE_TAG_SOF_RISING_EDGE: - if (amplitude > DecodeTag->threshold_sof + DecodeTag->previous_amplitude) { // edge still rising - if (amplitude > DecodeTag->threshold_sof + DecodeTag->threshold_sof) { // steeper edge, take this as time reference - DecodeTag->posCount = 1; - } else { - DecodeTag->posCount = 2; - } - DecodeTag->threshold_sof = (amplitude - DecodeTag->previous_amplitude) / 2; - } else { - DecodeTag->posCount = 2; - DecodeTag->threshold_sof = DecodeTag->threshold_sof/2; - } - // DecodeTag->posCount = 2; - DecodeTag->state = STATE_TAG_SOF_HIGH; - break; + case STATE_TAG_SOF_RISING_EDGE: + if (amplitude > DecodeTag->threshold_sof + DecodeTag->previous_amplitude) { // edge still rising + if (amplitude > DecodeTag->threshold_sof + DecodeTag->threshold_sof) { // steeper edge, take this as time reference + DecodeTag->posCount = 1; + } else { + DecodeTag->posCount = 2; + } + DecodeTag->threshold_sof = (amplitude - DecodeTag->previous_amplitude) / 2; + } else { + DecodeTag->posCount = 2; + DecodeTag->threshold_sof = DecodeTag->threshold_sof/2; + } + // DecodeTag->posCount = 2; + DecodeTag->state = STATE_TAG_SOF_HIGH; + break; - case STATE_TAG_SOF_HIGH: - // waiting for 10 times high. Take average over the last 8 - if (amplitude > DecodeTag->threshold_sof) { - DecodeTag->posCount++; - if (DecodeTag->posCount > 2) { - DecodeTag->threshold_half += amplitude; // keep track of average high value - } - if (DecodeTag->posCount == 10) { - DecodeTag->threshold_half >>= 2; // (4 times 1/2 average) - DecodeTag->state = STATE_TAG_SOF_HIGH_END; - } - } else { // high phase was too short - DecodeTag->posCount = 1; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - } - break; + case STATE_TAG_SOF_HIGH: + // waiting for 10 times high. Take average over the last 8 + if (amplitude > DecodeTag->threshold_sof) { + DecodeTag->posCount++; + if (DecodeTag->posCount > 2) { + DecodeTag->threshold_half += amplitude; // keep track of average high value + } + if (DecodeTag->posCount == 10) { + DecodeTag->threshold_half >>= 2; // (4 times 1/2 average) + DecodeTag->state = STATE_TAG_SOF_HIGH_END; + } + } else { // high phase was too short + DecodeTag->posCount = 1; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + } + break; - case STATE_TAG_SOF_HIGH_END: - // check for falling edge - if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) { - DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) - DecodeTag->shiftReg = 0; - DecodeTag->bitCount = 0; - DecodeTag->len = 0; - DecodeTag->sum1 = amplitude; - DecodeTag->sum2 = 0; - DecodeTag->posCount = 2; - DecodeTag->state = STATE_TAG_RECEIVING_DATA; - // FpgaDisableTracing(); // DEBUGGING - // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", - // amplitude, - // DecodeTag->threshold_sof, - // DecodeTag->threshold_half/4, - // DecodeTag->previous_amplitude); // DEBUGGING - LED_C_ON(); - } else { - DecodeTag->posCount++; - if (DecodeTag->posCount > 13) { // high phase too long - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } - break; + case STATE_TAG_SOF_HIGH_END: + // check for falling edge + if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) { + DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) + DecodeTag->shiftReg = 0; + DecodeTag->bitCount = 0; + DecodeTag->len = 0; + DecodeTag->sum1 = amplitude; + DecodeTag->sum2 = 0; + DecodeTag->posCount = 2; + DecodeTag->state = STATE_TAG_RECEIVING_DATA; + // FpgaDisableTracing(); // DEBUGGING + // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", + // amplitude, + // DecodeTag->threshold_sof, + // DecodeTag->threshold_half/4, + // DecodeTag->previous_amplitude); // DEBUGGING + LED_C_ON(); + } else { + DecodeTag->posCount++; + if (DecodeTag->posCount > 13) { // high phase too long + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + break; - case STATE_TAG_RECEIVING_DATA: - // FpgaDisableTracing(); // DEBUGGING - // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", - // amplitude, - // DecodeTag->threshold_sof, - // DecodeTag->threshold_half/4, - // DecodeTag->previous_amplitude); // DEBUGGING - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; - } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; - } else { - DecodeTag->sum2 += amplitude; - } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in both halves - if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF - DecodeTag->state = STATE_TAG_EOF; - } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } else if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in second half - // logic 1 - if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF - DecodeTag->lastBit = SOF_PART2; // SOF completed - } else { - DecodeTag->lastBit = LOGIC1; - DecodeTag->shiftReg >>= 1; - DecodeTag->shiftReg |= 0x80; - DecodeTag->bitCount++; - if (DecodeTag->bitCount == 8) { - DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; - DecodeTag->len++; - // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING - if (DecodeTag->len > DecodeTag->max_len) { - // buffer overflow, give up - LED_C_OFF(); - return true; - } - DecodeTag->bitCount = 0; - DecodeTag->shiftReg = 0; - } - } - } else if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half - // logic 0 - if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } else { - DecodeTag->lastBit = LOGIC0; - DecodeTag->shiftReg >>= 1; - DecodeTag->bitCount++; - if (DecodeTag->bitCount == 8) { - DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; - DecodeTag->len++; - // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING - if (DecodeTag->len > DecodeTag->max_len) { - // buffer overflow, give up - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - DecodeTag->bitCount = 0; - DecodeTag->shiftReg = 0; - } - } - } else { // no modulation - if (DecodeTag->lastBit == SOF_PART2) { // only SOF (this is OK for iClass) - LED_C_OFF(); - return true; - } else { - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } - DecodeTag->posCount = 0; - } - DecodeTag->posCount++; - break; + case STATE_TAG_RECEIVING_DATA: + // FpgaDisableTracing(); // DEBUGGING + // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", + // amplitude, + // DecodeTag->threshold_sof, + // DecodeTag->threshold_half/4, + // DecodeTag->previous_amplitude); // DEBUGGING + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; + } + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += amplitude; + } else { + DecodeTag->sum2 += amplitude; + } + if (DecodeTag->posCount == 8) { + if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in both halves + if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF + DecodeTag->state = STATE_TAG_EOF; + } else { + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } else if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in second half + // logic 1 + if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF + DecodeTag->lastBit = SOF_PART2; // SOF completed + } else { + DecodeTag->lastBit = LOGIC1; + DecodeTag->shiftReg >>= 1; + DecodeTag->shiftReg |= 0x80; + DecodeTag->bitCount++; + if (DecodeTag->bitCount == 8) { + DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; + DecodeTag->len++; + // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING + if (DecodeTag->len > DecodeTag->max_len) { + // buffer overflow, give up + LED_C_OFF(); + return true; + } + DecodeTag->bitCount = 0; + DecodeTag->shiftReg = 0; + } + } + } else if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half + // logic 0 + if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } else { + DecodeTag->lastBit = LOGIC0; + DecodeTag->shiftReg >>= 1; + DecodeTag->bitCount++; + if (DecodeTag->bitCount == 8) { + DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; + DecodeTag->len++; + // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING + if (DecodeTag->len > DecodeTag->max_len) { + // buffer overflow, give up + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + DecodeTag->bitCount = 0; + DecodeTag->shiftReg = 0; + } + } + } else { // no modulation + if (DecodeTag->lastBit == SOF_PART2) { // only SOF (this is OK for iClass) + LED_C_OFF(); + return true; + } else { + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + DecodeTag->posCount = 0; + } + DecodeTag->posCount++; + break; - case STATE_TAG_EOF: - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; - } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; - } else { - DecodeTag->sum2 += amplitude; - } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_EOF_TAIL; - } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } - DecodeTag->posCount++; - break; + case STATE_TAG_EOF: + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; + } + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += amplitude; + } else { + DecodeTag->sum2 += amplitude; + } + if (DecodeTag->posCount == 8) { + if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_EOF_TAIL; + } else { + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + DecodeTag->posCount++; + break; - case STATE_TAG_EOF_TAIL: - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; - } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; - } else { - DecodeTag->sum2 += amplitude; - } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // no modulation in both halves - LED_C_OFF(); - return true; - } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } - DecodeTag->posCount++; - break; - } + case STATE_TAG_EOF_TAIL: + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; + } + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += amplitude; + } else { + DecodeTag->sum2 += amplitude; + } + if (DecodeTag->posCount == 8) { + if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // no modulation in both halves + LED_C_OFF(); + return true; + } else { + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = amplitude; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + DecodeTag->posCount++; + break; + } - return false; + return false; } static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) { - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; - DecodeTag->output = data; - DecodeTag->max_len = max_len; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + DecodeTag->output = data; + DecodeTag->max_len = max_len; } static void DecodeTagReset(DecodeTag_t *DecodeTag) { - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; } @@ -619,90 +620,97 @@ static void DecodeTagReset(DecodeTag_t *DecodeTag) { */ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { - int samples = 0; - int ret = 0; + int samples = 0; + int ret = 0; - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - // the Decoder data structure - DecodeTag_t DecodeTag = { 0 }; - DecodeTagInit(&DecodeTag, response, max_len); + // the Decoder data structure + DecodeTag_t DecodeTag = { 0 }; + DecodeTagInit(&DecodeTag, response, max_len); - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); - // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); + // And put the FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); - // Setup and start DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - uint32_t dma_start_time = 0; - uint16_t *upTo = dmaBuf; + // Setup and start DMA. + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + uint32_t dma_start_time = 0; + uint16_t *upTo = dmaBuf; - for(;;) { - uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + for(;;) { + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - if (behindBy == 0) continue; + if (behindBy == 0) continue; - samples++; - if (samples == 1) { - // DMA has transferred the very first data - dma_start_time = GetCountSspClk() & 0xfffffff0; - } + samples++; + if (samples == 1) { + // DMA has transferred the very first data + dma_start_time = GetCountSspClk() & 0xfffffff0; + } - uint16_t tagdata = *upTo++; + uint16_t tagdata = *upTo++; - if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); - ret = -1; - break; - } - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers - } + if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if (behindBy > (9 * ISO15693_DMA_BUFFER_SIZE / 10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + ret = -1; + break; + } + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + } - if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) { - *eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM; // end of EOF - if (DecodeTag.lastBit == SOF_PART2) { - *eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) - } - if (DecodeTag.len > DecodeTag.max_len) { - ret = -2; // buffer overflow - } - break; - } + if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) { + *eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM; // end of EOF + if (DecodeTag.lastBit == SOF_PART2) { + *eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) + } + if (DecodeTag.len > DecodeTag.max_len) { + ret = -2; // buffer overflow + } + break; + } - if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { - ret = -1; // timeout - break; - } + if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { + ret = -1; // timeout + break; + } - } + } - FpgaDisableSscDma(); + FpgaDisableSscDma(); - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d", - samples, ret, DecodeTag.state, DecodeTag.lastBit, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); + uint32_t sof_time = *eof_time + - DecodeTag.len * 8 * 8 * 16 // time for byte transfers + - 32 * 16 // time for SOF transfer + - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer - if (ret < 0) { - return ret; - } + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d", + samples, + ret, + DecodeTag.state, + DecodeTag.lastBit, + DecodeTag.len, + DecodeTag.bitCount, + DecodeTag.posCount + ); + Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); + } - uint32_t sof_time = *eof_time - - DecodeTag.len * 8 * 8 * 16 // time for byte transfers - - 32 * 16 // time for SOF transfer - - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer + LogTrace(DecodeTag.output, DecodeTag.len, (sof_time * 4), (*eof_time * 4), NULL, false); - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("timing: sof_time = %d, eof_time = %d", sof_time, *eof_time); - - LogTrace(DecodeTag.output, DecodeTag.len, sof_time*4, *eof_time*4, NULL, false); - - return DecodeTag.len; + if (ret < 0) { + return ret; + } + return DecodeTag.len; } @@ -720,279 +728,279 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo //============================================================================= typedef struct DecodeReader { - enum { - STATE_READER_UNSYNCD, - STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF, - STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF, - STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF, - STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF, - STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4, - STATE_READER_RECEIVE_DATA_1_OUT_OF_4, - STATE_READER_RECEIVE_DATA_1_OUT_OF_256, - STATE_READER_RECEIVE_JAMMING - } state; - enum { - CODING_1_OUT_OF_4, - CODING_1_OUT_OF_256 - } Coding; - uint8_t shiftReg; - uint8_t bitCount; - int byteCount; - int byteCountMax; - int posCount; - int sum1, sum2; - uint8_t *output; - uint8_t jam_search_len; - uint8_t *jam_search_string; + enum { + STATE_READER_UNSYNCD, + STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF, + STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF, + STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF, + STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF, + STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4, + STATE_READER_RECEIVE_DATA_1_OUT_OF_4, + STATE_READER_RECEIVE_DATA_1_OUT_OF_256, + STATE_READER_RECEIVE_JAMMING + } state; + enum { + CODING_1_OUT_OF_4, + CODING_1_OUT_OF_256 + } Coding; + uint8_t shiftReg; + uint8_t bitCount; + int byteCount; + int byteCountMax; + int posCount; + int sum1, sum2; + uint8_t *output; + uint8_t jam_search_len; + uint8_t *jam_search_string; } DecodeReader_t; static void DecodeReaderInit(DecodeReader_t* DecodeReader, uint8_t *data, uint16_t max_len, uint8_t jam_search_len, uint8_t *jam_search_string) { - DecodeReader->output = data; - DecodeReader->byteCountMax = max_len; - DecodeReader->state = STATE_READER_UNSYNCD; - DecodeReader->byteCount = 0; - DecodeReader->bitCount = 0; - DecodeReader->posCount = 1; - DecodeReader->shiftReg = 0; - DecodeReader->jam_search_len = jam_search_len; - DecodeReader->jam_search_string = jam_search_string; + DecodeReader->output = data; + DecodeReader->byteCountMax = max_len; + DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReader->byteCount = 0; + DecodeReader->bitCount = 0; + DecodeReader->posCount = 1; + DecodeReader->shiftReg = 0; + DecodeReader->jam_search_len = jam_search_len; + DecodeReader->jam_search_string = jam_search_string; } static void DecodeReaderReset(DecodeReader_t* DecodeReader) { - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReader->state = STATE_READER_UNSYNCD; } static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeReader) { - switch (DecodeReader->state) { - case STATE_READER_UNSYNCD: - // wait for unmodulated carrier - if (bit) { - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } - break; + switch (DecodeReader->state) { + case STATE_READER_UNSYNCD: + // wait for unmodulated carrier + if (bit) { + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } + break; - case STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF: - if (!bit) { - // we went low, so this could be the beginning of a SOF - DecodeReader->posCount = 1; - DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; - } - break; + case STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF: + if (!bit) { + // we went low, so this could be the beginning of a SOF + DecodeReader->posCount = 1; + DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; + } + break; - case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF: - DecodeReader->posCount++; - if (bit) { // detected rising edge - if (DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { // SOF - DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; - } - } else { - if (DecodeReader->posCount > 5) { // stayed low for too long - DecodeReaderReset(DecodeReader); - } else { - // do nothing, keep waiting - } - } - break; + case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF: + DecodeReader->posCount++; + if (bit) { // detected rising edge + if (DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { // SOF + DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; + } + } else { + if (DecodeReader->posCount > 5) { // stayed low for too long + DecodeReaderReset(DecodeReader); + } else { + // do nothing, keep waiting + } + } + break; - case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF: - DecodeReader->posCount++; - if (!bit) { // detected a falling edge - if (DecodeReader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) - DecodeReaderReset(DecodeReader); - } else if (DecodeReader->posCount < 23) { // SOF for 1 out of 4 coding - DecodeReader->Coding = CODING_1_OUT_OF_4; - DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; - } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) - DecodeReaderReset(DecodeReader); - } else { // SOF for 1 out of 256 coding - DecodeReader->Coding = CODING_1_OUT_OF_256; - DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; - } - } else { - if (DecodeReader->posCount > 29) { // stayed high for too long - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { - // do nothing, keep waiting - } - } - break; + case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF: + DecodeReader->posCount++; + if (!bit) { // detected a falling edge + if (DecodeReader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) + DecodeReaderReset(DecodeReader); + } else if (DecodeReader->posCount < 23) { // SOF for 1 out of 4 coding + DecodeReader->Coding = CODING_1_OUT_OF_4; + DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) + DecodeReaderReset(DecodeReader); + } else { // SOF for 1 out of 256 coding + DecodeReader->Coding = CODING_1_OUT_OF_256; + DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + } + } else { + if (DecodeReader->posCount > 29) { // stayed high for too long + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { + // do nothing, keep waiting + } + } + break; - case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF: - DecodeReader->posCount++; - if (bit) { // detected rising edge - if (DecodeReader->Coding == CODING_1_OUT_OF_256) { - if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { - DecodeReader->posCount = 1; - DecodeReader->bitCount = 0; - DecodeReader->byteCount = 0; - DecodeReader->sum1 = 1; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; - LED_B_ON(); - } - } else { // CODING_1_OUT_OF_4 - if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { - DecodeReader->posCount = 1; - DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; - } - } - } else { - if (DecodeReader->Coding == CODING_1_OUT_OF_256) { - if (DecodeReader->posCount > 34) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); - } else { - // do nothing, keep waiting - } - } else { // CODING_1_OUT_OF_4 - if (DecodeReader->posCount > 26) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); - } else { - // do nothing, keep waiting - } - } - } - break; + case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF: + DecodeReader->posCount++; + if (bit) { // detected rising edge + if (DecodeReader->Coding == CODING_1_OUT_OF_256) { + if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { + DecodeReader->posCount = 1; + DecodeReader->bitCount = 0; + DecodeReader->byteCount = 0; + DecodeReader->sum1 = 1; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; + LED_B_ON(); + } + } else { // CODING_1_OUT_OF_4 + if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { + DecodeReader->posCount = 1; + DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; + } + } + } else { + if (DecodeReader->Coding == CODING_1_OUT_OF_256) { + if (DecodeReader->posCount > 34) { // signal stayed low for too long + DecodeReaderReset(DecodeReader); + } else { + // do nothing, keep waiting + } + } else { // CODING_1_OUT_OF_4 + if (DecodeReader->posCount > 26) { // signal stayed low for too long + DecodeReaderReset(DecodeReader); + } else { + // do nothing, keep waiting + } + } + } + break; - case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: - DecodeReader->posCount++; - if (bit) { - if (DecodeReader->posCount == 9) { - DecodeReader->posCount = 1; - DecodeReader->bitCount = 0; - DecodeReader->byteCount = 0; - DecodeReader->sum1 = 1; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; - LED_B_ON(); - } else { - // do nothing, keep waiting - } - } else { // unexpected falling edge - DecodeReaderReset(DecodeReader); - } - break; + case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: + DecodeReader->posCount++; + if (bit) { + if (DecodeReader->posCount == 9) { + DecodeReader->posCount = 1; + DecodeReader->bitCount = 0; + DecodeReader->byteCount = 0; + DecodeReader->sum1 = 1; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; + LED_B_ON(); + } else { + // do nothing, keep waiting + } + } else { // unexpected falling edge + DecodeReaderReset(DecodeReader); + } + break; - case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: - DecodeReader->posCount++; - if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit?1:0; - } else if (DecodeReader->posCount <= 4) { - if (bit) DecodeReader->sum1++; - } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit?1:0; - } else { - if (bit) DecodeReader->sum2++; - } - if (DecodeReader->posCount == 8) { - DecodeReader->posCount = 0; - if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF - LED_B_OFF(); // Finished receiving - DecodeReaderReset(DecodeReader); - if (DecodeReader->byteCount != 0) { - return true; - } - } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected a 2bit position - DecodeReader->shiftReg >>= 2; - DecodeReader->shiftReg |= (DecodeReader->bitCount << 6); - } - if (DecodeReader->bitCount == 15) { // we have a full byte - DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; - if (DecodeReader->byteCount > DecodeReader->byteCountMax) { - // buffer overflow, give up - LED_B_OFF(); - DecodeReaderReset(DecodeReader); - } - DecodeReader->bitCount = 0; - DecodeReader->shiftReg = 0; - if (DecodeReader->byteCount == DecodeReader->jam_search_len) { - if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); - DecodeReader->state = STATE_READER_RECEIVE_JAMMING; - } - } - } else { - DecodeReader->bitCount++; - } - } - break; + case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: + DecodeReader->posCount++; + if (DecodeReader->posCount == 1) { + DecodeReader->sum1 = bit?1:0; + } else if (DecodeReader->posCount <= 4) { + if (bit) DecodeReader->sum1++; + } else if (DecodeReader->posCount == 5) { + DecodeReader->sum2 = bit?1:0; + } else { + if (bit) DecodeReader->sum2++; + } + if (DecodeReader->posCount == 8) { + DecodeReader->posCount = 0; + if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF + LED_B_OFF(); // Finished receiving + DecodeReaderReset(DecodeReader); + if (DecodeReader->byteCount != 0) { + return true; + } + } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected a 2bit position + DecodeReader->shiftReg >>= 2; + DecodeReader->shiftReg |= (DecodeReader->bitCount << 6); + } + if (DecodeReader->bitCount == 15) { // we have a full byte + DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; + if (DecodeReader->byteCount > DecodeReader->byteCountMax) { + // buffer overflow, give up + LED_B_OFF(); + DecodeReaderReset(DecodeReader); + } + DecodeReader->bitCount = 0; + DecodeReader->shiftReg = 0; + if (DecodeReader->byteCount == DecodeReader->jam_search_len) { + if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); + DecodeReader->state = STATE_READER_RECEIVE_JAMMING; + } + } + } else { + DecodeReader->bitCount++; + } + } + break; - case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: - DecodeReader->posCount++; - if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit?1:0; - } else if (DecodeReader->posCount <= 4) { - if (bit) DecodeReader->sum1++; - } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit?1:0; - } else if (bit) { - DecodeReader->sum2++; - } - if (DecodeReader->posCount == 8) { - DecodeReader->posCount = 0; - if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF - LED_B_OFF(); // Finished receiving - DecodeReaderReset(DecodeReader); - if (DecodeReader->byteCount != 0) { - return true; - } - } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected the bit position - DecodeReader->shiftReg = DecodeReader->bitCount; - } - if (DecodeReader->bitCount == 255) { // we have a full byte - DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; - if (DecodeReader->byteCount > DecodeReader->byteCountMax) { - // buffer overflow, give up - LED_B_OFF(); - DecodeReaderReset(DecodeReader); - } - if (DecodeReader->byteCount == DecodeReader->jam_search_len) { - if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); - DecodeReader->state = STATE_READER_RECEIVE_JAMMING; - } - } - } - DecodeReader->bitCount++; - } - break; + case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: + DecodeReader->posCount++; + if (DecodeReader->posCount == 1) { + DecodeReader->sum1 = bit?1:0; + } else if (DecodeReader->posCount <= 4) { + if (bit) DecodeReader->sum1++; + } else if (DecodeReader->posCount == 5) { + DecodeReader->sum2 = bit?1:0; + } else if (bit) { + DecodeReader->sum2++; + } + if (DecodeReader->posCount == 8) { + DecodeReader->posCount = 0; + if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF + LED_B_OFF(); // Finished receiving + DecodeReaderReset(DecodeReader); + if (DecodeReader->byteCount != 0) { + return true; + } + } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected the bit position + DecodeReader->shiftReg = DecodeReader->bitCount; + } + if (DecodeReader->bitCount == 255) { // we have a full byte + DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; + if (DecodeReader->byteCount > DecodeReader->byteCountMax) { + // buffer overflow, give up + LED_B_OFF(); + DecodeReaderReset(DecodeReader); + } + if (DecodeReader->byteCount == DecodeReader->jam_search_len) { + if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); + DecodeReader->state = STATE_READER_RECEIVE_JAMMING; + } + } + } + DecodeReader->bitCount++; + } + break; - case STATE_READER_RECEIVE_JAMMING: - DecodeReader->posCount++; - if (DecodeReader->Coding == CODING_1_OUT_OF_4) { - if (DecodeReader->posCount == 7*16) { // 7 bits jammed - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming - // FpgaDisableTracing(); - LED_D_OFF(); - } else if (DecodeReader->posCount == 8*16) { - DecodeReader->posCount = 0; - DecodeReader->output[DecodeReader->byteCount++] = 0x00; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; - } - } else { - if (DecodeReader->posCount == 7*256) { // 7 bits jammend - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming - LED_D_OFF(); - } else if (DecodeReader->posCount == 8*256) { - DecodeReader->posCount = 0; - DecodeReader->output[DecodeReader->byteCount++] = 0x00; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; - } - } - break; + case STATE_READER_RECEIVE_JAMMING: + DecodeReader->posCount++; + if (DecodeReader->Coding == CODING_1_OUT_OF_4) { + if (DecodeReader->posCount == 7*16) { // 7 bits jammed + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming + // FpgaDisableTracing(); + LED_D_OFF(); + } else if (DecodeReader->posCount == 8*16) { + DecodeReader->posCount = 0; + DecodeReader->output[DecodeReader->byteCount++] = 0x00; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; + } + } else { + if (DecodeReader->posCount == 7*256) { // 7 bits jammend + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming + LED_D_OFF(); + } else if (DecodeReader->posCount == 8*256) { + DecodeReader->posCount = 0; + DecodeReader->output[DecodeReader->byteCount++] = 0x00; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; + } + } + break; - default: - LED_B_OFF(); - DecodeReaderReset(DecodeReader); - break; - } + default: + LED_B_OFF(); + DecodeReaderReset(DecodeReader); + break; + } - return false; + return false; } //----------------------------------------------------------------------------- @@ -1006,86 +1014,86 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR //----------------------------------------------------------------------------- int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) { - int samples = 0; - bool gotFrame = false; - uint8_t b; + int samples = 0; + bool gotFrame = false; + uint8_t b; - uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - // the decoder data structure - DecodeReader_t DecodeReader = {0}; - DecodeReaderInit(&DecodeReader, received, max_len, 0, NULL); + // the decoder data structure + DecodeReader_t DecodeReader = {0}; + DecodeReaderInit(&DecodeReader, received, max_len, 0, NULL); - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); - // clear receive register and wait for next transfer - uint32_t temp = AT91C_BASE_SSC->SSC_RHR; - (void) temp; - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; + // clear receive register and wait for next transfer + uint32_t temp = AT91C_BASE_SSC->SSC_RHR; + (void) temp; + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; - uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8; + uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8; - // Setup and start DMA. - FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE); - uint8_t *upTo = dmaBuf; + // Setup and start DMA. + FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE); + uint8_t *upTo = dmaBuf; - for (;;) { - uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + for (;;) { + uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - if (behindBy == 0) continue; + if (behindBy == 0) continue; - b = *upTo++; - if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); - break; - } - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers - } + b = *upTo++; + if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + break; + } + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + } - for (int i = 7; i >= 0; i--) { - if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { - *eof_time = dma_start_time + samples - DELAY_READER_TO_ARM; // end of EOF - gotFrame = true; - break; - } - samples++; - } + for (int i = 7; i >= 0; i--) { + if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { + *eof_time = dma_start_time + samples - DELAY_READER_TO_ARM; // end of EOF + gotFrame = true; + break; + } + samples++; + } - if (gotFrame) { - break; - } + if (gotFrame) { + break; + } - if (BUTTON_PRESS()) { - DecodeReader.byteCount = -1; - break; - } + if (BUTTON_PRESS()) { + DecodeReader.byteCount = -1; + break; + } - WDT_HIT(); - } + WDT_HIT(); + } - FpgaDisableSscDma(); + FpgaDisableSscDma(); - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", + samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); - if (DecodeReader.byteCount > 0) { - uint32_t sof_time = *eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers - - 32 // time for SOF transfer - - 16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*32, *eof_time*32, NULL, true); - } + if (DecodeReader.byteCount > 0) { + uint32_t sof_time = *eof_time + - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers + - 32 // time for SOF transfer + - 16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*32, *eof_time*32, NULL, true); + } - return DecodeReader.byteCount; + return DecodeReader.byteCount; } //----------------------------------------------------------------------------- @@ -1094,214 +1102,211 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo // so that it can be downloaded to a PC and processed there. //----------------------------------------------------------------------------- void AcquireRawAdcSamplesIso15693(void) { - LED_A_ON(); + LED_A_ON(); + uint8_t *dest = BigBuf_malloc(4000); - //iceman: needs malloc - uint8_t *dest = BigBuf_get_addr(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + LED_D_ON(); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); - LED_D_ON(); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + uint8_t cmd[5]; + BuildIdentifyRequest(cmd); + CodeIso15693AsReader(cmd, sizeof(cmd)); - uint8_t cmd[5]; - BuildIdentifyRequest(cmd); - CodeIso15693AsReader(cmd, sizeof(cmd)); + // Give the tags time to energize + SpinDelay(100); - // Give the tags time to energize - SpinDelay(100); + // Now send the command + uint32_t start_time = 0; + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); - // Now send the command - uint32_t start_time = 0; - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ; - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); + for(int c = 0; c < 4000; ) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + uint16_t r = AT91C_BASE_SSC->SSC_RHR; + dest[c++] = r >> 5; + } + } - for(int c = 0; c < 4000; ) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint16_t r = AT91C_BASE_SSC->SSC_RHR; - dest[c++] = r >> 5; - } - } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { - LED_A_ON(); + LED_A_ON(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - clear_trace(); - set_tracing(true); + clear_trace(); + set_tracing(true); - // The DMA buffer, used to stream samples from the FPGA - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + // The DMA buffer, used to stream samples from the FPGA + uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - // Count of samples received so far, so that we can include timing - // information in the trace buffer. - int samples = 0; + // Count of samples received so far, so that we can include timing + // information in the trace buffer. + int samples = 0; - DecodeTag_t DecodeTag = {0}; - uint8_t response[ISO15693_MAX_RESPONSE_LENGTH]; - DecodeTagInit(&DecodeTag, response, sizeof(response)); + DecodeTag_t DecodeTag = {0}; + uint8_t response[ISO15693_MAX_RESPONSE_LENGTH]; + DecodeTagInit(&DecodeTag, response, sizeof(response)); - DecodeReader_t DecodeReader = {0}; - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; - DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd), jam_search_len, jam_search_string); + DecodeReader_t DecodeReader = {0}; + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd), jam_search_len, jam_search_string); - // Print some debug information about the buffer sizes - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("Sniffing buffers initialized:"); - Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); - Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); - Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); - Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); - } + // Print some debug information about the buffer sizes + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("Sniffing buffers initialized:"); + Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); + Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); + Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); + Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); + } - Dbprintf("Sniff started. Press PM3 Button to stop."); + Dbprintf("Sniff started. Press PM3 Button to stop."); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); - LED_D_OFF(); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - StartCountSspClk(); - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); + LED_D_OFF(); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + StartCountSspClk(); + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - bool TagIsActive = false; - bool ReaderIsActive = false; - bool ExpectTagAnswer = false; - uint32_t dma_start_time = 0; - uint16_t *upTo = dmaBuf; + bool TagIsActive = false; + bool ReaderIsActive = false; + bool ExpectTagAnswer = false; + uint32_t dma_start_time = 0; + uint16_t *upTo = dmaBuf; - uint16_t max_behindBy = 0; - - // And now we loop, receiving samples. - for(;;) { - uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - if (behindBy > max_behindBy) { - max_behindBy = behindBy; - } - - if (behindBy == 0) continue; + uint16_t max_behindBy = 0; + + // And now we loop, receiving samples. + for(;;) { + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + if (behindBy > max_behindBy) { + max_behindBy = behindBy; + } + + if (behindBy == 0) continue; - samples++; - if (samples == 1) { - // DMA has transferred the very first data - dma_start_time = GetCountSspClk() & 0xfffffff0; - } + samples++; + if (samples == 1) { + // DMA has transferred the very first data + dma_start_time = GetCountSspClk() & 0xfffffff0; + } - uint16_t sniffdata = *upTo++; + uint16_t sniffdata = *upTo++; - if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d, samples=%d", behindBy, samples); - break; - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers - WDT_HIT(); - if (BUTTON_PRESS()) { - DbpString("Sniff stopped."); - break; - } - } - } + Dbprintf("About to blow circular buffer - aborted! behindBy=%d, samples=%d", behindBy, samples); + break; + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + WDT_HIT(); + if (BUTTON_PRESS()) { + DbpString("Sniff stopped."); + break; + } + } + } - if (!TagIsActive) { // no need to try decoding reader data if the tag is sending - if (Handle15693SampleFromReader(sniffdata & 0x02, &DecodeReader)) { + if (!TagIsActive) { // no need to try decoding reader data if the tag is sending + if (Handle15693SampleFromReader(sniffdata & 0x02, &DecodeReader)) { - uint32_t eof_time = dma_start_time + samples*16 + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF - if (DecodeReader.byteCount > 0) { - uint32_t sof_time = eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers - - 32*16 // time for SOF transfer - - 16*16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); - } - // And ready to receive another command. - DecodeReaderReset(&DecodeReader); - // And also reset the demod code, which might have been - // false-triggered by the commands from the reader. - DecodeTagReset(&DecodeTag); - ReaderIsActive = false; - ExpectTagAnswer = true; + uint32_t eof_time = dma_start_time + samples*16 + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF + if (DecodeReader.byteCount > 0) { + uint32_t sof_time = eof_time + - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers + - 32*16 // time for SOF transfer + - 16*16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); + } + // And ready to receive another command. + DecodeReaderReset(&DecodeReader); + // And also reset the demod code, which might have been + // false-triggered by the commands from the reader. + DecodeTagReset(&DecodeTag); + ReaderIsActive = false; + ExpectTagAnswer = true; - } else if (Handle15693SampleFromReader(sniffdata & 0x01, &DecodeReader)) { + } else if (Handle15693SampleFromReader(sniffdata & 0x01, &DecodeReader)) { - uint32_t eof_time = dma_start_time + samples*16 + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF - if (DecodeReader.byteCount > 0) { - uint32_t sof_time = eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers - - 32*16 // time for SOF transfer - - 16*16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); - } - // And ready to receive another command - DecodeReaderReset(&DecodeReader); + uint32_t eof_time = dma_start_time + samples*16 + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF + if (DecodeReader.byteCount > 0) { + uint32_t sof_time = eof_time + - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers + - 32*16 // time for SOF transfer + - 16*16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); + } + // And ready to receive another command + DecodeReaderReset(&DecodeReader); - // And also reset the demod code, which might have been - // false-triggered by the commands from the reader. - DecodeTagReset(&DecodeTag); - ReaderIsActive = false; - ExpectTagAnswer = true; + // And also reset the demod code, which might have been + // false-triggered by the commands from the reader. + DecodeTagReset(&DecodeTag); + ReaderIsActive = false; + ExpectTagAnswer = true; - } else { - ReaderIsActive = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); - } - } + } else { + ReaderIsActive = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); + } + } - if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet - if (Handle15693SamplesFromTag(sniffdata >> 2, &DecodeTag)) { + if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + if (Handle15693SamplesFromTag(sniffdata >> 2, &DecodeTag)) { - uint32_t eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM_SNIFF; // end of EOF - if (DecodeTag.lastBit == SOF_PART2) { - eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) - } - uint32_t sof_time = eof_time - - DecodeTag.len * 8 * 8 * 16 // time for byte transfers - - 32 * 16 // time for SOF transfer - - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer - LogTrace(DecodeTag.output, DecodeTag.len, sof_time*4, eof_time*4, NULL, false); - // And ready to receive another response. - DecodeTagReset(&DecodeTag); - DecodeReaderReset(&DecodeReader); - ExpectTagAnswer = false; - TagIsActive = false; - } else { - TagIsActive = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); - } - } + uint32_t eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM_SNIFF; // end of EOF + if (DecodeTag.lastBit == SOF_PART2) { + eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) + } + uint32_t sof_time = eof_time + - DecodeTag.len * 8 * 8 * 16 // time for byte transfers + - 32 * 16 // time for SOF transfer + - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer + LogTrace(DecodeTag.output, DecodeTag.len, sof_time*4, eof_time*4, NULL, false); + // And ready to receive another response. + DecodeTagReset(&DecodeTag); + DecodeReaderReset(&DecodeReader); + ExpectTagAnswer = false; + TagIsActive = false; + } else { + TagIsActive = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); + } + } - } + } - FpgaDisableSscDma(); + FpgaDisableSscDma(); - DbpString("Sniff statistics:"); - Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", ExpectTagAnswer, TagIsActive, ReaderIsActive); - Dbprintf(" DecodeTag State: %d", DecodeTag.state); - Dbprintf(" DecodeTag byteCnt: %d", DecodeTag.len); - Dbprintf(" DecodeTag posCount: %d", DecodeTag.posCount); - Dbprintf(" DecodeReader State: %d", DecodeReader.state); - Dbprintf(" DecodeReader byteCnt: %d", DecodeReader.byteCount); - Dbprintf(" DecodeReader posCount: %d", DecodeReader.posCount); - Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); - Dbprintf(" Max behindBy: %d", max_behindBy); + DbpString("Sniff statistics:"); + Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", ExpectTagAnswer, TagIsActive, ReaderIsActive); + Dbprintf(" DecodeTag State: %d", DecodeTag.state); + Dbprintf(" DecodeTag byteCnt: %d", DecodeTag.len); + Dbprintf(" DecodeTag posCount: %d", DecodeTag.posCount); + Dbprintf(" DecodeReader State: %d", DecodeReader.state); + Dbprintf(" DecodeReader byteCnt: %d", DecodeReader.byteCount); + Dbprintf(" DecodeReader posCount: %d", DecodeReader.posCount); + Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); + Dbprintf(" Max behindBy: %d", max_behindBy); } -// Initialize the proxmark as iso15k reader -// (this might produces glitches that confuse some tags +// Initialize Proxmark3 as ISO15693 reader void Iso15693InitReader(void) { - + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Start from off (no field generated) @@ -1309,16 +1314,20 @@ void Iso15693InitReader(void) { LEDsoff(); SpinDelay(10); - // switch field on - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); - LED_D_ON(); - - // initialize SSC and select proper AD input - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // switch field on + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + LED_D_ON(); + + // initialize SSC and select proper AD input + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // give tags some time to energize - SpinDelay(250); + // give tags some time to energize + SpinDelay(250); + + set_tracing(true); + + StartCountSspClk(); } /////////////////////////////////////////////////////////////////////// @@ -1333,10 +1342,10 @@ void Iso15693InitReader(void) { static void BuildIdentifyRequest(uint8_t *cmd) { // flags cmd[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; - // inventory command code - cmd[1] = ISO15_CMD_INVENTORY; - // no mask - cmd[2] = 0x00; + // inventory command code + cmd[1] = ISO15_CMD_INVENTORY; + // no mask + cmd[2] = 0x00; // CRC AddCrc15(cmd, 3); } @@ -1376,49 +1385,41 @@ static void BuildInventoryResponse(uint8_t *uid) { int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time) { - if (init) { - Iso15693InitReader(); - StartCountSspClk(); - } + if (init) { + Iso15693InitReader(); + } - int answerLen = 0; + if (speed_fast) { + // high speed (1 out of 4) + CodeIso15693AsReader(send, sendlen); + } else { + // low speed (1 out of 256) + CodeIso15693AsReader256(send, sendlen); + } - if (speed_fast) { - // high speed (1 out of 4) - CodeIso15693AsReader(send, sendlen); - } else { - // low speed (1 out of 256) - CodeIso15693AsReader256(send, sendlen); - } + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); + uint32_t end_time = start_time + 32 * (8 * ToSendMax -4); // substract the 4 padding bits after EOF + LogTrace(send, sendlen, (start_time * 4), (end_time * 4), NULL, true); - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); - uint32_t end_time = start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF - LogTrace(send, sendlen, start_time*4, end_time*4, NULL, true); - - // Now wait for a response - if (recv != NULL) { - answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); - } - - return answerLen; + int res = 0; + if (recv != NULL) { + res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + } + return res; } int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time) { - int answerLen = 0; + CodeIso15693AsReaderEOF(); + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); + uint32_t end_time = start_time + 32 * (8 * ToSendMax - 4); // substract the 4 padding bits after EOF + LogTrace(NULL, 0, (start_time * 4), (end_time * 4), NULL, true); - CodeIso15693AsReaderEOF(); - - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); - uint32_t end_time = start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF - LogTrace(NULL, 0, start_time*4, end_time*4, NULL, true); - - // Now wait for a response - if (recv != NULL) { - answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); - } - - return answerLen; + int res = 0; + if (recv != NULL) { + res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + } + return res; } // -------------------------------------------------------------------- @@ -1496,22 +1497,22 @@ static void DbdecodeIso15693Answer(int len, uint8_t *d) { // parameter is unused !?! void ReaderIso15693(uint32_t parameter) { - LED_A_ON(); - set_tracing(true); + LED_A_ON(); + set_tracing(true); - uint8_t *answer = BigBuf_malloc(ISO15693_MAX_RESPONSE_LENGTH); + uint8_t *answer = BigBuf_malloc(ISO15693_MAX_RESPONSE_LENGTH); memset(answer, 0x00, ISO15693_MAX_RESPONSE_LENGTH); - // FIRST WE RUN AN INVENTORY TO GET THE TAG UID - // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME + // FIRST WE RUN AN INVENTORY TO GET THE TAG UID + // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - // Send the IDENTIFY command - uint8_t cmd[5] = {0}; - BuildIdentifyRequest(cmd); - uint32_t start_time = 0; - uint32_t eof_time; - int answerLen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + // Send the IDENTIFY command + uint8_t cmd[5] = {0}; + BuildIdentifyRequest(cmd); + uint32_t start_time = 0; + uint32_t eof_time; + int answerLen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; // we should do a better check than this if (answerLen >= 12) { @@ -1551,19 +1552,30 @@ void ReaderIso15693(uint32_t parameter) { // When SIM: initialize the Proxmark3 as ISO15693 tag void Iso15693InitTag(void) { - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - StartCountSspClk(); + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + SpinDelay(10); + + // switch simulation FPGA + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + + // initialize SSC and select proper AD input + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // turn on clock + StartCountSspClk(); } // Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands // all demodulation performed in arm rather than host. - greg void SimTagIso15693(uint8_t *uid) { - LEDsoff(); - Iso15693InitTag(); + Iso15693InitTag(); LED_A_ON(); @@ -1582,21 +1594,21 @@ void SimTagIso15693(uint8_t *uid) { WDT_HIT(); // Listen to reader - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; - uint32_t eof_time = 0, start_time = 0; - int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + uint32_t eof_time = 0, start_time = 0; + int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); - if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { // TODO: check more flags - bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); - start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); - } + if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { // TODO: check more flags + bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); + start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + } if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf(" %d bytes read from reader:", cmd_len); Dbhexdump(cmd_len, cmd, false); } - } + } switch_off(); } @@ -1619,9 +1631,9 @@ void BruteforceIso15693Afi(uint32_t speed) { int datalen = 5; uint32_t eof_time = 0; - uint32_t start_time = GetCountSspClk(); - int recvlen = SendDataTag(data, datalen, true, speed, recv, sizeof(recv), 0, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + uint32_t start_time = GetCountSspClk(); + int recvlen = SendDataTag(data, datalen, true, speed, recv, sizeof(recv), 0, ISO15693_READER_TIMEOUT, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); @@ -1643,8 +1655,8 @@ void BruteforceIso15693Afi(uint32_t speed) { data[2] = i & 0xFF; AddCrc15(data, 4); - recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time, ISO15693_READER_TIMEOUT, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); @@ -1674,63 +1686,60 @@ void BruteforceIso15693Afi(uint32_t speed) { // OBS: doesn't turn off rf field afterwards. void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data) { - LED_A_ON(); + LED_A_ON(); - int recvlen = 0; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - uint32_t eof_time; - uint16_t timeout; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + uint32_t eof_time; + uint16_t timeout; bool request_answer = false; - - switch (data[1]) { - case ISO15_CMD_WRITE: - case ISO15_CMD_LOCK: - case ISO15_CMD_WRITEMULTI: - case ISO15_CMD_WRITEAFI: - case ISO15_CMD_LOCKAFI: - case ISO15_CMD_WRITEDSFID: - case ISO15_CMD_LOCKDSFID: - timeout = ISO15693_READER_TIMEOUT_WRITE; - request_answer = data[0] & ISO15_REQ_OPTION; - break; - default: - timeout = ISO15693_READER_TIMEOUT; - } + + switch (data[1]) { + case ISO15_CMD_WRITE: + case ISO15_CMD_LOCK: + case ISO15_CMD_WRITEMULTI: + case ISO15_CMD_WRITEAFI: + case ISO15_CMD_LOCKAFI: + case ISO15_CMD_WRITEDSFID: + case ISO15_CMD_LOCKDSFID: + timeout = ISO15693_READER_TIMEOUT_WRITE; + request_answer = data[0] & ISO15_REQ_OPTION; + break; + default: + timeout = ISO15693_READER_TIMEOUT; + } - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("SEND:"); - Dbhexdump(datalen, data, false); - } + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("SEND:"); + Dbhexdump(datalen, data, false); + } - recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), 0, timeout, &eof_time); + recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), 0, timeout, &eof_time); // send a single EOF to get the tag response - if (request_answer) { - recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), 0, ISO15693_READER_TIMEOUT, &eof_time); - } - - // for the time being, switch field off to protect rdv4.0 - // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); + if (request_answer) { + recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), 0, ISO15693_READER_TIMEOUT, &eof_time); + } + + // for the time being, switch field off to protect rdv4.0 + // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); if (recv) { - if (recvlen > ISO15693_MAX_RESPONSE_LENGTH) { - recvlen = ISO15693_MAX_RESPONSE_LENGTH; - } - reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); - - - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("RECV:"); - if (recvlen > 0) { - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } - } - + if (recvlen > ISO15693_MAX_RESPONSE_LENGTH) { + recvlen = ISO15693_MAX_RESPONSE_LENGTH; + } + reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("RECV:"); + if (recvlen > 0) { + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } + } } else { reply_mix(CMD_ACK, 1, 0, 0, 0, 0); } @@ -1745,55 +1754,55 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint // Set the UID on Magic ISO15693 tag (based on Iceman's LUA-script). void SetTag15693Uid(uint8_t *uid) { - LED_A_ON(); + LED_A_ON(); - uint8_t cmd[4][9] = { - {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x3e, 0x00, 0x00, 0x00, 0x00}, - {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x3f, 0x69, 0x96, 0x00, 0x00}, - {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x38}, - {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x39} - }; + uint8_t cmd[4][9] = { + {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x3e, 0x00, 0x00, 0x00, 0x00}, + {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x3f, 0x69, 0x96, 0x00, 0x00}, + {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x38}, + {ISO15_REQ_DATARATE_HIGH, ISO15_CMD_WRITE, 0x39} + }; - int recvlen = 0; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - uint32_t eof_time; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + uint32_t eof_time; - // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) - cmd[2][3] = uid[7]; - cmd[2][4] = uid[6]; - cmd[2][5] = uid[5]; - cmd[2][6] = uid[4]; + // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) + cmd[2][3] = uid[7]; + cmd[2][4] = uid[6]; + cmd[2][5] = uid[5]; + cmd[2][6] = uid[4]; - // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) - cmd[3][3] = uid[3]; - cmd[3][4] = uid[2]; - cmd[3][5] = uid[1]; - cmd[3][6] = uid[0]; + // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) + cmd[3][3] = uid[3]; + cmd[3][4] = uid[2]; + cmd[3][5] = uid[1]; + cmd[3][6] = uid[0]; AddCrc15(cmd[0], 7); AddCrc15(cmd[1], 7); AddCrc15(cmd[2], 7); AddCrc15(cmd[3], 7); - uint32_t start_time = 0; - - for (int i = 0; i < 4; i++) { - - recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), i == 0 ? true : false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + uint32_t start_time = 0; + + for (int i = 0; i < 4; i++) { + + recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), i == 0 ? true : false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("SEND:"); - Dbhexdump(sizeof(cmd[i]), cmd[i], false); - Dbprintf("RECV:"); - if (recvlen > 0) { - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } - } - } + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("SEND:"); + Dbhexdump(sizeof(cmd[i]), cmd[i], false); + Dbprintf("RECV:"); + if (recvlen > 0) { + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } + } + } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); + reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); } From a0d23f586eb6147dfc141bd968217bf3b6216c35 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Jul 2020 19:42:04 +0200 Subject: [PATCH 037/139] fpga --- armsrc/optimized_cipher.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index 0f762a8d6..24bb8d7ee 100644 --- a/armsrc/optimized_cipher.c +++ b/armsrc/optimized_cipher.c @@ -245,7 +245,6 @@ void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) { uint8_t dest [] = {0, 0, 0, 0, 0, 0, 0, 0}; opt_MAC(div_key_p, cc_nr_p, dest); memcpy(mac, dest, 4); - return; } void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { @@ -257,7 +256,6 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { }; opt_suc(div_key_p, &_init, cc_p, 12, true); opt_output(div_key_p, &_init, mac); - return; } /** @@ -291,5 +289,4 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) { opt_suc(div_key_p, &_init, nr, 4, true); opt_output(div_key_p, &_init, mac); - return; } From b627d91fc2fc18d1f435a155989b69cc50f43f3c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Jul 2020 19:42:34 +0200 Subject: [PATCH 038/139] adapt --- client/src/cmdhficlass.c | 41 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index f11d65945..1eda5678b 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1121,36 +1121,38 @@ static void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) { PacketResponseNG resp; - uint8_t flags = FLAG_ICLASS_READER_ONLY_ONCE; + uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); if (use_credit_key) flags |= FLAG_ICLASS_READER_CEDITKEY; clearCommandBuffer(); SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { PrintAndLogEx(WARNING, "command execute timeout"); return false; } uint8_t isOK = resp.oldarg[0] & 0xff; - uint8_t *data = resp.data.asBytes; - memcpy(CSN, data, 8); - - if (CCNR != NULL) - memcpy(CCNR, data + 16, 8); - - if (isOK > 0 && verbose) { - PrintAndLogEx(SUCCESS, "CSN | %s", sprint_hex(CSN, 8)); - PrintAndLogEx(SUCCESS, "CCNR | %s", sprint_hex(CCNR, 8)); + if (isOK == 0xFF) { + if (verbose) { + PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", isOK); + } + return false; } - if (isOK <= 1) { - if (verbose) - PrintAndLogEx(FAILED, "failed to obtain CC! Tag-select is aborting... (%d)", isOK); + picopass_hdr *hdr = (picopass_hdr *)resp.data.asBytes; - return false; + if (CSN != NULL) + memcpy(CSN, hdr->csn, 8); + + if (CCNR != NULL) + memcpy(CCNR, hdr->epurse, 8); + + if (verbose) { + PrintAndLogEx(SUCCESS, "CSN %s", sprint_hex(CSN, 8)); + PrintAndLogEx(SUCCESS, "epurse %s", sprint_hex(CCNR, 8)); } return true; } @@ -1159,12 +1161,12 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (!select_only(CSN, CCNR, use_credit_key, verbose)) { + if (select_only(CSN, CCNR, use_credit_key, verbose) == false) { if (verbose) PrintAndLogEx(FAILED, "selecting tag failed"); - // DropField(); return false; } + //get div_key if (rawkey) memcpy(div_key, KEY, 8); @@ -1177,7 +1179,6 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_AUTH, MAC, 4); if (WaitForResponseTimeout(CMD_HF_ICLASS_AUTH, &resp, 2000) == 0) { if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); @@ -2967,10 +2968,12 @@ int readIclass(bool loop, bool verbose) { SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { uint8_t readStatus = resp.oldarg[0] & 0xff; + PrintAndLogEx(NORMAL, "ICE: %x", readStatus); + // no tag found or button pressed if ((readStatus == 0 && !loop) || readStatus == 0xFF) { DropField(); From 1feb34617be5ef590234be72beaf275fd55f34e6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 9 Jul 2020 19:43:00 +0200 Subject: [PATCH 039/139] hunting down why logtrace is missing --- client/src/cmdtrace.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 1b172bfb3..81840dfc1 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -181,7 +181,10 @@ static uint16_t printHexLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trac static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes) { // sanity check - if (is_last_record(tracepos, traceLen)) return traceLen; + if (is_last_record(tracepos, traceLen)) { + PrintAndLogEx(DEBUG, "last record triggered. t-pos: %u t-len %u", tracepos, traceLen); + return traceLen; + } uint32_t duration; uint16_t data_len; From a25a5322dd91e498c87794ed661be8969660ea24 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 10 Jul 2020 16:37:56 +0200 Subject: [PATCH 040/139] fpga: added iCLASS on deviceside --- armsrc/BigBuf.c | 81 +++++---- armsrc/Makefile | 2 +- armsrc/iclass.c | 55 ++++-- armsrc/iso15693.c | 47 ++--- armsrc/optimized_cipher.c | 28 +++ armsrc/optimized_cipher.h | 2 + armsrc/optimized_cipherutils.c | 140 ++++++++++++++ armsrc/optimized_cipherutils.h | 66 +++++++ armsrc/optimized_elite.c | 238 ++++++++++++++++++++++++ armsrc/optimized_elite.h | 62 +++++++ armsrc/optimized_ikeys.c | 324 +++++++++++++++++++++++++++++++++ armsrc/optimized_ikeys.h | 69 +++++++ client/src/cmdhficlass.c | 57 +++--- 13 files changed, 1072 insertions(+), 99 deletions(-) create mode 100644 armsrc/optimized_cipherutils.c create mode 100644 armsrc/optimized_cipherutils.h create mode 100644 armsrc/optimized_elite.c create mode 100644 armsrc/optimized_elite.h create mode 100644 armsrc/optimized_ikeys.c create mode 100644 armsrc/optimized_ikeys.h diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 4642d0079..8637443a0 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -22,29 +22,29 @@ extern uint8_t _stack_start, __bss_end__; static uint8_t *BigBuf = &__bss_end__; /* BigBuf memory layout: -Pointer to highest available memory: BigBuf_hi - high BigBuf_size - reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, +Pointer to highest available memory: s_bigbuf_hi + high s_bigbuf_size + reserved = BigBuf_malloc() subtracts amount from s_bigbuf_hi, low 0x00 */ -static uint32_t BigBuf_size = 0; +static uint32_t s_bigbuf_size = 0; // High memory mark -static uint32_t BigBuf_hi = 0; +static uint32_t s_bigbuf_hi = 0; // pointer to the emulator memory. static uint8_t *emulator_memory = NULL; // trace related variables -static uint32_t traceLen = 0; +static uint32_t trace_len = 0; static bool tracing = true; // compute the available size for BigBuf void BigBuf_initialize(void) { - BigBuf_size = (uint32_t)&_stack_start - (uint32_t)&__bss_end__; - BigBuf_hi = BigBuf_size; - traceLen = 0; + s_bigbuf_size = (uint32_t)&_stack_start - (uint32_t)&__bss_end__; + s_bigbuf_hi = s_bigbuf_size; + trace_len = 0; } // get the address of BigBuf @@ -53,7 +53,7 @@ uint8_t *BigBuf_get_addr(void) { } uint32_t BigBuf_get_size(void) { - return BigBuf_size; + return s_bigbuf_size; } // get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done @@ -64,6 +64,11 @@ uint8_t *BigBuf_get_EM_addr(void) { return emulator_memory; } +/* +uint32_t BigBuf_get_EM_size(void) { + return CARD_MEMORY_SIZE; +} +*/ // clear ALL of BigBuf void BigBuf_Clear(void) { @@ -72,9 +77,9 @@ void BigBuf_Clear(void) { // clear ALL of BigBuf void BigBuf_Clear_ext(bool verbose) { - memset(BigBuf, 0, BigBuf_size); + memset(BigBuf, 0, s_bigbuf_size); if (verbose) - Dbprintf("Buffer cleared (%i bytes)", BigBuf_size); + Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size); } void BigBuf_Clear_EM(void) { @@ -82,23 +87,23 @@ void BigBuf_Clear_EM(void) { } void BigBuf_Clear_keep_EM(void) { - memset(BigBuf, 0, BigBuf_hi); + memset(BigBuf, 0, s_bigbuf_hi); } // allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory // at the beginning of BigBuf is always for traces/samples uint8_t *BigBuf_malloc(uint16_t chunksize) { - if (BigBuf_hi < chunksize) + if (s_bigbuf_hi < chunksize) return NULL; // no memory left chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 - BigBuf_hi -= chunksize; // aligned to 4 Byte boundary - return (uint8_t *)BigBuf + BigBuf_hi; + s_bigbuf_hi -= chunksize; // aligned to 4 Byte boundary + return (uint8_t *)BigBuf + s_bigbuf_hi; } // free ALL allocated chunks. The whole BigBuf is available for traces or samples again. void BigBuf_free(void) { - BigBuf_hi = BigBuf_size; + s_bigbuf_hi = s_bigbuf_size; emulator_memory = NULL; // shouldn't this empty BigBuf also? } @@ -106,33 +111,33 @@ void BigBuf_free(void) { // free allocated chunks EXCEPT the emulator memory void BigBuf_free_keep_EM(void) { if (emulator_memory != NULL) - BigBuf_hi = emulator_memory - (uint8_t *)BigBuf; + s_bigbuf_hi = emulator_memory - (uint8_t *)BigBuf; else - BigBuf_hi = BigBuf_size; + s_bigbuf_hi = s_bigbuf_size; // shouldn't this empty BigBuf also? } void BigBuf_print_status(void) { DbpString(_CYAN_("Memory")); - Dbprintf(" BigBuf_size.............%d", BigBuf_size); - Dbprintf(" Available memory........%d", BigBuf_hi); + Dbprintf(" BigBuf_size.............%d", s_bigbuf_size); + Dbprintf(" Available memory........%d", s_bigbuf_hi); DbpString(_CYAN_("Tracing")); Dbprintf(" tracing ................%d", tracing); - Dbprintf(" traceLen ...............%d", traceLen); + Dbprintf(" traceLen ...............%d", trace_len); } // return the maximum trace length (i.e. the unallocated size of BigBuf) uint16_t BigBuf_max_traceLen(void) { - return BigBuf_hi; + return s_bigbuf_hi; } void clear_trace(void) { - traceLen = 0; + trace_len = 0; } void set_tracelen(uint32_t value) { - traceLen = value; + trace_len = value; } void set_tracing(bool enable) { @@ -148,7 +153,7 @@ bool get_tracing(void) { * @return */ uint32_t BigBuf_get_traceLen(void) { - return traceLen; + return trace_len; } /** @@ -164,12 +169,12 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ } uint8_t *trace = BigBuf_get_addr(); - tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + traceLen); + tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + trace_len); uint32_t num_paritybytes = (iLen - 1) / 8 + 1; // number of valid paritybytes in *parity // Return when trace is full - if (TRACELOG_HDR_LEN + iLen + num_paritybytes >= BigBuf_max_traceLen() - traceLen) { + if (TRACELOG_HDR_LEN + iLen + num_paritybytes >= BigBuf_max_traceLen() - trace_len) { tracing = false; // don't trace any more if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("trace is full"); } return false; @@ -185,33 +190,35 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ if (duration > 0x7FFF) { if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("Error in LogTrace: duration too long for 15 bits encoding: 0x%08x start:0x%08x end:0x%08x", duration, timestamp_start, timestamp_end); - Dbprintf("Forcing duration = 0"); +// Dbprintf("Forcing duration = 0"); } - duration = 0; + + duration /= 32; + // duration >>= 5; +// duration = 0; } hdr->timestamp = timestamp_start; hdr->duration = duration; hdr->data_len = iLen; hdr->isResponse = !readerToTag; - traceLen += TRACELOG_HDR_LEN; + trace_len += TRACELOG_HDR_LEN; // data bytes if (btBytes != NULL && iLen != 0) { - memcpy(trace + traceLen, btBytes, iLen); + memcpy(trace + trace_len, btBytes, iLen); } - traceLen += iLen; + trace_len += iLen; // parity bytes if (num_paritybytes != 0) { if (parity != NULL) { - memcpy(trace + traceLen, parity, num_paritybytes); + memcpy(trace + trace_len, parity, num_paritybytes); } else { - memset(trace + traceLen, 0x00, num_paritybytes); + memset(trace + trace_len, 0x00, num_paritybytes); } } - traceLen += num_paritybytes; - + trace_len += num_paritybytes; return true; } diff --git a/armsrc/Makefile b/armsrc/Makefile index 44ca3ab6b..2768ab3a4 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -30,7 +30,7 @@ SRC_ISO14443b = iso14443b.c SRC_FELICA = felica.c SRC_CRAPTO1 = crypto1.c des.c desfire_crypto.c mifaredesfire.c aes.c platform_util.c SRC_CRC = crc.c crc16.c crc32.c -SRC_ICLASS = iclass.c optimized_cipher.c +SRC_ICLASS = iclass.c optimized_cipherutils.c optimized_ikeys.c optimized_elite.c optimized_cipher.c SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c SRC_NFCBARCODE = thinfilm.c diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 478bafa43..a68565830 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -781,9 +781,10 @@ static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time) CodeIso15693AsReader(frame, len); TransmitTo15693Tag(ToSend, ToSendMax, start_time); - uint32_t end_time = *start_time + 32 * (8 * ToSendMax - 4); // substract the 4 padding bits after EOF + uint32_t end_time = *start_time + (32 * ((8 * ToSendMax) - 4)); // substract the 4 padding bits after EOF - LogTrace(frame, len, *start_time * 4, end_time * 4, NULL, true); + if (LogTrace(frame, len, (*start_time * 4), (end_time * 4), NULL, true) == false) + DbpString("send_as_reader: failed logtrace"); } static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* resp, size_t max_resp_size, @@ -1112,35 +1113,57 @@ void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { // used with function select_and_auth (cmdhficlass.c) // which needs to authenticate before doing more things like read/write -void iClass_Authentication(uint8_t *mac) { +// selects and authenticate to a card, sends back div_key and mac to client. +void iClass_Authentication(uint8_t *bytes) { + + struct p { + uint8_t key[8]; + bool use_raw; + bool use_elite; + bool use_credit_key; + } PACKED; + struct p *payload = (struct p *)bytes; + + // device response message + struct { + bool isOK; + uint8_t div_key[8]; + uint8_t mac[4]; + } PACKED packet; Iso15693InitReader(); StartCountSspClk(); uint8_t card_data[3 * 8] = {0xFF}; - bool use_credit_key = false; uint32_t eof_time = 0; - bool isOK = select_iclass_tag(card_data, use_credit_key, &eof_time); - if (isOK == false) { - reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); + packet.isOK = select_iclass_tag(card_data, payload->use_credit_key, &eof_time); + if (packet.isOK == false) { + reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&packet, sizeof(packet)); return; } uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; uint8_t check[9] = { ICLASS_CMD_CHECK }; -// uint8_t mac[4]; -// opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, mac ) + uint8_t ccnr[12] = {0}; + memcpy(ccnr, card_data + 16, 8); + + if (payload->use_raw) + memcpy(packet.div_key, payload->key, 8); + else + iclass_calc_div_key(card_data, payload->key, packet.div_key, payload->use_elite); + + opt_doReaderMAC(ccnr, packet.div_key, packet.mac); // copy MAC to check command (readersignature) - check[5] = mac[0]; - check[6] = mac[1]; - check[7] = mac[2]; - check[8] = mac[3]; + check[5] = packet.mac[0]; + check[6] = packet.mac[1]; + check[7] = packet.mac[2]; + check[8] = packet.mac[3]; uint8_t resp[ICLASS_BUFFER_SIZE]; - isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); + packet.isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&packet, sizeof(packet)); } typedef struct iclass_premac { @@ -1300,6 +1323,8 @@ void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { // return pointer to dump memory in arg3 // iceman: why not return | dataout - getbigbuf ? Should give exact location. + Dbprintf("ICE:: dataout, %u max trace %u, bb start %u, data-bb %u ", dataout, BigBuf_max_traceLen(), BigBuf_get_addr(), dataout - BigBuf_get_addr() ); + Dbprintf("ICE:: bb size %u, malloced %u (255*8)", BigBuf_get_size(), BigBuf_get_size() - (dataout - BigBuf_get_addr()) ); reply_mix(CMD_ACK, isOK, blkcnt, BigBuf_max_traceLen(), 0, 0); BigBuf_free(); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f8214b5e4..39a64a8c4 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -688,9 +688,9 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo FpgaDisableSscDma(); uint32_t sof_time = *eof_time - - DecodeTag.len * 8 * 8 * 16 // time for byte transfers - - 32 * 16 // time for SOF transfer - - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer + - (DecodeTag.len * 8 * 8 * 16) // time for byte transfers + - (32 * 16) // time for SOF transfer + - (DecodeTag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d", @@ -705,7 +705,8 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); } - LogTrace(DecodeTag.output, DecodeTag.len, (sof_time * 4), (*eof_time * 4), NULL, false); + if (LogTrace(DecodeTag.output, DecodeTag.len, (sof_time * 4), (*eof_time * 4), NULL, false) == false) + DbpString("GetIso15693AnswerFromTag: failed logtrace"); if (ret < 0) { return ret; @@ -1090,7 +1091,8 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers - 32 // time for SOF transfer - 16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*32, *eof_time*32, NULL, true); + if (LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*32, *eof_time*32, NULL, true) == false) + DbpString("GetIso15693CommandFromReader: failed logtrace"); } return DecodeReader.byteCount; @@ -1223,16 +1225,18 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { } } - if (!TagIsActive) { // no need to try decoding reader data if the tag is sending + // no need to try decoding reader data if the tag is sending + if (TagIsActive == false) { + if (Handle15693SampleFromReader(sniffdata & 0x02, &DecodeReader)) { - uint32_t eof_time = dma_start_time + samples*16 + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF + uint32_t eof_time = dma_start_time + (samples * 16) + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF if (DecodeReader.byteCount > 0) { uint32_t sof_time = eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers - - 32*16 // time for SOF transfer - - 16*16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); + - DecodeReader.byteCount * (DecodeReader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers + - 32 * 16 // time for SOF transfer + - 16 * 16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); } // And ready to receive another command. DecodeReaderReset(&DecodeReader); @@ -1244,13 +1248,13 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { } else if (Handle15693SampleFromReader(sniffdata & 0x01, &DecodeReader)) { - uint32_t eof_time = dma_start_time + samples*16 + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF + uint32_t eof_time = dma_start_time + (samples * 16) + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF if (DecodeReader.byteCount > 0) { uint32_t sof_time = eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers - - 32*16 // time for SOF transfer - - 16*16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); + - DecodeReader.byteCount * (DecodeReader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers + - 32 * 16 // time for SOF transfer + - 16 * 16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); } // And ready to receive another command DecodeReaderReset(&DecodeReader); @@ -1269,15 +1273,16 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet if (Handle15693SamplesFromTag(sniffdata >> 2, &DecodeTag)) { - uint32_t eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM_SNIFF; // end of EOF + uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF if (DecodeTag.lastBit == SOF_PART2) { - eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) + eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) } uint32_t sof_time = eof_time - DecodeTag.len * 8 * 8 * 16 // time for byte transfers - - 32 * 16 // time for SOF transfer - - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer - LogTrace(DecodeTag.output, DecodeTag.len, sof_time*4, eof_time*4, NULL, false); + - (32 * 16) // time for SOF transfer + - (DecodeTag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer + + LogTrace(DecodeTag.output, DecodeTag.len, (sof_time * 4), (eof_time * 4), NULL, false); // And ready to receive another response. DecodeTagReset(&DecodeTag); DecodeReaderReset(&DecodeReader); diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index 24bb8d7ee..021b8ae22 100644 --- a/armsrc/optimized_cipher.c +++ b/armsrc/optimized_cipher.c @@ -77,7 +77,15 @@ -- piwi 2019 **/ +/** + add the possibility to do iCLASS on device only + -- iceman 2020 +**/ + #include "optimized_cipher.h" +#include "optimized_elite.h" +#include "optimized_ikeys.h" +#include "optimized_cipherutils.h" static const uint8_t opt_select_LUT[256] = { 00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04, @@ -290,3 +298,23 @@ void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *di opt_suc(div_key_p, &_init, nr, 4, true); opt_output(div_key_p, &_init, mac); } + + +void iclass_calc_div_key(uint8_t *csn, uint8_t *key, uint8_t *div_key, bool elite) { + if (elite) { + uint8_t keytable[128] = {0}; + uint8_t key_index[8] = {0}; + uint8_t key_sel[8] = { 0 }; + uint8_t key_sel_p[8] = { 0 }; + hash2(key, keytable); + hash1(csn, key_index); + for (uint8_t i = 0; i < 8 ; i++) + key_sel[i] = keytable[key_index[i]]; + + //Permute from iclass format to standard format + permutekey_rev(key_sel, key_sel_p); + diversifyKey(csn, key_sel_p, div_key); + } else { + diversifyKey(csn, key, div_key); + } +} diff --git a/armsrc/optimized_cipher.h b/armsrc/optimized_cipher.h index c6df25ab8..e65b6c4cb 100644 --- a/armsrc/optimized_cipher.h +++ b/armsrc/optimized_cipher.h @@ -46,4 +46,6 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p); */ void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p); + +void iclass_calc_div_key(uint8_t *csn, uint8_t *key, uint8_t *div_key, bool elite); #endif // OPTIMIZED_CIPHER_H diff --git a/armsrc/optimized_cipherutils.c b/armsrc/optimized_cipherutils.c new file mode 100644 index 000000000..c51f83f9b --- /dev/null +++ b/armsrc/optimized_cipherutils.c @@ -0,0 +1,140 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file 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 loclass. If not, see . + * + * + ****************************************************************************/ +#include "optimized_cipherutils.h" +#include + +/** + * + * @brief Return and remove the first bit (x0) in the stream : + * @param stream + * @return + */ +bool headBit(BitstreamIn *stream) { + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = (stream->position++) & 7; // mask out 00000111 + return (*(stream->buffer + bytepos) >> (7 - bitpos)) & 1; +} +/** + * @brief Return and remove the last bit (xn) in the stream: + * @param stream + * @return + */ +bool tailBit(BitstreamIn *stream) { + int bitpos = stream->numbits - 1 - (stream->position++); + + int bytepos = bitpos >> 3; + bitpos &= 7; + return (*(stream->buffer + bytepos) >> (7 - bitpos)) & 1; +} +/** + * @brief Pushes bit onto the stream + * @param stream + * @param bit + */ +void pushBit(BitstreamOut *stream, bool bit) { + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = stream->position & 7; + *(stream->buffer + bytepos) |= (bit) << (7 - bitpos); + stream->position++; + stream->numbits++; +} + +/** + * @brief Pushes the lower six bits onto the stream + * as b0 b1 b2 b3 b4 b5 b6 + * @param stream + * @param bits + */ +void push6bits(BitstreamOut *stream, uint8_t bits) { + pushBit(stream, bits & 0x20); + pushBit(stream, bits & 0x10); + pushBit(stream, bits & 0x08); + pushBit(stream, bits & 0x04); + pushBit(stream, bits & 0x02); + pushBit(stream, bits & 0x01); +} + +/** + * @brief bitsLeft + * @param stream + * @return number of bits left in stream + */ +int bitsLeft(BitstreamIn *stream) { + return stream->numbits - stream->position; +} +/** + * @brief numBits + * @param stream + * @return Number of bits stored in stream + */ +void x_num_to_bytes(uint64_t n, size_t len, uint8_t *dest) { + while (len--) { + dest[len] = (uint8_t) n; + n >>= 8; + } +} + +uint64_t x_bytes_to_num(uint8_t *src, size_t len) { + uint64_t num = 0; + while (len--) { + num = (num << 8) | (*src); + src++; + } + return num; +} + +uint8_t reversebytes(uint8_t b) { + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} + +void reverse_arraybytes(uint8_t *arr, size_t len) { + uint8_t i; + for (i = 0; i < len ; i++) { + arr[i] = reversebytes(arr[i]); + } +} + +void reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len) { + uint8_t i; + for (i = 0; i < len ; i++) { + dest[i] = reversebytes(arr[i]); + } +} + diff --git a/armsrc/optimized_cipherutils.h b/armsrc/optimized_cipherutils.h new file mode 100644 index 000000000..63ba8b8aa --- /dev/null +++ b/armsrc/optimized_cipherutils.h @@ -0,0 +1,66 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file 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 loclass. If not, see . + * + * + ****************************************************************************/ +#ifndef CIPHERUTILS_H +#define CIPHERUTILS_H +#include +#include +#include + +typedef struct { + uint8_t *buffer; + uint8_t numbits; + uint8_t position; +} BitstreamIn; + +typedef struct { + uint8_t *buffer; + uint8_t numbits; + uint8_t position; +} BitstreamOut; + +bool headBit(BitstreamIn *stream); +bool tailBit(BitstreamIn *stream); +void pushBit(BitstreamOut *stream, bool bit); +int bitsLeft(BitstreamIn *stream); + +void push6bits(BitstreamOut *stream, uint8_t bits); +void x_num_to_bytes(uint64_t n, size_t len, uint8_t *dest); +uint64_t x_bytes_to_num(uint8_t *src, size_t len); +uint8_t reversebytes(uint8_t b); +void reverse_arraybytes(uint8_t *arr, size_t len); +void reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len); +#endif // CIPHERUTILS_H diff --git a/armsrc/optimized_elite.c b/armsrc/optimized_elite.c new file mode 100644 index 000000000..d2c57ac68 --- /dev/null +++ b/armsrc/optimized_elite.c @@ -0,0 +1,238 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file 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 loclass. If not, see . + * + * + * + ****************************************************************************/ +#include "optimized_elite.h" + +#include +#include +#include +#include "mbedtls/des.h" +#include "optimized_ikeys.h" + +/** + * @brief Permutes a key from standard NIST format to Iclass specific format + * from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220 + * + * If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below. + * + * 1 0 1 1 1 1 1 1 bf + * 0 0 0 0 0 0 0 1 01 + * 0 0 1 0 1 1 0 1 2d + * 0 0 1 0 1 0 1 0 2a + * 1 1 1 1 1 0 0 1 f9 + * 0 1 0 0 0 1 0 0 44 + * 1 0 0 0 1 1 0 1 8d + * 0 1 1 0 1 1 0 0 6c + * + * 8 0 b 8 b a 9 e + * a d 9 8 b 7 0 a + * + * @param key + * @param dest + */ +void permutekey(uint8_t key[8], uint8_t dest[8]) { + int i; + for (i = 0 ; i < 8 ; i++) { + dest[i] = (((key[7] & (0x80 >> i)) >> (7 - i)) << 7) | + (((key[6] & (0x80 >> i)) >> (7 - i)) << 6) | + (((key[5] & (0x80 >> i)) >> (7 - i)) << 5) | + (((key[4] & (0x80 >> i)) >> (7 - i)) << 4) | + (((key[3] & (0x80 >> i)) >> (7 - i)) << 3) | + (((key[2] & (0x80 >> i)) >> (7 - i)) << 2) | + (((key[1] & (0x80 >> i)) >> (7 - i)) << 1) | + (((key[0] & (0x80 >> i)) >> (7 - i)) << 0); + } +} +/** + * Permutes a key from iclass specific format to NIST format + * @brief permutekey_rev + * @param key + * @param dest + */ +void permutekey_rev(uint8_t key[8], uint8_t dest[8]) { + int i; + for (i = 0 ; i < 8 ; i++) { + dest[7 - i] = (((key[0] & (0x80 >> i)) >> (7 - i)) << 7) | + (((key[1] & (0x80 >> i)) >> (7 - i)) << 6) | + (((key[2] & (0x80 >> i)) >> (7 - i)) << 5) | + (((key[3] & (0x80 >> i)) >> (7 - i)) << 4) | + (((key[4] & (0x80 >> i)) >> (7 - i)) << 3) | + (((key[5] & (0x80 >> i)) >> (7 - i)) << 2) | + (((key[6] & (0x80 >> i)) >> (7 - i)) << 1) | + (((key[7] & (0x80 >> i)) >> (7 - i)) << 0); + } +} + +/** + * Helper function for hash1 + * @brief rr + * @param val + * @return + */ +static inline uint8_t rr(uint8_t val) { + return val >> 1 | ((val & 1) << 7); +} + +/** + * Helper function for hash1 + * @brief rl + * @param val + * @return + */ +static inline uint8_t rl(uint8_t val) { + return val << 1 | ((val & 0x80) >> 7); +} + +/** + * Helper function for hash1 + * @brief swap + * @param val + * @return + */ +static inline uint8_t swap(uint8_t val) { + return ((val >> 4) & 0xFF) | ((val & 0xFF) << 4); +} + +/** + * Hash1 takes CSN as input, and determines what bytes in the keytable will be used + * when constructing the K_sel. + * @param csn the CSN used + * @param k output + */ +void hash1(uint8_t csn[], uint8_t k[]) { + k[0] = csn[0] ^ csn[1] ^ csn[2] ^ csn[3] ^ csn[4] ^ csn[5] ^ csn[6] ^ csn[7]; + k[1] = csn[0] + csn[1] + csn[2] + csn[3] + csn[4] + csn[5] + csn[6] + csn[7]; + k[2] = rr(swap(csn[2] + k[1])); + k[3] = rl(swap(csn[3] + k[0])); + k[4] = ~rr(csn[4] + k[2]) + 1; + k[5] = ~rl(csn[5] + k[3]) + 1; + k[6] = rr(csn[6] + (k[4] ^ 0x3c)); + k[7] = rl(csn[7] + (k[5] ^ 0xc3)); + + k[7] &= 0x7F; + k[6] &= 0x7F; + k[5] &= 0x7F; + k[4] &= 0x7F; + k[3] &= 0x7F; + k[2] &= 0x7F; + k[1] &= 0x7F; + k[0] &= 0x7F; +} +/** +Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8 as +rk(x [0] . . . x [7] , 0) = x [0] . . . x [7] +rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n) +**/ +static void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) { + memcpy(outp_key, key, 8); + uint8_t j; + while (n-- > 0) { + for (j = 0; j < 8 ; j++) + outp_key[j] = rl(outp_key[j]); + } + return; +} + +static mbedtls_des_context ctx_enc; +static mbedtls_des_context ctx_dec; + +static void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { + uint8_t key_std_format[8] = {0}; + permutekey_rev(iclass_key, key_std_format); + mbedtls_des_setkey_dec(&ctx_dec, key_std_format); + mbedtls_des_crypt_ecb(&ctx_dec, input, output); +} + +static void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { + uint8_t key_std_format[8] = {0}; + permutekey_rev(iclass_key, key_std_format); + mbedtls_des_setkey_enc(&ctx_enc, key_std_format); + mbedtls_des_crypt_ecb(&ctx_enc, input, output); +} + +/** + * @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select. + * @param key unpermuted custom key + * @param hash1 hash1 + * @param key_sel output key_sel=h[hash1[i]] + */ +void hash2(uint8_t *key64, uint8_t *outp_keytable) { + /** + *Expected: + * High Security Key Table + + 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 + 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 + 20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2 + 30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C + 40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6 + 50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42 + 60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95 + 70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB + + **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/ + uint8_t key64_negated[8] = {0}; + uint8_t z[8][8] = {{0}, {0}}; + uint8_t temp_output[8] = {0}; + + //calculate complement of key + int i; + for (i = 0; i < 8; i++) + key64_negated[i] = ~key64[i]; + + // Once again, key is on iclass-format + desencrypt_iclass(key64, key64_negated, z[0]); + + uint8_t y[8][8] = {{0}, {0}}; + + // y[0]=DES_dec(z[0],~key) + // Once again, key is on iclass-format + desdecrypt_iclass(z[0], key64_negated, y[0]); + + for (i = 1; i < 8; i++) { + rk(key64, i, temp_output); + desdecrypt_iclass(temp_output, z[i - 1], z[i]); + desencrypt_iclass(temp_output, y[i - 1], y[i]); + } + + if (outp_keytable != NULL) { + for (i = 0 ; i < 8 ; i++) { + memcpy(outp_keytable + i * 16, y[i], 8); + memcpy(outp_keytable + 8 + i * 16, z[i], 8); + } + } +} diff --git a/armsrc/optimized_elite.h b/armsrc/optimized_elite.h new file mode 100644 index 000000000..281ecf0bb --- /dev/null +++ b/armsrc/optimized_elite.h @@ -0,0 +1,62 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file 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 loclass. If not, see . + * + * + ****************************************************************************/ + + +#ifndef ELITE_CRACK_H +#define ELITE_CRACK_H + +#include +#include + +void permutekey(uint8_t key[8], uint8_t dest[8]); +/** + * Permutes a key from iclass specific format to NIST format + * @brief permutekey_rev + * @param key + * @param dest + */ +void permutekey_rev(uint8_t key[8], uint8_t dest[8]); +/** + * Hash1 takes CSN as input, and determines what bytes in the keytable will be used + * when constructing the K_sel. + * @param csn the CSN used + * @param k output + */ +void hash1(uint8_t *csn, uint8_t *k); +void hash2(uint8_t *key64, uint8_t *outp_keytable); + +#endif diff --git a/armsrc/optimized_ikeys.c b/armsrc/optimized_ikeys.c new file mode 100644 index 000000000..eeb00e562 --- /dev/null +++ b/armsrc/optimized_ikeys.c @@ -0,0 +1,324 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file 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 loclass. If not, see . + * + * + ****************************************************************************/ + +/** +From "Dismantling iclass": + This section describes in detail the built-in key diversification algorithm of iClass. + Besides the obvious purpose of deriving a card key from a master key, this + algorithm intends to circumvent weaknesses in the cipher by preventing the + usage of certain ‘weak’ keys. In order to compute a diversified key, the iClass + reader first encrypts the card identity id with the master key K, using single + DES. The resulting ciphertext is then input to a function called hash0 which + outputs the diversified key k. + + k = hash0(DES enc (id, K)) + + Here the DES encryption of id with master key K outputs a cryptogram c + of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] ∈ F 82 × F 82 × (F 62 ) 8 + which is used as input to the hash0 function. This function introduces some + obfuscation by performing a number of permutations, complement and modulo + operations, see Figure 2.5. Besides that, it checks for and removes patterns like + similar key bytes, which could produce a strong bias in the cipher. Finally, the + output of hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 . + +**/ +#include "optimized_ikeys.h" + +#include +#include +#include +#include "mbedtls/des.h" +#include "optimized_cipherutils.h" + +uint8_t pi[35] = { + 0x0F, 0x17, 0x1B, 0x1D, 0x1E, 0x27, 0x2B, 0x2D, + 0x2E, 0x33, 0x35, 0x39, 0x36, 0x3A, 0x3C, 0x47, + 0x4B, 0x4D, 0x4E, 0x53, 0x55, 0x56, 0x59, 0x5A, + 0x5C, 0x63, 0x65, 0x66, 0x69, 0x6A, 0x6C, 0x71, + 0x72, 0x74, 0x78 +}; + +static mbedtls_des_context ctx_enc; + +/** + * @brief The key diversification algorithm uses 6-bit bytes. + * This implementation uses 64 bit uint to pack seven of them into one + * variable. When they are there, they are placed as follows: + * XXXX XXXX N0 .... N7, occupying the last 48 bits. + * + * This function picks out one from such a collection + * @param all + * @param n bitnumber + * @return + */ +static uint8_t getSixBitByte(uint64_t c, int n) { + return (c >> (42 - 6 * n)) & 0x3F; +} + +/** + * @brief Puts back a six-bit 'byte' into a uint64_t. + * @param c buffer + * @param z the value to place there + * @param n bitnumber. + */ +static void pushbackSixBitByte(uint64_t *c, uint8_t z, int n) { + //0x XXXX YYYY ZZZZ ZZZZ ZZZZ + // ^z0 ^z7 + //z0: 1111 1100 0000 0000 + + uint64_t masked = z & 0x3F; + uint64_t eraser = 0x3F; + masked <<= 42 - 6 * n; + eraser <<= 42 - 6 * n; + + //masked <<= 6*n; + //eraser <<= 6*n; + + eraser = ~eraser; + (*c) &= eraser; + (*c) |= masked; + +} +/** + * @brief Swaps the z-values. + * If the input value has format XYZ0Z1...Z7, the output will have the format + * XYZ7Z6...Z0 instead + * @param c + * @return + */ +static uint64_t swapZvalues(uint64_t c) { + uint64_t newz = 0; + pushbackSixBitByte(&newz, getSixBitByte(c, 0), 7); + pushbackSixBitByte(&newz, getSixBitByte(c, 1), 6); + pushbackSixBitByte(&newz, getSixBitByte(c, 2), 5); + pushbackSixBitByte(&newz, getSixBitByte(c, 3), 4); + pushbackSixBitByte(&newz, getSixBitByte(c, 4), 3); + pushbackSixBitByte(&newz, getSixBitByte(c, 5), 2); + pushbackSixBitByte(&newz, getSixBitByte(c, 6), 1); + pushbackSixBitByte(&newz, getSixBitByte(c, 7), 0); + newz |= (c & 0xFFFF000000000000); + return newz; +} + +/** +* @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3 +*/ +static uint64_t ck(int i, int j, uint64_t z) { + if (i == 1 && j == -1) { + // ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] + return z; + } else if (j == -1) { + // ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] ) + return ck(i - 1, i - 2, z); + } + + if (getSixBitByte(z, i) == getSixBitByte(z, j)) { + //ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ) + uint64_t newz = 0; + int c; + for (c = 0; c < 4; c++) { + uint8_t val = getSixBitByte(z, c); + if (c == i) + pushbackSixBitByte(&newz, j, c); + else + pushbackSixBitByte(&newz, val, c); + } + return ck(i, j - 1, newz); + } else { + return ck(i, j - 1, z); + } +} +/** + + Definition 8. + Let the function check : (F 62 ) 8 → (F 62 ) 8 be defined as + check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] ) + + where ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as + + ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] + ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] ) + ck(i, j, z [0] . . . z [3] ) = + ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ), if z [i] = z [j] ; + ck(i, j − 1, z [0] . . . z [3] ), otherwise + + otherwise. +**/ + +static uint64_t check(uint64_t z) { + //These 64 bits are divided as c = x, y, z [0] , . . . , z [7] + + // ck(3, 2, z [0] . . . z [3] ) + uint64_t ck1 = ck(3, 2, z); + + // ck(3, 2, z [4] . . . z [7] ) + uint64_t ck2 = ck(3, 2, z << 24); + + //The ck function will place the values + // in the middle of z. + ck1 &= 0x00000000FFFFFF000000; + ck2 &= 0x00000000FFFFFF000000; + + return ck1 | ck2 >> 24; +} + +static void permute(BitstreamIn *p_in, uint64_t z, int l, int r, BitstreamOut *out) { + if (bitsLeft(p_in) == 0) + return; + + bool pn = tailBit(p_in); + if (pn) { // pn = 1 + uint8_t zl = getSixBitByte(z, l); + + push6bits(out, zl + 1); + permute(p_in, z, l + 1, r, out); + } else { // otherwise + uint8_t zr = getSixBitByte(z, r); + + push6bits(out, zr); + permute(p_in, z, l, r + 1, out); + } +} + +/** + * @brief + *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as + * hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where + * z'[i] = (z[i] mod (63-i)) + i i = 0...3 + * z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3 + * ẑ = check(z'); + * @param c + * @param k this is where the diversified key is put (should be 8 bytes) + * @return + */ +void hash0(uint64_t c, uint8_t k[8]) { + c = swapZvalues(c); + + //These 64 bits are divided as c = x, y, z [0] , . . . , z [7] + // x = 8 bits + // y = 8 bits + // z0-z7 6 bits each : 48 bits + uint8_t x = (c & 0xFF00000000000000) >> 56; + uint8_t y = (c & 0x00FF000000000000) >> 48; + uint64_t zP = 0; + + for (int n = 0; n < 4 ; n++) { + uint8_t zn = getSixBitByte(c, n); + uint8_t zn4 = getSixBitByte(c, n + 4); + uint8_t _zn = (zn % (63 - n)) + n; + uint8_t _zn4 = (zn4 % (64 - n)) + n; + pushbackSixBitByte(&zP, _zn, n); + pushbackSixBitByte(&zP, _zn4, n + 4); + } + + uint64_t zCaret = check(zP); + uint8_t p = pi[x % 35]; + + if (x & 1) //Check if x7 is 1 + p = ~p; + + BitstreamIn p_in = { &p, 8, 0 }; + uint8_t outbuffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; + BitstreamOut out = {outbuffer, 0, 0}; + permute(&p_in, zCaret, 0, 4, &out); //returns 48 bits? or 6 8-bytes + + //Out is now a buffer containing six-bit bytes, should be 48 bits + // if all went well + //Shift z-values down onto the lower segment + + uint64_t zTilde = x_bytes_to_num(outbuffer, sizeof(outbuffer)); + + zTilde >>= 16; + + for (int i = 0; i < 8; i++) { + // the key on index i is first a bit from y + // then six bits from z, + // then a bit from p + + // Init with zeroes + k[i] = 0; + // First, place yi leftmost in k + //k[i] |= (y << i) & 0x80 ; + + // First, place y(7-i) leftmost in k + k[i] |= (y << (7 - i)) & 0x80 ; + + uint8_t zTilde_i = getSixBitByte(zTilde, i); + // zTildeI is now on the form 00XXXXXX + // with one leftshift, it'll be + // 0XXXXXX0 + // So after leftshift, we can OR it into k + // However, when doing complement, we need to + // again MASK 0XXXXXX0 (0x7E) + zTilde_i <<= 1; + + //Finally, add bit from p or p-mod + //Shift bit i into rightmost location (mask only after complement) + uint8_t p_i = p >> i & 0x1; + + if (k[i]) { // yi = 1 + k[i] |= ~zTilde_i & 0x7E; + k[i] |= p_i & 1; + k[i] += 1; + + } else { // otherwise + k[i] |= zTilde_i & 0x7E; + k[i] |= (~p_i) & 1; + } + } +} +/** + * @brief Performs Elite-class key diversification + * @param csn + * @param key + * @param div_key + */ +void diversifyKey(uint8_t *csn, uint8_t *key, uint8_t *div_key) { + // Prepare the DES key + mbedtls_des_setkey_enc(&ctx_enc, key); + + uint8_t crypted_csn[8] = {0}; + + // Calculate DES(CSN, KEY) + mbedtls_des_crypt_ecb(&ctx_enc, csn, crypted_csn); + + //Calculate HASH0(DES)) + uint64_t c_csn = x_bytes_to_num(crypted_csn, sizeof(crypted_csn)); + + hash0(c_csn, div_key); +} + diff --git a/armsrc/optimized_ikeys.h b/armsrc/optimized_ikeys.h new file mode 100644 index 000000000..91fa406ad --- /dev/null +++ b/armsrc/optimized_ikeys.h @@ -0,0 +1,69 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file 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 loclass. If not, see . + * + * + ****************************************************************************/ + +#ifndef IKEYS_H +#define IKEYS_H + +#include + +/** + * @brief + *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as + * hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where + * z'[i] = (z[i] mod (63-i)) + i i = 0...3 + * z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3 + * ẑ = check(z'); + * @param c + * @param k this is where the diversified key is put (should be 8 bytes) + * @return + */ +void hash0(uint64_t c, uint8_t k[8]); +/** + * @brief Performs Elite-class key diversification + * @param csn + * @param key + * @param div_key + */ + +void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]); +/** + * @brief Permutes a key from standard NIST format to Iclass specific format + * @param key + * @param dest + */ + +#endif // IKEYS_H diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 1eda5678b..62ba0f70a 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1158,28 +1158,22 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v } static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) { - uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - if (select_only(CSN, CCNR, use_credit_key, verbose) == false) { - if (verbose) PrintAndLogEx(FAILED, "selecting tag failed"); -// DropField(); - return false; - } - - //get div_key - if (rawkey) - memcpy(div_key, KEY, 8); - else - HFiClassCalcDivKey(CSN, KEY, div_key, elite); - - if (verbose) PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); - - doMAC(CCNR, div_key, MAC); - + + struct { + uint8_t key[8]; + bool use_raw; + bool use_elite; + bool use_credit_key; + } PACKED payload; + + memcpy(payload.key, KEY, 8); + payload.use_raw = rawkey; + payload.use_elite = elite; + payload.use_credit_key = use_credit_key; + + SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t*)&payload, sizeof(payload)); PacketResponseNG resp; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_AUTH, MAC, 4); + clearCommandBuffer(); if (WaitForResponseTimeout(CMD_HF_ICLASS_AUTH, &resp, 2000) == 0) { if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); return false; @@ -1190,12 +1184,25 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u return false; } - uint8_t isOK = resp.data.asBytes[0]; - if (isOK == 0) { + struct p { + bool isOK; + uint8_t div_key[8]; + uint8_t mac[4]; + } PACKED; + struct p *packet = (struct p *)resp.data.asBytes; + + if (packet->isOK == 0) { if (verbose) PrintAndLogEx(FAILED, "authentication error"); return false; } - + + if (div_key) + memcpy(div_key, packet->div_key, sizeof(packet->div_key)); + + if (MAC) + memcpy(MAC, packet->mac, sizeof(packet->mac)); + + if (verbose) PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); return true; } @@ -2972,7 +2979,7 @@ int readIclass(bool loop, bool verbose) { uint8_t readStatus = resp.oldarg[0] & 0xff; - PrintAndLogEx(NORMAL, "ICE: %x", readStatus); +// PrintAndLogEx(NORMAL, "ICE: %x", readStatus); // no tag found or button pressed if ((readStatus == 0 && !loop) || readStatus == 0xFF) { From f866a847fb0896b6639024f893ffb09b64004897 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 11 Jul 2020 20:46:37 +0200 Subject: [PATCH 041/139] fix coverity 294114 --- client/src/cmdlfem4x50.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 8198bdc74..77476e5d9 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -608,10 +608,11 @@ int CmdEM4x50Dump(const char *Cmd) { em4x50_data_t etd; etd.pwd_given = false; etd.addr_given = false; - + etd.newpwd_given = false; + char filename[FILE_PATH_SIZE] = {0x00}; char *fptr = filename; - + bool errors = false; uint8_t cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -655,9 +656,9 @@ int CmdEM4x50Dump(const char *Cmd) { bool success = (resp.status & STATUS_SUCCESS) >> 1; if (success == false) { PrintAndLogEx(FAILED, "reading tag " _RED_("failed")); - return PM3_ESOFT; + return PM3_ESOFT; } - + // structured format em4x50_word_t words[EM4X50_NO_WORDS]; prepare_result(resp.data.asBytes, 0, EM4X50_NO_WORDS - 1, words); From ebb7eb9f3ed75f206141eab6a510226cbd46d0da Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 11 Jul 2020 20:53:07 +0200 Subject: [PATCH 042/139] fix coverity 294113 --- armsrc/em4x50.c | 71 +++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 63b58e5bd..2b9ede4bf 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -100,7 +100,6 @@ int gLow = 0; static void init_tag(void) { // initialize global tag structure - for (int i = 0; i < 34; i++) for (int j = 0; j < 7; j++) tag.sectors[i][j] = 0x00; @@ -109,9 +108,7 @@ static void init_tag(void) { static uint8_t bits2byte(uint8_t *bits, int length) { // converts separate bits into a single "byte" - uint8_t byte = 0; - for (int i = 0; i < length; i++) { byte |= bits[i]; @@ -124,11 +121,10 @@ static uint8_t bits2byte(uint8_t *bits, int length) { } static void msb2lsb_word(uint8_t *word) { - + // reorders given according to EM4x50 datasheet (msb -> lsb) - + uint8_t buff[4]; - buff[0] = reflect8(word[3]); buff[1] = reflect8(word[2]); buff[2] = reflect8(word[1]); @@ -141,13 +137,12 @@ static void msb2lsb_word(uint8_t *word) { } static void save_word(int pos, uint8_t bits[EM4X50_TAG_WORD]) { - + // split "raw" word into data, row and column parity bits and stop bit and // save them in global tag structure - uint8_t row_parity[4]; uint8_t col_parity[8]; - + // data and row parities for (int i = 0; i < 4; i++) { tag.sectors[pos][i] = bits2byte(&bits[9*i],8); @@ -161,7 +156,7 @@ static void save_word(int pos, uint8_t bits[EM4X50_TAG_WORD]) { col_parity[i] = bits[36+i]; tag.sectors[pos][5] = bits2byte(col_parity,8); - + // stop bit tag.sectors[pos][6] = bits[44]; } @@ -169,7 +164,7 @@ static void save_word(int pos, uint8_t bits[EM4X50_TAG_WORD]) { static void wait_timer(int timer, uint32_t period) { // do nothing for using timer - + if (timer == FPGA_TIMER_0) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; @@ -184,9 +179,8 @@ static void wait_timer(int timer, uint32_t period) { } static void em4x50_setup_read(void) { - + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); // 50ms for the resonant antenna to settle. @@ -195,12 +189,12 @@ static void em4x50_setup_read(void) { FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); // start a 1.5ticks is 1us StartTicks(); - + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); // Connect the A/D to the peak-detected low-frequency path. SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - + // Steal this pin from the SSP (SPI communication channel with fpga) and // use it to control the modulation AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; @@ -208,7 +202,7 @@ static void em4x50_setup_read(void) { // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); - + // Enable Peripheral Clock for // TIMER_CLOCK0, used to measure exact timing before answering // TIMER_CLOCK1, used to capture edges of the tag frames @@ -221,17 +215,17 @@ static void em4x50_setup_read(void) { // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - + // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - + // synchronized startup procedure while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero - + // Watchdog hit WDT_HIT(); } @@ -239,21 +233,21 @@ static void em4x50_setup_read(void) { // functions for "reader" use case static bool get_signalproperties(void) { - + // calculate signal properties (mean amplitudes) from measured data: // 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow - + bool signal_found = false; int no_periods = 32, pct = 75, noise = 140; - uint8_t sample = 0, sample_ref = 127; + uint8_t sample_ref = 127; uint8_t sample_max_mean = 0; uint8_t sample_max[no_periods]; uint32_t sample_max_sum = 0; + memcpy(sample_max, 0x00, sizeof(sample_max)); - // wait until signal/noise > 1 (max. 32 periods) for (int i = 0; i < T0 * no_periods; i++) { - + // about 2 samples per bit period wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); @@ -261,9 +255,9 @@ static bool get_signalproperties(void) { signal_found = true; break; } - + } - + if (!signal_found) return false; @@ -273,39 +267,36 @@ static bool get_signalproperties(void) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < T0 * 3 * EM4X50_T_TAG_FULL_PERIOD) { - - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - + + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if (sample > sample_max[i]) sample_max[i] = sample; - + } - + sample_max_sum += sample_max[i]; } - + sample_max_mean = sample_max_sum / no_periods; - + // set global envelope variables gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100; gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100; - return true; } static int get_next_bit(void) { - + // returns bit value (or EM4X50_BIT_OTHER -> no bit pattern) by evaluating // a single sample within a bit period (given there is no LIW, ACK or NAK) // This function is not used for decoding, it is only used for identifying // a listen window (return value = EM4X50_BIT_OTHER) in functions // "find_double_listen_window" and "check_ack" - - uint8_t sample; // get sample at 3/4 of bit period wait_timer(0, T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // wait until end of bit period wait_timer(0, T0 * EM4X50_T_TAG_QUARTER_PERIOD); @@ -315,7 +306,7 @@ static int get_next_bit(void) { return EM4X50_BIT_0; else if (sample < gLow) return EM4X50_BIT_1; - + return EM4X50_BIT_OTHER; } From 86538912a840a1cec8730e2a5c6dc746d16e3cb4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:18:26 +0200 Subject: [PATCH 043/139] make sure uninitialized vars doesnt end up on COMMON_section --- armsrc/Makefile | 2 +- bootrom/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 2768ab3a4..8b1fbfc2b 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -20,7 +20,7 @@ endif #in the next section to remove that particular feature from compilation. # NO space,TABs after the "\" sign. APP_CFLAGS = $(PLATFORM_DEFS) \ - -ffunction-sections -fdata-sections + -ffunction-sections -fdata-sections -fno-common SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c SRC_ISO15693 = iso15693.c iso15693tools.c diff --git a/bootrom/Makefile b/bootrom/Makefile index 75a4e5ced..9a0359d2f 100644 --- a/bootrom/Makefile +++ b/bootrom/Makefile @@ -25,8 +25,8 @@ VERSIONSRC = version.c # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS = -I. -ffunction-sections -fdata-sections -# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc -APP_CFLAGS += -fno-stack-protector -fno-pie +# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc, no-common makes sure uninitalized vars doesn't end up in COMMON area +APP_CFLAGS += -fno-stack-protector -fno-pie -fno-common # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC From 1f8ab9c2fbb17c085cb30e99fffd090ce58f0616 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:19:06 +0200 Subject: [PATCH 044/139] better logtext for debug, iclass dump -> NG --- armsrc/appmain.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index a50c0ba7d..e35dc8ae2 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -69,13 +69,11 @@ //============================================================================= #define TOSEND_BUFFER_SIZE (9*MAX_FRAME_SIZE + 1 + 1 + 2) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits -uint8_t ToSend[TOSEND_BUFFER_SIZE]; +uint8_t ToSend[TOSEND_BUFFER_SIZE] = {0}; int ToSendMax = -1; +static int ToSendBit; extern uint32_t _stack_start, _stack_end; - - -static int ToSendBit; struct common_area common_area __attribute__((section(".commonarea"))); static int button_status = BUTTON_NO_CLICK; static bool allow_send_wtx = false; @@ -375,7 +373,26 @@ static void SendStatus(void) { print_stack_usage(); - Dbprintf(" DBGLEVEL................%d", DBGLEVEL); + char dbglvlstr[20] = {0}; + switch(DBGLEVEL) { + case DBG_NONE: + sprintf(dbglvlstr, "NONE"); + break; + case DBG_ERROR: + sprintf(dbglvlstr, "ERROR"); + break; + case DBG_INFO: + sprintf(dbglvlstr, "INFO"); + break; + case DBG_DEBUG: + sprintf(dbglvlstr, "DEBUG"); + break; + case DBG_EXTENDED: + sprintf(dbglvlstr, "EXTENDED"); + break; + } + Dbprintf(" DBGLEVEL................%d ( " _YELLOW_("%s")" )", DBGLEVEL, dbglvlstr); + Dbprintf(" ToSendMax...............%d", ToSendMax); Dbprintf(" ToSendBit...............%d", ToSendBit); Dbprintf(" ToSend BUFFERSIZE.......%d", TOSEND_BUFFER_SIZE); @@ -1453,7 +1470,12 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ICLASS_DUMP: { - iClass_Dump(packet->oldarg[0], packet->oldarg[1]); + struct p { + uint8_t start_blockno; + uint8_t numblks; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + iClass_Dump(payload->start_blockno, payload->numblks); break; } case CMD_HF_ICLASS_CLONE: { From 27c4d994ac12bbe5e50e56f31fc3ed90bb198514 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:20:12 +0200 Subject: [PATCH 045/139] remove some debugstatments, use hdr.frame instead --- armsrc/BigBuf.c | 22 +++++++++------------- armsrc/BigBuf.h | 2 +- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 8637443a0..24fe45e57 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -164,7 +164,7 @@ uint32_t BigBuf_get_traceLen(void) { **/ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) { if (tracing == false) { - if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("trace is turned off"); } + Dbprintf("trace is turned off"); return false; } @@ -175,8 +175,7 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ // Return when trace is full if (TRACELOG_HDR_LEN + iLen + num_paritybytes >= BigBuf_max_traceLen() - trace_len) { - tracing = false; // don't trace any more - if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("trace is full"); } + tracing = false; return false; } @@ -188,27 +187,24 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ } if (duration > 0x7FFF) { - if (DBGLEVEL >= DBG_DEBUG) { - Dbprintf("Error in LogTrace: duration too long for 15 bits encoding: 0x%08x start:0x%08x end:0x%08x", duration, timestamp_start, timestamp_end); -// Dbprintf("Forcing duration = 0"); + if (DBGLEVEL >= DBG_ERROR) { //DBG_DEBUG + Dbprintf("Error in LogTrace: duration too long for 15 bits encoding: 0x%08x start: 0x%08x end: 0x%08x", duration, timestamp_start, timestamp_end); } - duration /= 32; - // duration >>= 5; // duration = 0; } - + hdr->timestamp = timestamp_start; - hdr->duration = duration; + hdr->duration = duration & 0x7FFF; hdr->data_len = iLen; hdr->isResponse = !readerToTag; trace_len += TRACELOG_HDR_LEN; // data bytes if (btBytes != NULL && iLen != 0) { - memcpy(trace + trace_len, btBytes, iLen); + memcpy(hdr->frame, btBytes, iLen); + trace_len += iLen; } - trace_len += iLen; // parity bytes if (num_paritybytes != 0) { @@ -217,8 +213,8 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ } else { memset(trace + trace_len, 0x00, num_paritybytes); } + trace_len += num_paritybytes; } - trace_len += num_paritybytes; return true; } diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 60857e82a..b89b94242 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -19,7 +19,7 @@ #define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC #define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these #define CARD_MEMORY_SIZE 4096 -#define DMA_BUFFER_SIZE 256 //128 (how big is the dma?!? +#define DMA_BUFFER_SIZE 128 uint8_t *BigBuf_get_addr(void); uint32_t BigBuf_get_size(void); From 77aa5c614208e6801cd69a51ea31fe786ad4c96b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:20:35 +0200 Subject: [PATCH 046/139] style --- armsrc/iso14443a.c | 1 - 1 file changed, 1 deletion(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 836360740..0dae3c872 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2554,7 +2554,6 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { hf_field_active = true; } - void hf_field_off(void) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); From 713301226dd5ff6049898115ca9804930c9261cd Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:21:42 +0200 Subject: [PATCH 047/139] fgpa merge hell p.N --- armsrc/iclass.c | 510 +++++++++++++++++++++++------------------------- 1 file changed, 246 insertions(+), 264 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index a68565830..58cf36a0d 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -15,27 +15,6 @@ // // Please feel free to contribute and extend iClass support!! //----------------------------------------------------------------------------- -// -// FIX: -// ==== -// We still have sometimes a demodulation error when sniffing iClass communication. -// The resulting trace of a read-block-03 command may look something like this: -// -// + 22279: : 0c 03 e8 01 -// -// ...with an incorrect answer... -// -// + 85: 0: TAG ff! ff! ff! ff! ff! ff! ff! ff! bb 33 bb 00 01! 0e! 04! bb !crc -// -// We still left the error signalling bytes in the traces like 0xbb -// -// A correct trace should look like this: -// -// + 21112: : 0c 03 e8 01 -// + 85: 0: TAG ff ff ff ff ff ff ff ff ea f5 -// -//----------------------------------------------------------------------------- - #include "iclass.h" #include "proxmark3_arm.h" @@ -78,11 +57,6 @@ #define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1) -static void OnError(uint8_t reason) { - reply_mix(CMD_ACK, 0, reason, 0, 0, 0); - switch_off(); -} - /* * CARD TO READER * in ISO15693-2 mode - Manchester @@ -116,9 +90,9 @@ static void rotateCSN(uint8_t *original_csn, uint8_t *rotated_csn) { // Encode SOF only static void CodeIClassTagSOF(void) { - ToSendReset(); - ToSend[++ToSendMax] = 0x1D; - ToSendMax++; + ToSendReset(); + ToSend[++ToSendMax] = 0x1D; + ToSendMax++; } @@ -177,7 +151,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain LEDsoff(); - Iso15693InitTag(); + Iso15693InitTag(); clear_trace(); set_tracing(true); @@ -280,13 +254,13 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // free eventually allocated BigBuf memory BigBuf_free_keep_EM(); - uint16_t page_size = 32 * 8; - uint8_t current_page = 0; + uint16_t page_size = 32 * 8; + uint8_t current_page = 0; - // maintain cipher states for both credit and debit key for each page - State cipher_state_KD[8]; - State cipher_state_KC[8]; - State *cipher_state = &cipher_state_KD[0]; + // maintain cipher states for both credit and debit key for each page + State cipher_state_KD[8]; + State cipher_state_KC[8]; + State *cipher_state = &cipher_state_KD[0]; uint8_t *emulator = BigBuf_get_EM_addr(); uint8_t *csn = emulator; @@ -303,12 +277,12 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { AddCrc(anticoll_data, 8); AddCrc(csn_data, 8); - uint8_t diversified_kd[8] = { 0 }; - uint8_t diversified_kc[8] = { 0 }; - uint8_t *diversified_key = diversified_kd; + uint8_t diversified_kd[8] = { 0 }; + uint8_t diversified_kc[8] = { 0 }; + uint8_t *diversified_key = diversified_kd; - // configuration block - uint8_t conf_block[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; + // configuration block + uint8_t conf_block[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; // e-Purse uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -318,10 +292,10 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { if (simulationMode == ICLASS_SIM_MODE_FULL) { - memcpy(conf_block, emulator + (8 * 1), 8); // blk 1 - memcpy(card_challenge_data, emulator + (8 * 2), 8); // e-purse, blk 2 - memcpy(diversified_kd, emulator + (8 * 3), 8); // Kd, blk 3 - memcpy(diversified_kc, emulator + (8 * 4), 8); // Kc, blk 4 + memcpy(conf_block, emulator + (8 * 1), 8); // blk 1 + memcpy(card_challenge_data, emulator + (8 * 2), 8); // e-purse, blk 2 + memcpy(diversified_kd, emulator + (8 * 3), 8); // Kd, blk 3 + memcpy(diversified_kc, emulator + (8 * 4), 8); // Kc, blk 4 // (iceman) this only works for 2KS / 16KS tags. @@ -338,36 +312,36 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(reader_mac_buf, card_challenge_data, 8); } - if ((conf_block[5] & 0x80) == 0x80) { - page_size = 256 * 8; - } + if ((conf_block[5] & 0x80) == 0x80) { + page_size = 256 * 8; + } - // From PicoPass DS: - // When the page is in personalization mode this bit is equal to 1. - // Once the application issuer has personalized and coded its dedicated areas, this bit must be set to 0: - // the page is then "in application mode". - bool personalization_mode = conf_block[7] & 0x80; + // From PicoPass DS: + // When the page is in personalization mode this bit is equal to 1. + // Once the application issuer has personalized and coded its dedicated areas, this bit must be set to 0: + // the page is then "in application mode". + bool personalization_mode = conf_block[7] & 0x80; - // chip memory may be divided in 8 pages - uint8_t max_page = ((conf_block[4] & 0x10) == 0x10) ? 0 : 7; + // chip memory may be divided in 8 pages + uint8_t max_page = ((conf_block[4] & 0x10) == 0x10) ? 0 : 7; - // Precalculate the cipher states, feeding it the CC - cipher_state_KD[0] = opt_doTagMAC_1(card_challenge_data, diversified_kd); - cipher_state_KC[0] = opt_doTagMAC_1(card_challenge_data, diversified_kc); + // Precalculate the cipher states, feeding it the CC + cipher_state_KD[0] = opt_doTagMAC_1(card_challenge_data, diversified_kd); + cipher_state_KC[0] = opt_doTagMAC_1(card_challenge_data, diversified_kc); - if (simulationMode == ICLASS_SIM_MODE_FULL) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { - for (int i = 1; i < max_page; i++) { + for (int i = 1; i < max_page; i++) { // does all pages has their own epurse??) - uint8_t *epurse = emulator + (i * page_size) + (8 * 2); - uint8_t *kd = emulator + (i * page_size) + (8 * 3); - uint8_t *kc = emulator + (i * page_size) + (8 * 4); + uint8_t *epurse = emulator + (i * page_size) + (8 * 2); + uint8_t *kd = emulator + (i * page_size) + (8 * 3); + uint8_t *kc = emulator + (i * page_size) + (8 * 4); - cipher_state_KD[i] = opt_doTagMAC_1(epurse, kd); - cipher_state_KC[i] = opt_doTagMAC_1(epurse, kc); - } - } + cipher_state_KD[i] = opt_doTagMAC_1(epurse, kd); + cipher_state_KC[i] = opt_doTagMAC_1(epurse, kc); + } + } // Anti-collision process: // Reader 0a @@ -405,11 +379,11 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t *resp_cc = BigBuf_malloc(28); int resp_cc_len; - // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only - uint8_t *resp_ff = BigBuf_malloc(22); - int resp_ff_len; - uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; - AddCrc(ff_data, 8); + // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only + uint8_t *resp_ff = BigBuf_malloc(22); + int resp_ff_len; + uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; + AddCrc(ff_data, 8); // Application Issuer Area (blk 5) uint8_t *resp_aia = BigBuf_malloc(28); @@ -446,10 +420,10 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; - // Kd, Kc (blocks 3 and 4) - CodeIso15693AsTag(ff_data, sizeof(ff_data)); - memcpy(resp_ff, ToSend, ToSendMax); - resp_ff_len = ToSendMax; + // Kd, Kc (blocks 3 and 4) + CodeIso15693AsTag(ff_data, sizeof(ff_data)); + memcpy(resp_ff, ToSend, ToSendMax); + resp_ff_len = ToSendMax; // Application Issuer Area (block 5) CodeIso15693AsTag(aia_data, sizeof(aia_data)); @@ -464,7 +438,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) uint8_t *data_response = BigBuf_malloc((32 + 2) * 2 + 2); - enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; + enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; bool button_pressed = false; uint8_t cmd, options, block; @@ -474,20 +448,20 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { while (exit_loop == false) { WDT_HIT(); - uint32_t reader_eof_time = 0; - len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); + uint32_t reader_eof_time = 0; + len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); if (len < 0) { button_pressed = true; exit_loop = true; continue; } - // Now look at the reader command and provide appropriate responses - // default is no response: - modulated_response = NULL; - modulated_response_size = 0; - trace_data = NULL; - trace_data_size = 0; + // Now look at the reader command and provide appropriate responses + // default is no response: + modulated_response = NULL; + modulated_response_size = 0; + trace_data = NULL; + trace_data_size = 0; // extra response data cmd = receivedCmd[0] & 0xF; @@ -499,7 +473,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { if (chip_state != HALTED) { modulated_response = resp_sof; modulated_response_size = resp_sof_len; - chip_state = ACTIVATED; + chip_state = ACTIVATED; goto send; } @@ -544,13 +518,13 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } goto send; } - case 3: - case 4: { // Kd, Kc, always respond with 0xff bytes - modulated_response = resp_ff; - modulated_response_size = resp_ff_len; - trace_data = ff_data; - trace_data_size = sizeof(ff_data); - goto send; + case 3: + case 4: { // Kd, Kc, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + goto send; } case 5: { // Application Issuer Area (0c 05) modulated_response = resp_aia; @@ -588,7 +562,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (cmd == ICLASS_CMD_READCHECK) { // 0x88 // Read e-purse KD (88 02) KC (18 02) - if (chip_state == SELECTED) { + if (chip_state == SELECTED) { if ( ICLASS_DEBIT(cmd) ){ cipher_state = &cipher_state_KD[current_page]; diversified_key = diversified_kd; @@ -601,7 +575,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = card_challenge_data; trace_data_size = sizeof(card_challenge_data); goto send; - } + } } else if (cmd == ICLASS_CMD_CHECK) { // 0x05 // Reader random and reader MAC!!! @@ -645,7 +619,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (cmd == ICLASS_CMD_HALT && options == 0 && len == 1) { - if (chip_state == SELECTED) { + if (chip_state == SELECTED) { // Reader ends the session modulated_response = resp_sof; modulated_response_size = resp_sof_len; @@ -655,7 +629,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06 - if (chip_state == SELECTED) { + if (chip_state == SELECTED) { //Read block memcpy(data_generic_trace, emulator + (current_page * page_size) + (block * 8), 8 * 4); AddCrc(data_generic_trace, 8 * 4); @@ -669,86 +643,86 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { - // We're expected to respond with the data+crc, exactly what's already in the receivedCmd - // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b - if (chip_state == SELECTED) { + // We're expected to respond with the data+crc, exactly what's already in the receivedCmd + // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b + if (chip_state == SELECTED) { - if (block == 2) { // update e-purse - memcpy(card_challenge_data, receivedCmd + 2, 8); - CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); - memcpy(resp_cc, ToSend, ToSendMax); - resp_cc_len = ToSendMax; - cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); - cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); + if (block == 2) { // update e-purse + memcpy(card_challenge_data, receivedCmd + 2, 8); + CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); + memcpy(resp_cc, ToSend, ToSendMax); + resp_cc_len = ToSendMax; + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); + cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); } else if (block == 3) { // update Kd - for (int i = 0; i < 8; i++) { - if (personalization_mode) { - diversified_kd[i] = receivedCmd[2 + i]; - } else { - diversified_kd[i] ^= receivedCmd[2 + i]; - } - } - cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); + for (int i = 0; i < 8; i++) { + if (personalization_mode) { + diversified_kd[i] = receivedCmd[2 + i]; + } else { + diversified_kd[i] ^= receivedCmd[2 + i]; + } + } + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); - } else if (block == 4) { // update Kc - for (int i = 0; i < 8; i++) { - if (personalization_mode) { - diversified_kc[i] = receivedCmd[2 + i]; - } else { - diversified_kc[i] ^= receivedCmd[2 + i]; - } - } - cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); + } else if (block == 4) { // update Kc + for (int i = 0; i < 8; i++) { + if (personalization_mode) { + diversified_kc[i] = receivedCmd[2 + i]; + } else { + diversified_kc[i] ^= receivedCmd[2 + i]; + } + } + cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); } // update emulator memcpy(emulator + (current_page * page_size) + (8 * block), receivedCmd + 2, 8); - memcpy(data_generic_trace, receivedCmd + 2, 8); - AddCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - } + memcpy(data_generic_trace, receivedCmd + 2, 8); + AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } goto send; } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { // 0x84 - // Pagesel, + // Pagesel, // - enables to select a page in the selected chip memory and return its configuration block - // Chips with a single page will not answer to this command - // Otherwise, we should answer 8bytes (conf block 1) + 2bytes CRC - if (chip_state == SELECTED) { + // Chips with a single page will not answer to this command + // Otherwise, we should answer 8bytes (conf block 1) + 2bytes CRC + if (chip_state == SELECTED) { - if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { + if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { - current_page = receivedCmd[1]; + current_page = receivedCmd[1]; - memcpy(data_generic_trace, emulator + (current_page * page_size) + (8 * 1), 8); - memcpy(diversified_kd, emulator + (current_page * page_size) + (8 * 3), 8); - memcpy(diversified_kc, emulator + (current_page * page_size) + (8 * 4), 8); + memcpy(data_generic_trace, emulator + (current_page * page_size) + (8 * 1), 8); + memcpy(diversified_kd, emulator + (current_page * page_size) + (8 * 3), 8); + memcpy(diversified_kc, emulator + (current_page * page_size) + (8 * 4), 8); - cipher_state = &cipher_state_KD[current_page]; + cipher_state = &cipher_state_KD[current_page]; - personalization_mode = data_generic_trace[7] & 0x80; - AddCrc(data_generic_trace, 8); + personalization_mode = data_generic_trace[7] & 0x80; + AddCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; + trace_data = data_generic_trace; + trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - } - } + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } + } // } else if(receivedCmd[0] == ICLASS_CMD_DETECT) { // 0x0F - } else if (receivedCmd[0] == 0x26 && len == 5) { - // standard ISO15693 INVENTORY command. Ignore. + } else if (receivedCmd[0] == 0x26 && len == 5) { + // standard ISO15693 INVENTORY command. Ignore. } else { // Never seen this command before if (DBGLEVEL >= DBG_EXTENDED) @@ -762,7 +736,7 @@ send: if (modulated_response_size > 0) { uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM; TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); - LogTrace(trace_data, trace_data_size, response_time * 32, (response_time * 32) + (modulated_response_size * 32 * 64), NULL, false); + LogTrace(trace_data, trace_data_size, response_time * 32, (response_time * 32) + (modulated_response_size * 32 * 64), NULL, false); } } @@ -776,20 +750,16 @@ send: // THE READER CODE -// logs. static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time) { - - CodeIso15693AsReader(frame, len); - TransmitTo15693Tag(ToSend, ToSendMax, start_time); - uint32_t end_time = *start_time + (32 * ((8 * ToSendMax) - 4)); // substract the 4 padding bits after EOF - - if (LogTrace(frame, len, (*start_time * 4), (end_time * 4), NULL, true) == false) - DbpString("send_as_reader: failed logtrace"); + CodeIso15693AsReader(frame, len); + TransmitTo15693Tag(ToSend, ToSendMax, start_time); + uint32_t end_time = *start_time + (32 * ((8 * ToSendMax) - 4)); // substract the 4 padding bits after EOF + LogTrace(frame, len, (*start_time * 4), (end_time * 4), NULL, true); } static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* resp, size_t max_resp_size, - uint8_t expected_size, uint8_t tries, uint32_t start_time, - uint32_t timeout, uint32_t *eof_time) { + uint8_t expected_size, uint8_t tries, uint32_t start_time, + uint16_t timeout, uint32_t *eof_time) { while (tries-- > 0) { iclass_send_as_reader(cmd, cmdsize, &start_time); @@ -797,9 +767,10 @@ static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* if (resp == NULL) return true; - if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time)) { + if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time)) { return true; } + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; } return false; } @@ -816,7 +787,7 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; static uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; + static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; static uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; @@ -826,19 +797,26 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t if (use_credit_key) read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; - uint32_t start_time = GetCountSspClk(); - iclass_send_as_reader(act_all, sizeof(act_all), &start_time); + set_tracing(true); - // card present? - int len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time); - if (len < 0) { - Dbprintf("Fail act all (%d)", len); - return false; - } + int len; + uint32_t start_time; + uint8_t tries = 10; + do { + // wakeup + start_time = GetCountSspClk(); + iclass_send_as_reader(act_all, 1, &start_time); + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time); + if (len >= 0) { + break; + } else if (len == -2) { + return false; + } + } while (tries-- > 0); // send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(identify, 1, &start_time); + iclass_send_as_reader(identify, 1, &start_time); // expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); @@ -849,36 +827,36 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t memcpy(&select[1], resp, 8); // select the card - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(select, sizeof(select), &start_time); + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + iclass_send_as_reader(select, sizeof(select), &start_time); // expect a 10-byte response here, 8 byte CSN and 2 byte CRC - len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); + if (len != 10) return false; //Save CSN in response data memcpy(card_data, resp, 8); // card selected, now read config (block1) (only 8 bytes no CRC) - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time); + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time); // expect a 8-byte response here - len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); + if (len != 10) return false; //Save CONF in response data memcpy(card_data + 8, resp, 8); // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time); + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time); // expect a 8-byte response here - len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 8) + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); + if (len != 8) return false; //Save CC (e-purse) in response data @@ -893,25 +871,23 @@ void ReaderIClass(uint8_t flags) { uint8_t card_data[6 * 8] = {0xFF}; // uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t resp[ICLASS_BUFFER_SIZE]; - -// memset(card_data, 0xFF, sizeof(card_data)); memset(resp, 0xFF, sizeof(resp)); // bool flag_readonce = flags & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully bool use_credit_key = flags & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key bool flag_read_aia = flags & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area - if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) { - switch_off(); - Iso15693InitReader(); - StartCountSspClk(); - } - - if ((flags & FLAG_ICLASS_READER_CLEARTRACE) == FLAG_ICLASS_READER_CLEARTRACE) { - clear_trace(); - } + if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) { + Iso15693InitReader(); + } - uint32_t eof_time = 0; + set_tracing(true); + + if ((flags & FLAG_ICLASS_READER_CLEARTRACE) == FLAG_ICLASS_READER_CLEARTRACE) { + clear_trace(); + } + + uint32_t eof_time = 0; bool status = select_iclass_tag(card_data, use_credit_key, &eof_time); if (status == false) { reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); @@ -926,7 +902,7 @@ void ReaderIClass(uint8_t flags) { if (flag_read_aia) { //Read App Issuer Area block CRC(0x05) => 0xde 0x64 uint8_t read_aa[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - status = iclass_send_cmd_with_retries(read_aa, sizeof(read_aa), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + status = iclass_send_cmd_with_retries(read_aa, sizeof(read_aa), resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); if (status) { result_status |= FLAG_ICLASS_AIA; memcpy(card_data + (8 * 5), resp, 8); @@ -944,7 +920,7 @@ void ReaderIClass(uint8_t flags) { // //Then we can 'ship' back the 6 * 8 bytes of data, // with 0xFF:s in block 3 and 4. - + LED_B_ON(); reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); @@ -968,7 +944,8 @@ void ReaderIClass(uint8_t flags) { // } else { // reply_mix(CMD_ACK, result_status, 0, 0, card_data, 0); // } - switch_off(); + + switch_off(); } // turn off afterwards @@ -991,8 +968,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { int keyaccess; } memory; - uint32_t start_time = 0; - uint32_t eof_time = 0; + uint32_t start_time = 0; + uint32_t eof_time = 0; while (BUTTON_PRESS() == false) { WDT_HIT(); @@ -1105,8 +1082,9 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { uint8_t readcheck[] = { keytype, blockno }; uint8_t resp[8] = {0}; - uint32_t eof_time = 0; - bool isOK = iclass_send_cmd_with_retries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + uint32_t eof_time = 0; +// start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + bool isOK = iclass_send_cmd_with_retries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); switch_off(); } @@ -1131,15 +1109,14 @@ void iClass_Authentication(uint8_t *bytes) { uint8_t mac[4]; } PACKED packet; - Iso15693InitReader(); - StartCountSspClk(); + Iso15693InitReader(); uint8_t card_data[3 * 8] = {0xFF}; uint32_t eof_time = 0; packet.isOK = select_iclass_tag(card_data, payload->use_credit_key, &eof_time); if (packet.isOK == false) { - reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&packet, sizeof(packet)); + reply_ng(CMD_HF_ICLASS_AUTH, PM3_ESOFT, (uint8_t *)&packet, sizeof(packet)); return; } uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -1163,7 +1140,8 @@ void iClass_Authentication(uint8_t *bytes) { uint8_t resp[ICLASS_BUFFER_SIZE]; packet.isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - reply_ng(CMD_HF_ICLASS_AUTH, PM3_SUCCESS, (uint8_t *)&packet, sizeof(packet)); + + reply_ng(CMD_HF_ICLASS_AUTH, (packet.isOK)? PM3_SUCCESS : PM3_ESOFT, (uint8_t *)&packet, sizeof(packet)); } typedef struct iclass_premac { @@ -1198,21 +1176,18 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { LED_A_ON(); + // fresh start switch_off(); SpinDelay(20); + + Iso15693InitReader(); - - bool read_status = false; uint32_t start_time = 0; uint32_t eof_time = 0; - uint8_t tries = 10; - while (tries-- > 0 || read_status == false) { - read_status = select_iclass_tag(card_data, use_credit_key, &eof_time); - } - - // failed to select card 10 times. return fail to client - if (read_status == false) + if (select_iclass_tag(card_data, use_credit_key, &eof_time) == false) goto out; + + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; // since select_iclass_tag call sends s readcheck, we start with sending first response. uint16_t checked = 0; @@ -1222,7 +1197,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { // Allow button press / usb cmd to interrupt device if (checked == 1000) { - if (BUTTON_PRESS() || !data_available()) goto out; + if (BUTTON_PRESS() || data_available()) goto out; checked = 0; } ++checked; @@ -1251,25 +1226,26 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { out: // send keyindex. - reply_mix(CMD_ACK, isOK, i, 0, 0, 0); + reply_mix(CMD_HF_ICLASS_CHKKEYS, isOK, i, 0, 0, 0); if (isOK >= 1 || lastChunk) { - switch_off(); LED_A_OFF(); } + switch_off(); + LED_B_OFF(); LED_C_OFF(); } // Tries to read block. // retries 10times. -static bool iClass_ReadBlock(uint8_t blockno, uint8_t *data) { +static bool iclass_readblock(uint8_t blockno, uint8_t *data) { uint8_t resp[10]; uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; AddCrc(c + 1, 1); uint32_t eof_time = 0; - bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 10, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); + bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 10, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); memcpy(data, resp, 8); return isOK; } @@ -1283,24 +1259,25 @@ void iClass_ReadBlk(uint8_t blockno) { } PACKED result; LED_A_ON(); - result.isOK = iClass_ReadBlock(blockno, result.blockdata); + result.isOK = iclass_readblock(blockno, result.blockdata); switch_off(); reply_ng(CMD_HF_ICLASS_READBL, PM3_SUCCESS, (uint8_t *)&result, sizeof(result)); } - + // Dump command seems to dump a block related portion of card memory. // I suppose it will need to do an authentatication to AA1, read its blocks by calling this. // then authenticate AA2, and read those blocks by calling this. // By the looks at it only 2K cards is supported, or first page dumps on larger cards. -// turn off afterwards +// turn off afterwards void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { - BigBuf_free(); + BigBuf_free(); - uint8_t *dataout = BigBuf_malloc(0xFF * 8); + uint8_t *dataout = BigBuf_malloc(0xFF * 8); if (dataout == NULL) { DbpString("fail to allocate memory"); - OnError(1); + reply_ng(CMD_HF_ICLASS_DUMP, PM3_EMALLOC, NULL, 0); + switch_off(); return; } memset(dataout, 0xFF, 0xFF * 8); @@ -1308,24 +1285,29 @@ void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { bool isOK; uint8_t blkcnt = 0; for (; blkcnt < numblks; blkcnt++) { - isOK = iClass_ReadBlock(start_blockno + blkcnt, dataout + (8 * blkcnt)); - - if (!isOK) { - isOK = iClass_ReadBlock(start_blockno + blkcnt, dataout + (8 * blkcnt)); - if (!isOK) { - Dbprintf("failed to read block %02X", start_blockno + blkcnt); - break; - } + isOK = iclass_readblock(start_blockno + blkcnt, dataout + (8 * blkcnt)); + if (isOK == false) { + Dbprintf("failed to read block %02X", start_blockno + blkcnt); + break; } } switch_off(); - // return pointer to dump memory in arg3 - // iceman: why not return | dataout - getbigbuf ? Should give exact location. - Dbprintf("ICE:: dataout, %u max trace %u, bb start %u, data-bb %u ", dataout, BigBuf_max_traceLen(), BigBuf_get_addr(), dataout - BigBuf_get_addr() ); - Dbprintf("ICE:: bb size %u, malloced %u (255*8)", BigBuf_get_size(), BigBuf_get_size() - (dataout - BigBuf_get_addr()) ); - reply_mix(CMD_ACK, isOK, blkcnt, BigBuf_max_traceLen(), 0, 0); + // return pointer to dump memory in arg3 + // iceman: why not return | dataout - getbigbuf ? Should give exact location. +// Dbprintf("ICE:: dataout, %u max trace %u, bb start %u, data-bb %u ", dataout, BigBuf_max_traceLen(), BigBuf_get_addr(), dataout - BigBuf_get_addr() ); +// Dbprintf("ICE:: bb size %u, malloced %u (255*8)", BigBuf_get_size(), BigBuf_get_size() - (dataout - BigBuf_get_addr()) ); +// reply_mix(CMD_ACK, isOK, blkcnt, BigBuf_max_traceLen(), 0, 0); + struct p { + bool isOK; + uint8_t block_cnt; + uint32_t bb_offset; + } PACKED payload; + payload.isOK = isOK; + payload.block_cnt = blkcnt; + payload.bb_offset = BigBuf_max_traceLen(); + reply_ng(CMD_HF_ICLASS_DUMP, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); BigBuf_free(); } @@ -1337,35 +1319,35 @@ static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { uint8_t resp[10] = {0}; uint32_t eof_time = 0; - bool isOK = iclass_send_cmd_with_retries(write, sizeof(write), resp, sizeof(resp), 10, 3, 0, ICLASS_READER_TIMEOUT_UPDATE, &eof_time); - if (isOK == false) { - return false; - } + bool isOK = iclass_send_cmd_with_retries(write, sizeof(write), resp, sizeof(resp), 10, 3, 0, ICLASS_READER_TIMEOUT_UPDATE, &eof_time); + if (isOK == false) { + return false; + } - uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - if (blockno == 2) { + uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + if (blockno == 2) { // check response. e-purse update swaps first and second half - if (memcmp(data + 4, resp, 4) || memcmp(data, resp + 4, 4)) { - return false; - } - } else if (blockno == 3 || blockno == 4) { + if (memcmp(data + 4, resp, 4) || memcmp(data, resp + 4, 4)) { + return false; + } + } else if (blockno == 3 || blockno == 4) { // check response. Key updates always return 0xffffffffffffffff - if (memcmp(all_ff, resp, 8)) { - return false; - } - } else { + if (memcmp(all_ff, resp, 8)) { + return false; + } + } else { // check response. All other updates return unchanged data - if (memcmp(data, resp, 8)) { - return false; - } - } + if (memcmp(data, resp, 8)) { + return false; + } + } return true; } // turn off afterwards void iClass_WriteBlock(uint8_t blockno, uint8_t *data) { - LED_A_ON(); + LED_A_ON(); uint8_t isOK = iClass_WriteBlock_ext(blockno, data); switch_off(); reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); From e055858fb8c865e36c7da691e9b8cff87235c540 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:25:44 +0200 Subject: [PATCH 048/139] clean up --- client/src/cmdtrace.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 81840dfc1..7f854d303 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -200,6 +200,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr data_len = hdr->data_len; if (tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr) > traceLen) { + PrintAndLogEx(DEBUG, "trace pos offset %d larger than reported tracelen %d", tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr), traceLen); return traceLen; } @@ -390,19 +391,23 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr } } - if (DecodeMifareData(frame, data_len, parityBytes, hdr->isResponse, mfData, &mfDataLen)) { - memset(explanation, 0x00, sizeof(explanation)); - if (!hdr->isResponse) { - annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen); + if (protocol == PROTO_MIFARE) { + if (DecodeMifareData(frame, data_len, parityBytes, hdr->isResponse, mfData, &mfDataLen)) { + memset(explanation, 0x00, sizeof(explanation)); + if (!hdr->isResponse) { + annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen); + } + uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen); + PrintAndLogEx(NORMAL, " | | * |%-72s | %-4s| %s", + sprint_hex_inrow_spaces(mfData, mfDataLen, 2), + (crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")), + explanation); } - uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen); - PrintAndLogEx(NORMAL, " | | * |%-72s | %-4s| %s", - sprint_hex_inrow_spaces(mfData, mfDataLen, 2), - (crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")), - explanation); } - if (is_last_record(tracepos, traceLen)) return traceLen; + if (is_last_record(tracepos, traceLen)) { + return traceLen; + } if (showWaitCycles && !hdr->isResponse && next_record_is_response(tracepos, trace)) { @@ -420,7 +425,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr static int download_trace(void) { - if (!IfPm3Present()) { + if (IfPm3Present() == false) { PrintAndLogEx(FAILED, "You requested a trace upload in offline mode, consider using parameter '1' for working from Tracebuffer"); return PM3_EINVARG; } @@ -437,7 +442,7 @@ static int download_trace(void) { return PM3_EMALLOC; } - PrintAndLogEx(INFO, "downloading tracelog from device"); + PrintAndLogEx(INFO, "downloading tracelog data from device"); // Query for the size of the trace, downloading PM3_CMD_DATA_SIZE PacketResponseNG response; @@ -533,11 +538,6 @@ int CmdTraceList(const char *Cmd) { bool errors = false; uint8_t protocol = 0; char type[10] = {0}; - - //int tlen = param_getstr(Cmd,0,type); - //char param1 = param_getchar(Cmd, 1); - //char param2 = param_getchar(Cmd, 2); - char cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -651,7 +651,10 @@ int CmdTraceList(const char *Cmd) { PrintAndLogEx(NORMAL, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation"); PrintAndLogEx(NORMAL, "------------+------------+-----+-------------------------------------------------------------------------+-----+--------------------"); - ClearAuthData(); + // clean authentication data used with the mifare classic decrypt fct + if (protocol == ISO_14443A || protocol == PROTO_MIFARE) + ClearAuthData(); + while (tracepos < g_traceLen) { tracepos = printTraceLine(tracepos, g_traceLen, g_trace, protocol, showWaitCycles, markCRCBytes); From e7127514db514ef5fd29d565057f71fa2ece7b2b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:26:26 +0200 Subject: [PATCH 049/139] change debug --- armsrc/BigBuf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 24fe45e57..8756e8171 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -28,7 +28,7 @@ Pointer to highest available memory: s_bigbuf_hi low 0x00 */ -static uint32_t s_bigbuf_size = 0; +static uint32_t s_bigbuf_size = 0; // High memory mark static uint32_t s_bigbuf_hi = 0; @@ -164,7 +164,6 @@ uint32_t BigBuf_get_traceLen(void) { **/ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) { if (tracing == false) { - Dbprintf("trace is turned off"); return false; } @@ -187,7 +186,7 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ } if (duration > 0x7FFF) { - if (DBGLEVEL >= DBG_ERROR) { //DBG_DEBUG + if (DBGLEVEL >= DBG_ERROR) { Dbprintf("Error in LogTrace: duration too long for 15 bits encoding: 0x%08x start: 0x%08x end: 0x%08x", duration, timestamp_start, timestamp_end); } duration /= 32; From a87ec6bd521335cb9df1b275ad22ba8fe08c1d45 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:28:01 +0200 Subject: [PATCH 050/139] style --- armsrc/iso15693.c | 50 ++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 39a64a8c4..7c018554c 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -95,18 +95,12 @@ #define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet #define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet - // 32 + 2 crc + 1 #define ISO15_MAX_FRAME 35 #define CMD_ID_RESP 5 #define CMD_READ_RESP 13 #define CMD_INV_RESP 12 -#define FrameSOF Iso15693FrameSOF -#define Logic0 Iso15693Logic0 -#define Logic1 Iso15693Logic1 -#define FrameEOF Iso15693FrameEOF - //#define Crc(data, len) Crc(CRC_15693, (data), (len)) #define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) @@ -132,7 +126,7 @@ void CodeIso15693AsReader(uint8_t *cmd, int n) { // data for (int i = 0; i < n; i++) { for (int j = 0; j < 8; j += 2) { - int these = (cmd[i] >> j) & 0x03; + uint8_t these = (cmd[i] >> j) & 0x03; switch(these) { case 0: ToSend[++ToSendMax] = 0x40; //01000000 @@ -152,7 +146,6 @@ void CodeIso15693AsReader(uint8_t *cmd, int n) { // EOF ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - ToSendMax++; } @@ -189,11 +182,15 @@ static void CodeIso15693AsReader256(uint8_t *cmd, int n) { // EOF ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - ToSendMax++; } -static const uint8_t encode_4bits[16] = { 0xaa, 0x6a, 0x9a, 0x5a, 0xa6, 0x66, 0x96, 0x56, 0xa9, 0x69, 0x99, 0x59, 0xa5, 0x65, 0x95, 0x55 }; +static const uint8_t encode_4bits[16] = { + 0xaa, 0x6a, 0x9a, 0x5a, + 0xa6, 0x66, 0x96, 0x56, + 0xa9, 0x69, 0x99, 0x59, + 0xa5, 0x65, 0x95, 0x55 +}; void CodeIso15693AsTag(uint8_t *cmd, size_t len) { /* @@ -260,8 +257,8 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { LED_B_ON(); for (int c = 0; c < len; c++) { - uint8_t data = cmd[c]; - for (int i = 0; i < 8; i++) { + volatile uint8_t data = cmd[c]; + for (uint8_t i = 0; i < 8; i++) { uint16_t send_word = (data & 0x80) ? 0xffff : 0x0000; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; AT91C_BASE_SSC->SSC_THR = send_word; @@ -307,7 +304,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, for (size_t c = 0; c < len; c++) { for (int i = (c==0?4:7); i >= 0; i--) { uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; - for (int j = 0; j < (slow?4:1); ) { + for (int j = 0; j < (slow ? 4 : 1); ) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; AT91C_BASE_SSC->SSC_THR = bits_to_send; @@ -652,9 +649,9 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo dma_start_time = GetCountSspClk() & 0xfffffff0; } - uint16_t tagdata = *upTo++; + volatile uint16_t tagdata = *upTo++; - if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. upTo = dmaBuf; // start reading the circular buffer from the beginning if (behindBy > (9 * ISO15693_DMA_BUFFER_SIZE / 10)) { Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); @@ -705,12 +702,11 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); } - if (LogTrace(DecodeTag.output, DecodeTag.len, (sof_time * 4), (*eof_time * 4), NULL, false) == false) - DbpString("GetIso15693AnswerFromTag: failed logtrace"); - if (ret < 0) { return ret; } + + LogTrace(DecodeTag.output, DecodeTag.len, (sof_time * 4), (*eof_time * 4), NULL, false); return DecodeTag.len; } @@ -1017,7 +1013,6 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) { int samples = 0; bool gotFrame = false; - uint8_t b; uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; @@ -1043,15 +1038,15 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo uint8_t *upTo = dmaBuf; for (;;) { - uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE - 1); if (behindBy == 0) continue; - b = *upTo++; + volatile uint8_t b = *upTo++; if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. upTo = dmaBuf; // start reading the circular buffer from the beginning if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + Dbprintf("About to blow circular buffer - aborted! behindBy %d", behindBy); break; } } @@ -1088,11 +1083,10 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo if (DecodeReader.byteCount > 0) { uint32_t sof_time = *eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers + - DecodeReader.byteCount * (DecodeReader.Coding == CODING_1_OUT_OF_4 ? 128 : 2048) // time for byte transfers - 32 // time for SOF transfer - 16; // time for EOF transfer - if (LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time*32, *eof_time*32, NULL, true) == false) - DbpString("GetIso15693CommandFromReader: failed logtrace"); + LogTrace(DecodeReader.output, DecodeReader.byteCount, (sof_time * 32), (*eof_time * 32), NULL, true); } return DecodeReader.byteCount; @@ -1317,7 +1311,7 @@ void Iso15693InitReader(void) { // Start from off (no field generated) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - SpinDelay(10); + SpinDelay(50); // switch field on FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); @@ -1328,7 +1322,7 @@ void Iso15693InitReader(void) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // give tags some time to energize - SpinDelay(250); + SpinDelay(200); set_tracing(true); @@ -1572,6 +1566,8 @@ void Iso15693InitTag(void) { FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + set_tracing(true); + // turn on clock StartCountSspClk(); } From 7aedd9c7fe120b60442e5b7d447f3488b3156d37 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:28:30 +0200 Subject: [PATCH 051/139] textual --- include/pm3_cmd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index ac5d7ce00..b85d996d6 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -122,6 +122,7 @@ typedef struct { bool verbose; } PACKED sample_config; +// Tracelog Header struct typedef struct { uint32_t timestamp; uint16_t duration; From 52e9d7a75048adad307acb5137f41f6b713c58f6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 12:29:31 +0200 Subject: [PATCH 052/139] rework iclass dump --- client/src/cmdhficlass.c | 174 ++++++++++++++++++++------------------- client/src/cmdhficlass.h | 13 +++ 2 files changed, 102 insertions(+), 85 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 62ba0f70a..5b0b11492 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1112,7 +1112,7 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { return PM3_SUCCESS; } -static void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t MAC[4]) { +static void calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t *MAC) { uint8_t wb[9]; wb[0] = blockno; memcpy(wb + 1, data, 8); @@ -1120,24 +1120,25 @@ static void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_ } static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) { - PacketResponseNG resp; - uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); + uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); if (use_credit_key) flags |= FLAG_ICLASS_READER_CEDITKEY; clearCommandBuffer(); + PacketResponseNG resp; SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0); if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { PrintAndLogEx(WARNING, "command execute timeout"); return false; } - uint8_t isOK = resp.oldarg[0] & 0xff; + uint8_t isok = resp.oldarg[0] & 0xff; - if (isOK == 0xFF) { + // no tag found or button pressed + if ((isok == 0) || isok == 0xFF) { if (verbose) { - PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", isOK); + PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", isok); } return false; } @@ -1159,17 +1160,12 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) { - struct { - uint8_t key[8]; - bool use_raw; - bool use_elite; - bool use_credit_key; - } PACKED payload; - + iclass_auth_req_t payload = { + .use_raw = rawkey, + .use_elite = elite, + .use_credit_key = use_credit_key + }; memcpy(payload.key, KEY, 8); - payload.use_raw = rawkey; - payload.use_elite = elite; - payload.use_credit_key = use_credit_key; SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t*)&payload, sizeof(payload)); PacketResponseNG resp; @@ -1184,13 +1180,8 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u return false; } - struct p { - bool isOK; - uint8_t div_key[8]; - uint8_t mac[4]; - } PACKED; - struct p *packet = (struct p *)resp.data.asBytes; - + iclass_auth_resp_t *packet = (iclass_auth_resp_t *)resp.data.asBytes; + if (packet->isOK == 0) { if (verbose) PrintAndLogEx(FAILED, "authentication error"); return false; @@ -1206,7 +1197,7 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u return true; } -static int CmdHFiClassReader_Dump(const char *Cmd) { +static int CmdHFiClassDump(const char *Cmd) { uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -1245,6 +1236,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { keyNbr = param_get8(Cmd, cmdp + 1); if (keyNbr < ICLASS_KEYS_MAX) { memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8); + PrintAndLogEx(INFO, "AA2 (credit) index %u", keyNbr); } else { PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); errors = true; @@ -1277,6 +1269,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { keyNbr = param_get8(Cmd, cmdp + 1); if (keyNbr < ICLASS_KEYS_MAX) { memcpy(KEY, iClass_Key_Table[keyNbr], 8); + PrintAndLogEx(INFO, "AA1 (debit) index %u", keyNbr); } else { PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); errors = true; @@ -1307,12 +1300,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { // if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work) if (!have_debit_key && have_credit_key) use_credit_key = true; - uint32_t flags = ( - FLAG_ICLASS_READER_INIT | - FLAG_ICLASS_READER_CLEARTRACE | - FLAG_ICLASS_READER_ONLY_ONCE - ); - + uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); //get config and first 3 blocks PacketResponseNG resp; @@ -1320,7 +1308,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ICLASS_READER, flags, 0, 0, NULL, 0); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(WARNING, "command execute timeout"); DropField(); return PM3_ESOFT; @@ -1346,21 +1334,22 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { } // authenticate debit key and get div_key - later store in dump block 3 - int numberAuthRetries = ICLASS_AUTH_RETRY; - do { - if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) - break; - } while (numberAuthRetries--); - - if (numberAuthRetries <= 0) { + if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) { PrintAndLogEx(WARNING, "failed authenticating with debit key"); DropField(); return PM3_ESOFT; } - // begin dump + struct { + uint8_t start_blockno; + uint8_t numblks; + } PACKED payload; + payload.start_blockno = blockno; + payload.numblks = numblks - blockno + 1; + clearCommandBuffer(); - SendCommandMIX(CMD_HF_ICLASS_DUMP, blockno, numblks - blockno + 1, 0, NULL, 0); + SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); + while (true) { printf("."); fflush(stdout); @@ -1371,47 +1360,53 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { return PM3_EOPABORTED; } - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) + if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) break; } + + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to communicate with card"); + return resp.status; + } + // dump cmd switch off at device when finised. - uint32_t blocksRead = resp.oldarg[1]; - uint8_t isOK = resp.oldarg[0] & 0xff; - if (!isOK && !blocksRead) { + struct p_resp { + bool isOK; + uint8_t block_cnt; + uint32_t bb_offset; + } PACKED; + struct p_resp *packet = (struct p_resp *)resp.data.asBytes; + + uint32_t blocks_read = packet->block_cnt; + + if (packet->isOK == false) { PrintAndLogEx(WARNING, "read block failed"); return PM3_ESOFT; } - uint32_t startindex = resp.oldarg[2]; - if (blocksRead * 8 > sizeof(tag_data) - (blockno * 8)) { + uint32_t startindex = packet->bb_offset; + + if (blocks_read * 8 > sizeof(tag_data) - (blockno * 8)) { PrintAndLogEx(FAILED, "data exceeded buffer size!"); - blocksRead = (sizeof(tag_data) / 8) - blockno; + blocks_read = (sizeof(tag_data) / 8) - blockno; } // response ok - now get bigbuf content of the dump - if (!GetFromDevice(BIG_BUF, tag_data + (blockno * 8), blocksRead * 8, startindex, NULL, 0, NULL, 2500, false)) { + if (!GetFromDevice(BIG_BUF, tag_data + (blockno * 8), blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } - size_t gotBytes = blocksRead * 8 + blockno * 8; + size_t gotBytes = blocks_read * 8 + blockno * 8; - // try AA2 + // try AA2 Kc, Credit if (have_credit_key) { - //turn off hf field before authenticating with different key - DropField(); memset(MAC, 0, 4); // AA2 authenticate credit key and git c_div_key - later store in dump block 4 - numberAuthRetries = ICLASS_AUTH_RETRY; - do { - if (select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose)) - break; - } while (numberAuthRetries--); - - if (numberAuthRetries <= 0) { + if (select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose) == false) { PrintAndLogEx(WARNING, "failed authenticating with credit key"); DropField(); return PM3_ESOFT; @@ -1419,32 +1414,43 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { // do we still need to read more block? (aa2 enabled?) if (maxBlk > blockno + numblks + 1) { - // setup dump and start + + payload.start_blockno = blockno + blocks_read; + payload.numblks = maxBlk - (blockno + blocks_read); + clearCommandBuffer(); - SendCommandMIX(CMD_HF_ICLASS_DUMP, blockno + blocksRead, maxBlk - (blockno + blocksRead), 0, NULL, 0); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); + + if (!WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) { PrintAndLogEx(WARNING, "command execute timeout 2"); return PM3_ETIMEOUT; } - isOK = resp.oldarg[0] & 0xff; - blocksRead = resp.oldarg[1]; - if (!isOK && !blocksRead) { - PrintAndLogEx(WARNING, "read block failed 2"); + + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to communicate with card"); + return resp.status; + } + + packet = (struct p_resp *)resp.data.asBytes; + if (packet->isOK == false) { + PrintAndLogEx(WARNING, "read block failed using credit key"); return PM3_ESOFT; } - startindex = resp.oldarg[2]; - if (blocksRead * 8 > sizeof(tag_data) - gotBytes) { + blocks_read = packet->block_cnt; + startindex = packet->bb_offset; + + if (blocks_read * 8 > sizeof(tag_data) - gotBytes) { PrintAndLogEx(FAILED, "data exceeded buffer size!"); - blocksRead = (sizeof(tag_data) - gotBytes) / 8; + blocks_read = (sizeof(tag_data) - gotBytes) / 8; } // get dumped data from bigbuf - if (!GetFromDevice(BIG_BUF, tag_data + gotBytes, blocksRead * 8, startindex, NULL, 0, NULL, 2500, false)) { + if (!GetFromDevice(BIG_BUF, tag_data + gotBytes, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } - gotBytes += blocksRead * 8; + gotBytes += blocks_read * 8; } } @@ -1485,13 +1491,13 @@ static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_c uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) { + if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) { numberAuthRetries--; DropField(); continue; } - Calc_wb_mac(blockno, bldata, div_key, MAC); + calc_wb_mac(blockno, bldata, div_key, MAC); struct p { uint8_t blockno; @@ -1506,7 +1512,7 @@ static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_c SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 4000) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) { if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); DropField(); return PM3_ETIMEOUT; @@ -1767,7 +1773,7 @@ static int CmdHFiClassCloneTag(const char *Cmd) { // calculate all mac for every the block we will write for (i = startblock; i <= endblock; i++) { - Calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC); + calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC); // usb command d start pointer = d + (i - 6) * 12 // memcpy(pointer,tag_data[i - 6],8) 8 bytes // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes; @@ -1806,7 +1812,7 @@ static int CmdHFiClassCloneTag(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_CLONE, (uint8_t *)&payload, total_bytes + 2); - if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 4500) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 2000) == 0) { PrintAndLogEx(WARNING, "command execute timeout"); DropField(); return PM3_ETIMEOUT; @@ -1829,7 +1835,6 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool isOK; uint8_t blockdata[8]; } PACKED; - struct p *result = NULL; do { @@ -1837,7 +1842,7 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, if (auth || blockno >= 2) { uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (!select_and_auth(KEY, MAC, div_key, (keyType == 0x18), elite, rawkey, verbose)) { + if (select_and_auth(KEY, MAC, div_key, (keyType == 0x18), elite, rawkey, verbose) == false) { numberAuthRetries--; DropField(); continue; @@ -1845,7 +1850,7 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, } else { uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (!select_only(CSN, CCNR, (keyType == 0x18), verbose)) { + if (select_only(CSN, CCNR, (keyType == 0x18), verbose) == false) { numberAuthRetries--; DropField(); continue; @@ -2156,6 +2161,7 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) { bool elite = false; bool errors = false; uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': @@ -2217,9 +2223,9 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) { } if (errors || cmdp < 4) return usage_hf_iclass_calc_newkey(); - if (!givenCSN) { + if (givenCSN == false) { uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (!select_only(CSN, CCNR, false, true)) { + if (select_only(CSN, CCNR, false, true) == false) { DropField(); return PM3_ESOFT; } @@ -2512,7 +2518,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys); PacketResponseNG resp; - while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + while (!WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000)) { timeout++; printf("."); fflush(stdout); @@ -2927,7 +2933,7 @@ static command_t CommandTable[] = { {"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"}, {"clone", CmdHFiClassCloneTag, IfPm3Iclass, "[options..] Restore a dump file onto a iClass tag"}, {"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" }, - {"dump", CmdHFiClassReader_Dump, IfPm3Iclass, "[options..] Dump iClass tag to file"}, + {"dump", CmdHFiClassDump, IfPm3Iclass, "[options..] Dump iClass tag to file"}, {"eload", CmdHFiClassELoad, IfPm3Iclass, "[f ] Load iClass dump file into emulator memory"}, {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"}, {"info", CmdHFiClassInfo, AlwaysAvailable, " Tag information"}, @@ -2979,8 +2985,6 @@ int readIclass(bool loop, bool verbose) { uint8_t readStatus = resp.oldarg[0] & 0xff; -// PrintAndLogEx(NORMAL, "ICE: %x", readStatus); - // no tag found or button pressed if ((readStatus == 0 && !loop) || readStatus == 0xFF) { DropField(); diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index 53880d647..19b994d0c 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -27,6 +27,19 @@ typedef struct iclass_prekey { uint8_t key[8]; } iclass_prekey_t; +typedef struct { + uint8_t key[8]; + bool use_raw; + bool use_elite; + bool use_credit_key; +} PACKED iclass_auth_req_t; + +typedef struct { + bool isOK; + uint8_t div_key[8]; + uint8_t mac[4]; +} PACKED iclass_auth_resp_t; + int CmdHFiClass(const char *Cmd); int readIclass(bool loop, bool verbose); From aaa6f25ab6e012f4ebf9997fc0b7cbc6f9dc53ba Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 13:55:19 +0200 Subject: [PATCH 053/139] chg: 'trace list' - now support relative times, us/fc (@piwi) --- client/src/cmdtrace.c | 174 +++++++++++++++++++++++++++++++++--------- 1 file changed, 136 insertions(+), 38 deletions(-) diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 7f854d303..f2b20ab68 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -31,6 +31,8 @@ static int usage_trace_list(void) { PrintAndLogEx(NORMAL, "Usage: trace list [f][c| <0|1>"); PrintAndLogEx(NORMAL, " f - show frame delay times as well"); PrintAndLogEx(NORMAL, " c - mark CRC bytes"); + PrintAndLogEx(NORMAL, " r - show relative times (gap and duration)"); + PrintAndLogEx(NORMAL, " u - display times in microseconds instead of clock cycles"); PrintAndLogEx(NORMAL, " x - show hexdump to convert to pcap(ng) or to import into Wireshark using encapsulation type \"ISO 14443\""); PrintAndLogEx(NORMAL, " syntax to use: `text2pcap -t \"%%S.\" -l 264 -n `"); PrintAndLogEx(NORMAL, " <0|1> - use data from Tracebuffer, if not set, try to collect a trace from Proxmark3 device."); @@ -179,16 +181,16 @@ static uint16_t printHexLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trac return ret; } -static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes) { +static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes, uint32_t *prev_eot, bool use_us) { // sanity check if (is_last_record(tracepos, traceLen)) { PrintAndLogEx(DEBUG, "last record triggered. t-pos: %u t-len %u", tracepos, traceLen); return traceLen; } + uint32_t end_of_transmission_timestamp = 0; uint32_t duration; uint16_t data_len; - uint32_t EndOfTransmissionTimestamp; uint8_t topaz_reader_command[9]; char explanation[40] = {0}; uint8_t mfData[32] = {0}; @@ -203,6 +205,12 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr PrintAndLogEx(DEBUG, "trace pos offset %d larger than reported tracelen %d", tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr), traceLen); return traceLen; } + + // adjust for different time scales + if (protocol == ICLASS || protocol == ISO_15693) { + duration *= 32; + } + uint8_t *frame = hdr->frame; uint8_t *parityBytes = hdr->frame + data_len; @@ -266,7 +274,13 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr char line[18][120] = {{0}}; if (data_len == 0) { - sprintf(line[0], ""); + if (protocol == ICLASS && duration == 2048) { + sprintf(line[0], " "); + } else if (protocol == ISO_15693 && duration == 512) { + sprintf(line[0], " "); + } else { + sprintf(line[0], ""); + } return tracepos; } @@ -318,7 +332,20 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr // Draw the CRC column const char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); - EndOfTransmissionTimestamp = hdr->timestamp + duration; + + uint32_t previous_end_of_transmission_timestamp = 0; + if (prev_eot) { + if (*prev_eot) { + previous_end_of_transmission_timestamp = *prev_eot; + } else { + previous_end_of_transmission_timestamp = hdr->timestamp; + } + } + + end_of_transmission_timestamp = hdr->timestamp + duration; + + if (prev_eot) + *prev_eot = end_of_transmission_timestamp; // Always annotate LEGIC read/tag if (protocol == LEGIC) @@ -376,18 +403,40 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr int num_lines = MIN((data_len - 1) / 18 + 1, 18); for (int j = 0; j < num_lines ; j++) { if (j == 0) { - PrintAndLogEx(NORMAL, " %10u | %10u | %s |%-72s | %s| %s", - (hdr->timestamp - first_hdr->timestamp), - (EndOfTransmissionTimestamp - first_hdr->timestamp), - (hdr->isResponse ? "Tag" : "Rdr"), - line[j], - (j == num_lines - 1) ? crc : " ", - (j == num_lines - 1) ? explanation : ""); + + uint32_t time1 = hdr->timestamp - first_hdr->timestamp; + uint32_t time2 = end_of_transmission_timestamp - first_hdr->timestamp; + if (prev_eot) { + time1 = hdr->timestamp - previous_end_of_transmission_timestamp; + time2 = duration; + } + + if (use_us) { + PrintAndLogEx(NORMAL, " %10.1f | %10.1f | %s |%-72s | %s| %s", + (float)time1/13.56, + (float)time2/13.56, + (hdr->isResponse ? "Tag" : "Rdr"), + line[j], + (j == num_lines - 1) ? crc : " ", + (j == num_lines - 1) ? explanation : "" + ); + } else { + PrintAndLogEx(NORMAL, " %10u | %10u | %s |%-72s | %s| %s", + (hdr->timestamp - first_hdr->timestamp), + (end_of_transmission_timestamp - first_hdr->timestamp), + (hdr->isResponse ? "Tag" : "Rdr"), + line[j], + (j == num_lines - 1) ? crc : " ", + (j == num_lines - 1) ? explanation : "" + ); + } + } else { PrintAndLogEx(NORMAL, " | | |%-72s | %s| %s", - line[j], - (j == num_lines - 1) ? crc : " ", - (j == num_lines - 1) ? explanation : ""); + line[j], + (j == num_lines - 1) ? crc : " ", + (j == num_lines - 1) ? explanation : "" + ); } } @@ -414,10 +463,10 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos); PrintAndLogEx(NORMAL, " %10u | %10u | %s |fdt (Frame Delay Time): %d", - (EndOfTransmissionTimestamp - first_hdr->timestamp), + (end_of_transmission_timestamp - first_hdr->timestamp), (next_hdr->timestamp - first_hdr->timestamp), " ", - (next_hdr->timestamp - EndOfTransmissionTimestamp)); + (next_hdr->timestamp - end_of_transmission_timestamp)); } return tracepos; @@ -531,10 +580,9 @@ int CmdTraceList(const char *Cmd) { clearCommandBuffer(); - bool showWaitCycles = false; - bool markCRCBytes = false; - bool showHex = false; - bool isOnline = true; + bool showWaitCycles = false, markCRCBytes = false; + bool showHex = false, isOnline = true; + bool use_us = false, use_relative = false; bool errors = false; uint8_t protocol = 0; char type[10] = {0}; @@ -567,6 +615,14 @@ int CmdTraceList(const char *Cmd) { isOnline = false; cmdp++; break; + case 'r': + use_relative = true; + cmdp++; + break; + case 'u': + use_us = true; + cmdp++; + break; default: PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -626,37 +682,79 @@ int CmdTraceList(const char *Cmd) { tracepos = printHexLine(tracepos, g_traceLen, g_trace, protocol); } } else { - PrintAndLogEx(INFO, _YELLOW_("Start") " = Start of Start Bit, " _YELLOW_("End") " = End of last modulation. " _YELLOW_("Src") " = Source of Transfer"); - if (protocol == ISO_14443A || protocol == PROTO_MIFARE || protocol == MFDES || protocol == TOPAZ || protocol == LTO) - PrintAndLogEx(INFO, "ISO14443A - All times are in carrier periods (1/13.56MHz)"); - if (protocol == THINFILM) - PrintAndLogEx(INFO, "Thinfilm - All times are in carrier periods (1/13.56MHz)"); - if (protocol == ICLASS) - PrintAndLogEx(INFO, "iClass - Timings are not as accurate"); + + if (use_relative) { + PrintAndLogEx(INFO, _YELLOW_("gap") " = time between transfers. " _YELLOW_("duration") " = duration of data transfer. " _YELLOW_("src") " = source of transfer"); + } else { + PrintAndLogEx(INFO, _YELLOW_("start") " = start of start frame " _YELLOW_("end") " = end of frame. " _YELLOW_("src") " = source of transfer"); + } + + if (protocol == ISO_14443A || protocol == PROTO_MIFARE || protocol == MFDES || protocol == TOPAZ || protocol == LTO) { + if (use_us) + PrintAndLogEx(INFO, _YELLOW_("ISO14443A") " - all times are in microseconds"); + else + PrintAndLogEx(INFO, _YELLOW_("ISO14443A") " - all times are in carrier periods (1/13.56MHz)"); + } + + if (protocol == THINFILM) { + if (use_us) + PrintAndLogEx(INFO, _YELLOW_("Thinfilm") " - all times are in microseconds"); + else + PrintAndLogEx(INFO, _YELLOW_("Thinfilm") " - all times are in carrier periods (1/13.56MHz)"); + } + + if (protocol == ICLASS || protocol == ISO_15693) { + if (use_us) + PrintAndLogEx(INFO, _YELLOW_("ISO15693 / iCLASS") " - all times are in microseconds"); + else + PrintAndLogEx(INFO, _YELLOW_("ISO15693 / iCLASS") " - all times are in carrier periods (1/13.56MHz)"); + } + if (protocol == LEGIC) - PrintAndLogEx(INFO, "LEGIC - Reader Mode: Timings are in ticks (1us == 1.5ticks)\n" + PrintAndLogEx(INFO, _YELLOW_("LEGIC") " - Reader Mode: Timings are in ticks (1us == 1.5ticks)\n" " Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)"); - if (protocol == ISO_14443B) - PrintAndLogEx(INFO, "ISO14443B"); // Timings ? - if (protocol == ISO_15693) - PrintAndLogEx(INFO, "ISO15693 - Timings are not as accurate"); + + if (protocol == ISO_14443B) { + if (use_us) + PrintAndLogEx(INFO, _YELLOW_("ISO14443B") " - all times are in microseconds"); + else + PrintAndLogEx(INFO, _YELLOW_("ISO14443B") " - all times are in carrier periods (1/13.56MHz)"); + } + if (protocol == ISO_7816_4) - PrintAndLogEx(INFO, "ISO7816-4 / Smartcard - Timings N/A yet"); + PrintAndLogEx(INFO, _YELLOW_("ISO7816-4 / Smartcard") " - Timings N/A"); + if (protocol == PROTO_HITAG1 || protocol == PROTO_HITAG2 || protocol == PROTO_HITAGS) - PrintAndLogEx(INFO, "Hitag1 / Hitag2 / HitagS - Timings in ETU (8us)"); - if (protocol == FELICA) - PrintAndLogEx(INFO, "ISO18092 / FeliCa - Timings are not as accurate"); + PrintAndLogEx(INFO, _YELLOW_("Hitag1 / Hitag2 / HitagS") " - Timings in ETU (8us)"); + + if (protocol == FELICA) { + if (use_us) + PrintAndLogEx(INFO, _YELLOW_("ISO18092 / FeliCa") " - all times are in microseconds"); + else + PrintAndLogEx(INFO, _YELLOW_("ISO18092 / FeliCa") " - all times are in carrier periods (1/13.56MHz)"); + } + PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation"); + if (use_relative) { + PrintAndLogEx(NORMAL, " Gap | Duration | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation"); + } else { + PrintAndLogEx(NORMAL, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation"); + } PrintAndLogEx(NORMAL, "------------+------------+-----+-------------------------------------------------------------------------+-----+--------------------"); // clean authentication data used with the mifare classic decrypt fct if (protocol == ISO_14443A || protocol == PROTO_MIFARE) ClearAuthData(); + + uint32_t previous_EOT = 0; + uint32_t *prev_EOT = NULL; + if (use_relative) { + prev_EOT = &previous_EOT; + } while (tracepos < g_traceLen) { - tracepos = printTraceLine(tracepos, g_traceLen, g_trace, protocol, showWaitCycles, markCRCBytes); + tracepos = printTraceLine(tracepos, g_traceLen, g_trace, protocol, showWaitCycles, markCRCBytes, prev_EOT, use_us); if (kbd_enter_pressed()) break; From a6c240fe3be87e4494683b6528e498263c60c23f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 17:56:19 +0200 Subject: [PATCH 054/139] tosend into bigbuff --- armsrc/BigBuf.c | 44 +++++++++++++++++++++ armsrc/BigBuf.h | 14 +++++++ armsrc/appmain.c | 83 +++++++++++++-------------------------- armsrc/hfsnoop.c | 9 +++-- armsrc/iclass.c | 98 +++++++++++++++++++++++------------------------ armsrc/iso15693.c | 88 +++++++++++++++++++++++------------------- armsrc/thinfilm.c | 16 +++++--- 7 files changed, 195 insertions(+), 157 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 8756e8171..9b3733d6f 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -227,3 +227,47 @@ uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length) { Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset + length), CARD_MEMORY_SIZE); return 1; } + + +//============================================================================= +// The ToSend buffer. +// A buffer where we can queue things up to be sent through the FPGA, for +// any purpose (fake tag, as reader, whatever). We go MSB first, since that +// is the order in which they go out on the wire. +//============================================================================= +static tosend_t toSend = { + .max = -1, + .bit = 8, + .buf = NULL +}; + +// get the address of the ToSend buffer. Allocate part of Bigbuf for it, if not yet done +tosend_t *get_tosend(void) { + + if (toSend.buf == NULL) + toSend.buf = BigBuf_malloc(TOSEND_BUFFER_SIZE); + + return &toSend; +} + +void tosend_reset(void) { + toSend.max = -1; + toSend.bit = 8; +} + +void tosend_stuffbit(int b) { + if (toSend.bit >= 8) { + toSend.max++; + toSend.buf[toSend.max] = 0; + toSend.bit = 0; + } + + if (b) + toSend.buf[ toSend.max] |= (1 << (7 - toSend.bit)); + + toSend.bit++; + + if (toSend.max >= TOSEND_BUFFER_SIZE) { + toSend.bit = 0; + } +} diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index b89b94242..33c454226 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -21,6 +21,9 @@ #define CARD_MEMORY_SIZE 4096 #define DMA_BUFFER_SIZE 128 +// 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits +#define TOSEND_BUFFER_SIZE (9 * MAX_FRAME_SIZE + 1 + 1 + 2) + uint8_t *BigBuf_get_addr(void); uint32_t BigBuf_get_size(void); uint8_t *BigBuf_get_EM_addr(void); @@ -42,4 +45,15 @@ bool get_tracing(void); bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length); + +typedef struct { + int max; + int bit; + uint8_t *buf; +} tosend_t; + +tosend_t *get_tosend(void); +void tosend_reset(void); +void tosend_stuffbit(int b); + #endif /* __BIGBUF_H */ diff --git a/armsrc/appmain.c b/armsrc/appmain.c index e35dc8ae2..094982a3c 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -62,17 +62,6 @@ #include "spiffs.h" #endif -//============================================================================= -// A buffer where we can queue things up to be sent through the FPGA, for -// any purpose (fake tag, as reader, whatever). We go MSB first, since that -// is the order in which they go out on the wire. -//============================================================================= - -#define TOSEND_BUFFER_SIZE (9*MAX_FRAME_SIZE + 1 + 1 + 2) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits -uint8_t ToSend[TOSEND_BUFFER_SIZE] = {0}; -int ToSendMax = -1; -static int ToSendBit; - extern uint32_t _stack_start, _stack_end; struct common_area common_area __attribute__((section(".commonarea"))); static int button_status = BUTTON_NO_CLICK; @@ -84,29 +73,6 @@ inline void send_wtx(uint16_t wtx) { } } -void ToSendReset(void) { - ToSendMax = -1; - ToSendBit = 8; -} - -void ToSendStuffBit(int b) { - if (ToSendBit >= 8) { - ToSendMax++; - ToSend[ToSendMax] = 0; - ToSendBit = 0; - } - - if (b) - ToSend[ToSendMax] |= (1 << (7 - ToSendBit)); - - ToSendBit++; - - if (ToSendMax >= sizeof(ToSend)) { - ToSendBit = 0; - DbpString("ToSendStuffBit overflowed!"); - } -} - //----------------------------------------------------------------------------- // Read an ADC channel and block till it completes, then return the result // in ADC units (0 to 1023). Also a routine to sum up a number of samples and @@ -326,6 +292,28 @@ static void TimingIntervalAcquisition(void) { StartTickCount(); } +static void print_debug_level(void) { + char dbglvlstr[20] = {0}; + switch(DBGLEVEL) { + case DBG_NONE: + sprintf(dbglvlstr, "NONE"); + break; + case DBG_ERROR: + sprintf(dbglvlstr, "ERROR"); + break; + case DBG_INFO: + sprintf(dbglvlstr, "INFO"); + break; + case DBG_DEBUG: + sprintf(dbglvlstr, "DEBUG"); + break; + case DBG_EXTENDED: + sprintf(dbglvlstr, "EXTENDED"); + break; + } + Dbprintf(" DBGLEVEL................%d ( " _YELLOW_("%s")" )", DBGLEVEL, dbglvlstr); +} + // measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. // Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the PacketCommandNG structure included. static void printConnSpeed(void) { @@ -372,29 +360,10 @@ static void SendStatus(void) { DbpString(_CYAN_("Various")); print_stack_usage(); - - char dbglvlstr[20] = {0}; - switch(DBGLEVEL) { - case DBG_NONE: - sprintf(dbglvlstr, "NONE"); - break; - case DBG_ERROR: - sprintf(dbglvlstr, "ERROR"); - break; - case DBG_INFO: - sprintf(dbglvlstr, "INFO"); - break; - case DBG_DEBUG: - sprintf(dbglvlstr, "DEBUG"); - break; - case DBG_EXTENDED: - sprintf(dbglvlstr, "EXTENDED"); - break; - } - Dbprintf(" DBGLEVEL................%d ( " _YELLOW_("%s")" )", DBGLEVEL, dbglvlstr); + print_debug_level(); - Dbprintf(" ToSendMax...............%d", ToSendMax); - Dbprintf(" ToSendBit...............%d", ToSendBit); + tosend_t *ts = get_tosend(); + Dbprintf(" ToSendMax...............%d", ts->max ); Dbprintf(" ToSend BUFFERSIZE.......%d", TOSEND_BUFFER_SIZE); while ((AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINRDY) == 0); // Wait for MAINF value to become available... uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINF; // Get # main clocks within 16 slow clocks @@ -752,7 +721,7 @@ static void PacketReceived(PacketCommandNG *packet) { // emulator case CMD_SET_DBGMODE: { DBGLEVEL = packet->data.asBytes[0]; - Dbprintf("Debug level: %d", DBGLEVEL); + print_debug_level(); reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0); break; } diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index 1b87d857a..ab2517187 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -114,8 +114,9 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) { } void HfPlotDownload(void) { - uint8_t *buf = ToSend; - uint8_t *this_buf = buf; + + tosend_t *ts = get_tosend(); + uint8_t *this_buf = ts->buf; FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -124,7 +125,7 @@ void HfPlotDownload(void) { AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) this_buf; // start transfer to this memory address AT91C_BASE_PDC_SSC->PDC_RCR = PM3_CMD_DATA_SIZE; // transfer this many samples - buf[0] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // clear receive register + ts->buf[0] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // clear receive register AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // Start DMA transfer FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_GET_TRACE); // let FPGA transfer its internal Block-RAM @@ -132,7 +133,7 @@ void HfPlotDownload(void) { LED_B_ON(); for (size_t i = 0; i < FPGA_TRACE_SIZE; i += PM3_CMD_DATA_SIZE) { // prepare next DMA transfer: - uint8_t *next_buf = buf + ((i + PM3_CMD_DATA_SIZE) % (2 * PM3_CMD_DATA_SIZE)); + uint8_t *next_buf = ts->buf + ((i + PM3_CMD_DATA_SIZE) % (2 * PM3_CMD_DATA_SIZE)); AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)next_buf; AT91C_BASE_PDC_SSC->PDC_RNCR = PM3_CMD_DATA_SIZE; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 58cf36a0d..d180aa6e0 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -90,9 +90,10 @@ static void rotateCSN(uint8_t *original_csn, uint8_t *rotated_csn) { // Encode SOF only static void CodeIClassTagSOF(void) { - ToSendReset(); - ToSend[++ToSendMax] = 0x1D; - ToSendMax++; + tosend_reset(); + tosend_t *ts = get_tosend(); + ts->buf[++ts->max] = 0x1D; + ts->max++; } @@ -393,42 +394,43 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); // Prepare card messages - ToSendMax = 0; + tosend_t *ts = get_tosend(); + ts->max = 0; // First card answer: SOF CodeIClassTagSOF(); - memcpy(resp_sof, ToSend, ToSendMax); - resp_sof_len = ToSendMax; + memcpy(resp_sof, ts->buf, ts->max); + resp_sof_len = ts->max; // Anticollision CSN CodeIso15693AsTag(anticoll_data, sizeof(anticoll_data)); - memcpy(resp_anticoll, ToSend, ToSendMax); - resp_anticoll_len = ToSendMax; + memcpy(resp_anticoll, ts->buf, ts->max); + resp_anticoll_len = ts->max; // CSN (block 0) CodeIso15693AsTag(csn_data, sizeof(csn_data)); - memcpy(resp_csn, ToSend, ToSendMax); - resp_csn_len = ToSendMax; + memcpy(resp_csn, ts->buf, ts->max); + resp_csn_len = ts->max; // Configuration (block 1) CodeIso15693AsTag(conf_block, sizeof(conf_block)); - memcpy(resp_conf, ToSend, ToSendMax); - resp_conf_len = ToSendMax; + memcpy(resp_conf, ts->buf, ts->max); + resp_conf_len = ts->max; // e-Purse (block 2) CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); - memcpy(resp_cc, ToSend, ToSendMax); - resp_cc_len = ToSendMax; + memcpy(resp_cc, ts->buf, ts->max); + resp_cc_len = ts->max; // Kd, Kc (blocks 3 and 4) CodeIso15693AsTag(ff_data, sizeof(ff_data)); - memcpy(resp_ff, ToSend, ToSendMax); - resp_ff_len = ToSendMax; + memcpy(resp_ff, ts->buf, ts->max); + resp_ff_len = ts->max; // Application Issuer Area (block 5) CodeIso15693AsTag(aia_data, sizeof(aia_data)); - memcpy(resp_aia, ToSend, ToSendMax); - resp_aia_len = ToSendMax; + memcpy(resp_aia, ts->buf, ts->max); + resp_aia_len = ts->max; //This is used for responding to READ-block commands or other data which is dynamically generated //First the 'trace'-data, not encoded for FPGA @@ -542,8 +544,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = data_generic_trace; trace_data_size = 10; CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(modulated_response, ToSend, ToSendMax); - modulated_response_size = ToSendMax; + memcpy(modulated_response, ts->buf, ts->max); + modulated_response_size = ts->max; goto send; } break; @@ -586,9 +588,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = data_generic_trace; trace_data_size = 4; CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); + memcpy(data_response, ts->buf, ts->max); modulated_response = data_response; - modulated_response_size = ToSendMax; + modulated_response_size = ts->max; } else { // Not fullsim, we don't respond // We do not know what to answer, so lets keep quiet @@ -636,8 +638,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = data_generic_trace; trace_data_size = 34; CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(modulated_response, ToSend, ToSendMax); - modulated_response_size = ToSendMax; + memcpy(modulated_response, ts->buf, ts->max); + modulated_response_size = ts->max; goto send; } @@ -650,8 +652,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { if (block == 2) { // update e-purse memcpy(card_challenge_data, receivedCmd + 2, 8); CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); - memcpy(resp_cc, ToSend, ToSendMax); - resp_cc_len = ToSendMax; + memcpy(resp_cc, ts->buf, ts->max); + resp_cc_len = ts->max; cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); @@ -684,9 +686,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = data_generic_trace; trace_data_size = 10; CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); + memcpy(data_response, ts->buf, ts->max); modulated_response = data_response; - modulated_response_size = ToSendMax; + modulated_response_size = ts->max; } goto send; @@ -714,9 +716,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data_size = 10; CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); + memcpy(data_response, ts->buf, ts->max); modulated_response = data_response; - modulated_response_size = ToSendMax; + modulated_response_size = ts->max; } } @@ -752,8 +754,9 @@ send: // THE READER CODE static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time) { CodeIso15693AsReader(frame, len); - TransmitTo15693Tag(ToSend, ToSendMax, start_time); - uint32_t end_time = *start_time + (32 * ((8 * ToSendMax) - 4)); // substract the 4 padding bits after EOF + tosend_t *ts = get_tosend(); + TransmitTo15693Tag(ts->buf, ts->max, start_time); + uint32_t end_time = *start_time + (32 * ((8 * ts->max) - 4)); // substract the 4 padding bits after EOF LogTrace(frame, len, (*start_time * 4), (end_time * 4), NULL, true); } @@ -770,7 +773,7 @@ static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time)) { return true; } - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; +// start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; } return false; } @@ -796,24 +799,19 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t if (use_credit_key) read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; - - set_tracing(true); - int len; - uint32_t start_time; - uint8_t tries = 10; - do { - // wakeup - start_time = GetCountSspClk(); - iclass_send_as_reader(act_all, 1, &start_time); - len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time); - if (len >= 0) { - break; - } else if (len == -2) { - return false; - } - } while (tries-- > 0); + // wakeup + uint32_t start_time = GetCountSspClk(); + iclass_send_as_reader(act_all, 1, &start_time); + int len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time); + if (len < 0) + return false; +/* + bool ok = iclass_send_cmd_with_retries(act_all, 1, resp, sizeof(resp), 1, 5, start_time, ICLASS_READER_TIMEOUT_ACTALL, eof_time); + if (ok == false) + return false; +*/ // send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; iclass_send_as_reader(identify, 1, &start_time); @@ -881,8 +879,6 @@ void ReaderIClass(uint8_t flags) { Iso15693InitReader(); } - set_tracing(true); - if ((flags & FLAG_ICLASS_READER_CLEARTRACE) == FLAG_ICLASS_READER_CLEARTRACE) { clear_trace(); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 7c018554c..82640d0cb 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -118,10 +118,11 @@ static void BuildInventoryResponse(uint8_t *uid); // n ... length of data void CodeIso15693AsReader(uint8_t *cmd, int n) { - ToSendReset(); + tosend_reset(); + tosend_t *ts = get_tosend(); // SOF for 1of4 - ToSend[++ToSendMax] = 0x84; //10000100 + ts->buf[++ts->max] = 0x84; //10000100 // data for (int i = 0; i < n; i++) { @@ -129,31 +130,32 @@ void CodeIso15693AsReader(uint8_t *cmd, int n) { uint8_t these = (cmd[i] >> j) & 0x03; switch(these) { case 0: - ToSend[++ToSendMax] = 0x40; //01000000 + ts->buf[++ts->max] = 0x40; //01000000 break; case 1: - ToSend[++ToSendMax] = 0x10; //00010000 + ts->buf[++ts->max] = 0x10; //00010000 break; case 2: - ToSend[++ToSendMax] = 0x04; //00000100 + ts->buf[++ts->max] = 0x04; //00000100 break; case 3: - ToSend[++ToSendMax] = 0x01; //00000001 + ts->buf[++ts->max] = 0x01; //00000001 break; } } } // EOF - ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - ToSendMax++; + ts->buf[++ts->max] = 0x20; //0010 + 0000 padding + ts->max++; } // Encode EOF only static void CodeIso15693AsReaderEOF(void) { - ToSendReset(); - ToSend[++ToSendMax] = 0x20; - ToSendMax++; + tosend_reset(); + tosend_t *ts = get_tosend(); + ts->buf[++ts->max] = 0x20; + ts->max++; } @@ -162,27 +164,28 @@ static void CodeIso15693AsReaderEOF(void) { // is designed for more robust communication over longer distances static void CodeIso15693AsReader256(uint8_t *cmd, int n) { - ToSendReset(); - + tosend_reset(); + tosend_t *ts = get_tosend(); + // SOF for 1of256 - ToSend[++ToSendMax] = 0x81; //10000001 + ts->buf[++ts->max] = 0x81; //10000001 // data for(int i = 0; i < n; i++) { for (int j = 0; j <= 255; j++) { if (cmd[i] == j) { - ToSendStuffBit(0); - ToSendStuffBit(1); + tosend_stuffbit(0); + tosend_stuffbit(1); } else { - ToSendStuffBit(0); - ToSendStuffBit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); } } } // EOF - ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - ToSendMax++; + ts->buf[++ts->max] = 0x20; //0010 + 0000 padding + ts->max++; } static const uint8_t encode_4bits[16] = { @@ -219,22 +222,22 @@ void CodeIso15693AsTag(uint8_t *cmd, size_t len) { * A logic 0 is 10 * * */ - - ToSendReset(); + tosend_reset(); + tosend_t *ts = get_tosend(); // SOF - ToSend[++ToSendMax] = 0x1D; // 00011101 + ts->buf[++ts->max] = 0x1D; // 00011101 // data for (int i = 0; i < len; i++) { - ToSend[++ToSendMax] = encode_4bits[cmd[i] & 0xF]; - ToSend[++ToSendMax] = encode_4bits[cmd[i] >> 4]; + ts->buf[++ts->max] = encode_4bits[cmd[i] & 0xF]; + ts->buf[++ts->max] = encode_4bits[cmd[i] >> 4]; } // EOF - ToSend[++ToSendMax] = 0xB8; // 10111000 + ts->buf[++ts->max] = 0xB8; // 10111000 - ToSendMax++; + ts->max++; } // Transmit the command (to the tag) that was placed in cmd[]. @@ -617,9 +620,7 @@ static void DecodeTagReset(DecodeTag_t *DecodeTag) { */ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { - int samples = 0; - int ret = 0; - + int samples = 0, ret = 0; uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; // the Decoder data structure @@ -641,7 +642,8 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo for(;;) { uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - if (behindBy == 0) continue; + if (behindBy == 0) + continue; samples++; if (samples == 1) { @@ -702,7 +704,7 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); } - if (ret < 0) { + if (ret == -1) { return ret; } @@ -1115,8 +1117,10 @@ void AcquireRawAdcSamplesIso15693(void) { SpinDelay(100); // Now send the command + tosend_t *ts = get_tosend(); + uint32_t start_time = 0; - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); + TransmitTo15693Tag(ts->buf, ts->max, &start_time); // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ; @@ -1321,11 +1325,11 @@ void Iso15693InitReader(void) { FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + set_tracing(true); + // give tags some time to energize SpinDelay(200); - set_tracing(true); - StartCountSspClk(); } @@ -1396,8 +1400,9 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t CodeIso15693AsReader256(send, sendlen); } - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); - uint32_t end_time = start_time + 32 * (8 * ToSendMax -4); // substract the 4 padding bits after EOF + tosend_t *ts = get_tosend(); + TransmitTo15693Tag(ts->buf, ts->max, &start_time); + uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // substract the 4 padding bits after EOF LogTrace(send, sendlen, (start_time * 4), (end_time * 4), NULL, true); int res = 0; @@ -1410,8 +1415,9 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time) { CodeIso15693AsReaderEOF(); - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); - uint32_t end_time = start_time + 32 * (8 * ToSendMax - 4); // substract the 4 padding bits after EOF + tosend_t *ts = get_tosend(); + TransmitTo15693Tag(ts->buf, ts->max, &start_time); + uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // substract the 4 padding bits after EOF LogTrace(NULL, 0, (start_time * 4), (end_time * 4), NULL, true); int res = 0; @@ -1591,6 +1597,8 @@ void SimTagIso15693(uint8_t *uid) { // not so obvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. BuildInventoryResponse(uid); + tosend_t *ts = get_tosend(); + while (!BUTTON_PRESS()) { WDT_HIT(); @@ -1602,7 +1610,7 @@ void SimTagIso15693(uint8_t *uid) { if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { // TODO: check more flags bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); + TransmitTo15693Reader(ts->buf, ts->max, &start_time, 0, slow); } if (DBGLEVEL >= DBG_EXTENDED) { diff --git a/armsrc/thinfilm.c b/armsrc/thinfilm.c index 16c91c8bf..dcc2ff36f 100644 --- a/armsrc/thinfilm.c +++ b/armsrc/thinfilm.c @@ -30,7 +30,6 @@ void ReadThinFilm(void) { clear_trace(); - set_tracing(true); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -60,15 +59,19 @@ static uint16_t ReadReaderField(void) { } static void CodeThinfilmAsTag(const uint8_t *cmd, uint16_t len) { - ToSendReset(); + + tosend_reset(); + + tosend_t *ts = get_tosend(); + for (uint16_t i = 0; i < len; i++) { uint8_t b = cmd[i]; for (uint8_t j = 0; j < 8; j++) { - ToSend[++ToSendMax] = (b & 0x80) ? SEC_D : SEC_E; + ts->buf[++ts->max] = (b & 0x80) ? SEC_D : SEC_E; b <<= 1; } } - ToSendMax++; + ts->max++; } static int EmSendCmdThinfilmRaw(uint8_t *resp, uint16_t respLen) { @@ -132,6 +135,8 @@ void SimulateThinFilm(uint8_t *data, size_t len) { uint16_t hf_baseline = ReadReaderField(); + tosend_t *ts = get_tosend(); + // Start the timer StartCountSspClk(); @@ -147,7 +152,8 @@ void SimulateThinFilm(uint8_t *data, size_t len) { if (hf_av < hf_baseline) hf_baseline = hf_av; if (hf_av > hf_baseline + 10) { - EmSendCmdThinfilmRaw(ToSend, ToSendMax); + + EmSendCmdThinfilmRaw(ts->buf, ts->max); if (!reader_detected) { LED_B_ON(); //Dbprintf("Reader detected, start beaming data"); From d6f65f8578c22717437ed3ec5039998d9d90cbee Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 18:14:34 +0200 Subject: [PATCH 055/139] tosend into bigbuff --- armsrc/iso14443a.c | 156 ++++++++++++++++++++++++--------------------- armsrc/iso14443b.c | 79 +++++++++++++---------- 2 files changed, 129 insertions(+), 106 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 0dae3c872..bac3008f9 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -729,62 +729,61 @@ void RAMFUNC SniffIso14443a(uint8_t param) { //----------------------------------------------------------------------------- static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par, bool collision) { - //uint8_t localCol = 0; - ToSendReset(); + tosend_reset(); + + tosend_t *ts = get_tosend(); // Correction bit, might be removed when not needed - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(1); // <----- - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); + tosend_stuffbit(1); // <----- + tosend_stuffbit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); // Send startbit - ToSend[++ToSendMax] = SEC_D; - LastProxToAirDuration = 8 * ToSendMax - 4; + ts->buf[++ts->max] = SEC_D; + LastProxToAirDuration = 8 * ts->max - 4; for (uint16_t i = 0; i < len; i++) { uint8_t b = cmd[i]; // Data bits for (uint16_t j = 0; j < 8; j++) { - //if (collision && (localCol >= colpos)){ if (collision) { - ToSend[++ToSendMax] = SEC_COLL; - //localCol++; + ts->buf[++ts->max] = SEC_COLL; } else { if (b & 1) { - ToSend[++ToSendMax] = SEC_D; + ts->buf[++ts->max] = SEC_D; } else { - ToSend[++ToSendMax] = SEC_E; + ts->buf[++ts->max] = SEC_E; } b >>= 1; } } if (collision) { - ToSend[++ToSendMax] = SEC_COLL; - LastProxToAirDuration = 8 * ToSendMax; + ts->buf[++ts->max] = SEC_COLL; + LastProxToAirDuration = 8 * ts->max; } else { // Get the parity bit if (par[i >> 3] & (0x80 >> (i & 0x0007))) { - ToSend[++ToSendMax] = SEC_D; - LastProxToAirDuration = 8 * ToSendMax - 4; + ts->buf[++ts->max] = SEC_D; + LastProxToAirDuration = 8 * ts->max - 4; } else { - ToSend[++ToSendMax] = SEC_E; - LastProxToAirDuration = 8 * ToSendMax; + ts->buf[++ts->max] = SEC_E; + LastProxToAirDuration = 8 * ts->max; } } } // Send stopbit - ToSend[++ToSendMax] = SEC_F; + ts->buf[++ts->max] = SEC_F; // Convert from last byte pos to length - ToSendMax++; + ts->max++; } static void CodeIso14443aAsTagEx(const uint8_t *cmd, uint16_t len, bool collision) { @@ -799,37 +798,39 @@ static void CodeIso14443aAsTag(const uint8_t *cmd, uint16_t len) { static void Code4bitAnswerAsTag(uint8_t cmd) { uint8_t b = cmd; - ToSendReset(); + tosend_reset(); + + tosend_t *ts = get_tosend(); // Correction bit, might be removed when not needed - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(1); // 1 - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); + tosend_stuffbit(1); // 1 + tosend_stuffbit(0); + tosend_stuffbit(0); + tosend_stuffbit(0); // Send startbit - ToSend[++ToSendMax] = SEC_D; + ts->buf[++ts->max] = SEC_D; for (uint8_t i = 0; i < 4; i++) { if (b & 1) { - ToSend[++ToSendMax] = SEC_D; - LastProxToAirDuration = 8 * ToSendMax - 4; + ts->buf[++ts->max] = SEC_D; + LastProxToAirDuration = 8 * ts->max - 4; } else { - ToSend[++ToSendMax] = SEC_E; - LastProxToAirDuration = 8 * ToSendMax; + ts->buf[++ts->max] = SEC_E; + LastProxToAirDuration = 8 * ts->max; } b >>= 1; } // Send stopbit - ToSend[++ToSendMax] = SEC_F; + ts->buf[++ts->max] = SEC_F; // Convert from last byte pos to length - ToSendMax++; + ts->max++; } //----------------------------------------------------------------------------- @@ -887,32 +888,36 @@ bool prepare_tag_modulation(tag_response_info_t *response_info, size_t max_buffe // Prepare the tag modulation bits from the message CodeIso14443aAsTag(response_info->response, response_info->response_n); + tosend_t *ts = get_tosend(); + // Make sure we do not exceed the free buffer space - if (ToSendMax > max_buffer_size) { + if (ts->max > max_buffer_size) { Dbprintf("ToSend buffer, Out-of-bound, when modulating bits for tag answer:"); Dbhexdump(response_info->response_n, response_info->response, false); return false; } // Copy the byte array, used for this modulation to the buffer position - memcpy(response_info->modulation, ToSend, ToSendMax); + memcpy(response_info->modulation, ts->buf, ts->max); // Store the number of bytes that were used for encoding/modulation and the time needed to transfer them - response_info->modulation_n = ToSendMax; + response_info->modulation_n = ts->max; response_info->ProxToAirDuration = LastProxToAirDuration; return true; } bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *max_buffer_size) { + tosend_t *ts = get_tosend(); + // Retrieve and store the current buffer index response_info->modulation = *buffer; // Forward the prepare tag modulation function to the inner function if (prepare_tag_modulation(response_info, *max_buffer_size)) { // Update the free buffer offset and the remaining buffer size - *buffer += ToSendMax; - *max_buffer_size -= ToSendMax; + *buffer += ts->max; + *max_buffer_size -= ts->max; return true; } else { return false; @@ -1638,12 +1643,14 @@ static void PrepareDelayedTransfer(uint16_t delay) { for (uint16_t i = 0; i < delay; i++) bitmask |= (0x01 << i); - ToSend[ToSendMax++] = 0x00; + tosend_t *ts = get_tosend(); - for (uint16_t i = 0; i < ToSendMax; i++) { - uint8_t bits_to_shift = ToSend[i] & bitmask; - ToSend[i] = ToSend[i] >> delay; - ToSend[i] = ToSend[i] | (bits_shifted << (8 - delay)); + ts->buf[ts->max++] = 0x00; + + for (uint16_t i = 0; i < ts->max; i++) { + uint8_t bits_to_shift = ts->buf[i] & bitmask; + ts->buf[i] = ts->buf[i] >> delay; + ts->buf[i] = ts->buf[i] | (bits_shifted << (8 - delay)); bits_shifted = bits_to_shift; } } @@ -1701,11 +1708,12 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8_t *par) { int last = 0; - ToSendReset(); + tosend_reset(); + tosend_t *ts = get_tosend(); // Start of Communication (Seq. Z) - ToSend[++ToSendMax] = SEC_Z; - LastProxToAirDuration = 8 * (ToSendMax + 1) - 6; + ts->buf[++ts->max] = SEC_Z; + LastProxToAirDuration = 8 * (ts->max + 1) - 6; size_t bytecount = nbytes(bits); // Generate send structure for the data bits @@ -1717,17 +1725,17 @@ static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, cons for (j = 0; j < bitsleft; j++) { if (b & 1) { // Sequence X - ToSend[++ToSendMax] = SEC_X; - LastProxToAirDuration = 8 * (ToSendMax + 1) - 2; + ts->buf[++ts->max] = SEC_X; + LastProxToAirDuration = 8 * (ts->max + 1) - 2; last = 1; } else { if (last == 0) { // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - LastProxToAirDuration = 8 * (ToSendMax + 1) - 6; + ts->buf[++ts->max] = SEC_Z; + LastProxToAirDuration = 8 * (ts->max + 1) - 6; } else { // Sequence Y - ToSend[++ToSendMax] = SEC_Y; + ts->buf[++ts->max] = SEC_Y; last = 0; } } @@ -1739,17 +1747,17 @@ static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, cons // Get the parity bit if (par[i >> 3] & (0x80 >> (i & 0x0007))) { // Sequence X - ToSend[++ToSendMax] = SEC_X; - LastProxToAirDuration = 8 * (ToSendMax + 1) - 2; + ts->buf[++ts->max] = SEC_X; + LastProxToAirDuration = 8 * (ts->max + 1) - 2; last = 1; } else { if (last == 0) { // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - LastProxToAirDuration = 8 * (ToSendMax + 1) - 6; + ts->buf[++ts->max] = SEC_Z; + LastProxToAirDuration = 8 * (ts->max + 1) - 6; } else { // Sequence Y - ToSend[++ToSendMax] = SEC_Y; + ts->buf[++ts->max] = SEC_Y; last = 0; } } @@ -1759,16 +1767,16 @@ static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, cons // End of Communication: Logic 0 followed by Sequence Y if (last == 0) { // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - LastProxToAirDuration = 8 * (ToSendMax + 1) - 6; + ts->buf[++ts->max] = SEC_Z; + LastProxToAirDuration = 8 * (ts->max + 1) - 6; } else { // Sequence Y - ToSend[++ToSendMax] = SEC_Y; + ts->buf[++ts->max] = SEC_Y; } - ToSend[++ToSendMax] = SEC_Y; + ts->buf[++ts->max] = SEC_Y; // Convert to length of command: - ToSendMax++; + ts->max++; } //----------------------------------------------------------------------------- @@ -1970,7 +1978,8 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { int EmSend4bit(uint8_t resp) { Code4bitAnswerAsTag(resp); - int res = EmSendCmd14443aRaw(ToSend, ToSendMax); + tosend_t *ts = get_tosend(); + int res = EmSendCmd14443aRaw(ts->buf, ts->max); // do the tracing for the previous reader request and this tag answer: uint8_t par[1] = {0x00}; GetParity(&resp, 1, par); @@ -1991,7 +2000,9 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par) { } int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision) { CodeIso14443aAsTagPar(resp, respLen, par, collision); - int res = EmSendCmd14443aRaw(ToSend, ToSendMax); + tosend_t *ts = get_tosend(); + int res = EmSendCmd14443aRaw(ts->buf, ts->max); + // do the tracing for the previous reader request and this tag answer: EmLogTrace(Uart.output, Uart.len, @@ -2152,7 +2163,8 @@ void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t CodeIso14443aBitsAsReaderPar(frame, bits, par); // Send command to tag - TransmitFor14443a(ToSend, ToSendMax, timing); + tosend_t *ts = get_tosend(); + TransmitFor14443a(ts->buf, ts->max, timing); if (g_trigger) LED_A_ON(); LogTrace(frame, nbytes(bits), (LastTimeProxToAirStart << 4) + DELAY_ARM2AIR_AS_READER, ((LastTimeProxToAirStart + LastProxToAirDuration) << 4) + DELAY_ARM2AIR_AS_READER, par, true); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 4448d3570..b06dbcb44 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -50,7 +50,7 @@ #endif // 4sample -#define SEND4STUFFBIT(x) ToSendStuffBit(x);ToSendStuffBit(x);ToSendStuffBit(x);ToSendStuffBit(x); +#define SEND4STUFFBIT(x) tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x); static void iso14b_set_timeout(uint32_t timeout); static void iso14b_set_maxframesize(uint16_t size); @@ -140,7 +140,7 @@ static uint32_t iso14b_timeout = TR0; static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { int i; - ToSendReset(); + tosend_reset(); // Transmit a burst of ones, as the initial thing that lets the // reader get phase sync. @@ -199,8 +199,9 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { SEND4STUFFBIT(1); } + tosend_t *ts = get_tosend(); // Convert from last byte pos to length - ToSendMax++; + ts->max++; } //----------------------------------------------------------------------------- @@ -543,24 +544,32 @@ void SimulateIso14443bTag(uint32_t pupi) { uint16_t len, cmdsReceived = 0; int cardSTATE = SIM_NOFIELD; int vHf = 0; // in mV + + tosend_t *ts = get_tosend(); + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); // prepare "ATQB" tag answer (encoded): CodeIso14443bAsTag(respATQB, sizeof(respATQB)); - uint8_t *encodedATQB = BigBuf_malloc(ToSendMax); - uint16_t encodedATQBLen = ToSendMax; - memcpy(encodedATQB, ToSend, ToSendMax); + uint8_t *encodedATQB = BigBuf_malloc(ts->max); + uint16_t encodedATQBLen = ts->max; + memcpy(encodedATQB, ts->buf, ts->max); // prepare "OK" tag answer (encoded): CodeIso14443bAsTag(respOK, sizeof(respOK)); - uint8_t *encodedOK = BigBuf_malloc(ToSendMax); - uint16_t encodedOKLen = ToSendMax; - memcpy(encodedOK, ToSend, ToSendMax); + uint8_t *encodedOK = BigBuf_malloc(ts->max); + uint16_t encodedOKLen = ts->max; + memcpy(encodedOK, ts->buf, ts->max); // Simulation loop - while (!BUTTON_PRESS() && !data_available()) { + while (BUTTON_PRESS() == false) { WDT_HIT(); + + //iceman: limit with 2000 times.. + if (data_available()) { + break; + } // find reader field if (cardSTATE == SIM_NOFIELD) { @@ -669,7 +678,7 @@ void SimulateIso14443bTag(uint32_t pupi) { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen()); - switch_off(); //simulate + switch_off(); //simulate } //============================================================================= @@ -967,9 +976,10 @@ static void TransmitFor14443b_AsReader(void) { FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); LED_B_ON(); - - for (int c = 0; c < ToSendMax; c++) { - uint8_t data = ToSend[c]; + tosend_t *ts = get_tosend(); + + for (int c = 0; c < ts->max; c++) { + uint8_t data = ts->buf[c]; for (int i = 0; i < 8; i++) { uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; @@ -1006,48 +1016,48 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { * 1 "stuffbit" = 1ETU (9us) */ - ToSendReset(); + tosend_reset(); // Send SOF // 10-11 ETUs of ZERO for (int i = 0; i < 10; i++) - ToSendStuffBit(0); + tosend_stuffbit(0); // 2-3 ETUs of ONE - ToSendStuffBit(1); - ToSendStuffBit(1); + tosend_stuffbit(1); + tosend_stuffbit(1); // Sending cmd, LSB // from here we add BITS for (int i = 0; i < len; i++) { // Start bit - ToSendStuffBit(0); + tosend_stuffbit(0); // Data bits uint8_t b = cmd[i]; - ToSendStuffBit(b & 1); - ToSendStuffBit((b >> 1) & 1); - ToSendStuffBit((b >> 2) & 1); - ToSendStuffBit((b >> 3) & 1); - ToSendStuffBit((b >> 4) & 1); - ToSendStuffBit((b >> 5) & 1); - ToSendStuffBit((b >> 6) & 1); - ToSendStuffBit((b >> 7) & 1); + tosend_stuffbit(b & 1); + tosend_stuffbit((b >> 1) & 1); + tosend_stuffbit((b >> 2) & 1); + tosend_stuffbit((b >> 3) & 1); + tosend_stuffbit((b >> 4) & 1); + tosend_stuffbit((b >> 5) & 1); + tosend_stuffbit((b >> 6) & 1); + tosend_stuffbit((b >> 7) & 1); // Stop bit - ToSendStuffBit(1); + tosend_stuffbit(1); // EGT extra guard time // For PCD it ranges 0-57us (1etu = 9us) -// ToSendStuffBit(1); -// ToSendStuffBit(1); -// ToSendStuffBit(1); +// tosend_stuffbit(1); +// tosend_stuffbit(1); +// tosend_stuffbit(1); } // Send EOF // 10-11 ETUs of ZERO for (int i = 0; i < 10; i++) - ToSendStuffBit(0); + tosend_stuffbit(0); // Transition time. TR0 - guard time // 8ETUS minum? @@ -1056,11 +1066,12 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { // ensure that last byte is filled up for (int i = 0; i < 8 ; ++i) - ToSendStuffBit(1); + tosend_stuffbit(1); // TR1 - Synchronization time // Convert from last character reference to length - ToSendMax++; + tosend_t *ts = get_tosend(); + ts->max++; } /* From 88c14b9c08e80e1ab3fc3ccac9a0d5ff9236acc5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 18:20:43 +0200 Subject: [PATCH 056/139] iclass doesnt need 4500 timout anymore, can put earlier in hf search. --- client/src/cmdhf.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 4fc138a98..e1cf99305 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -129,6 +129,15 @@ int CmdHFSearch(const char *Cmd) { } } + PROMPT_CLEARLINE; + PrintAndLogEx(INPLACE, " Searching for iClass / PicoPass tag..."); + if (IfPm3Iclass()) { + if (readIclass(false, false) == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") " found\n"); + res = PM3_SUCCESS; + } + } + PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, " Searching for LEGIC tag..."); if (IfPm3Legicrf()) { @@ -156,7 +165,6 @@ int CmdHFSearch(const char *Cmd) { } } /* - // 14b and iclass is the longest test (put last) PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, " Searching for CryptoRF tag..."); if (IfPm3Iso14443b()) { @@ -167,7 +175,7 @@ int CmdHFSearch(const char *Cmd) { } */ - // 14b and iclass is the longest test (put last) + // 14b is the longest test (put last) PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, " Searching for ISO14443-B tag..."); if (IfPm3Iso14443b()) { @@ -177,14 +185,6 @@ int CmdHFSearch(const char *Cmd) { } } - PROMPT_CLEARLINE; - PrintAndLogEx(INPLACE, " Searching for iClass / PicoPass tag..."); - if (IfPm3Iclass()) { - if (readIclass(false, false) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") " found\n"); - res = PM3_SUCCESS; - } - } PROMPT_CLEARLINE; if (res != PM3_SUCCESS) { From b62c060727dc292e3f673b4970d9b11f4b0fe502 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 20:13:25 +0200 Subject: [PATCH 057/139] chg: hf iclass rdbl, wrbl - got some love --- client/src/cmdhficlass.c | 146 +++++++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 58 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 5b0b11492..8bdde6592 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -35,6 +35,7 @@ #define ICLASS_KEYS_MAX 8 #define ICLASS_AUTH_RETRY 10 #define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" +static uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static int CmdHelp(const char *Cmd); @@ -954,7 +955,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { uint8_t max_blk = 31; getMemConfig(mem, chip, &max_blk, &app_areas, &kb); - uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03); @@ -1484,61 +1485,40 @@ static int CmdHFiClassDump(const char *Cmd) { return PM3_SUCCESS; } -static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool verbose) { +static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool verbose) { - int numberAuthRetries = ICLASS_AUTH_RETRY; - do { - - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) { - numberAuthRetries--; - DropField(); - continue; - } - - calc_wb_mac(blockno, bldata, div_key, MAC); - - struct p { - uint8_t blockno; - uint8_t data[12]; - } PACKED payload; - payload.blockno = blockno; - - memcpy(payload.data, bldata, 8); - memcpy(payload.data + 8, MAC, 4); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - - if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) { - if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); - DropField(); - return PM3_ETIMEOUT; - } - - if (resp.status != PM3_SUCCESS) { - if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); - DropField(); - return PM3_EWRONGANSWER; - } - - if (resp.data.asBytes[0] == 1) - break; - - } while (numberAuthRetries); - - DropField(); - - if (numberAuthRetries > 0) { - PrintAndLogEx(SUCCESS, "Write block %02X successful\n", blockno); - } else { - PrintAndLogEx(ERR, "failed to authenticate and write block"); + uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; + uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) { return PM3_ESOFT; } - return PM3_SUCCESS; + calc_wb_mac(blockno, bldata, div_key, MAC); + + struct p { + uint8_t blockno; + uint8_t data[12]; + } PACKED payload; + payload.blockno = blockno; + + memcpy(payload.data, bldata, 8); + memcpy(payload.data + 8, MAC, 4); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) { + if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; + } + + if (resp.status != PM3_SUCCESS) { + if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); + return PM3_EWRONGANSWER; + } + + return (resp.data.asBytes[0] == 1) ? PM3_SUCCESS : PM3_ESOFT; } static int CmdHFiClass_WriteBlock(const char *Cmd) { @@ -1620,7 +1600,12 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { if (errors || cmdp < 6) return usage_hf_iclass_writeblock(); - return WriteBlock(blockno, bldata, KEY, use_credit_key, elite, rawkey, verbose); + int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, verbose); + if (isok == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno); + else + PrintAndLogEx(FAILED, "Writing failed"); + return isok; } static int CmdHFiClassCloneTag(const char *Cmd) { @@ -1827,7 +1812,7 @@ static int CmdHFiClassCloneTag(const char *Cmd) { return resp.status; } -static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth) { +static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth) { int numberAuthRetries = ICLASS_AUTH_RETRY; // return data. @@ -1886,12 +1871,57 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "block %02X: %s\n", blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); + PrintAndLogEx(SUCCESS, "block %02X: " _GREEN_("%s"), blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); - if (blockno == 6) { - if (IsCryptoHelperPresent()) { + if (memcmp(result->blockdata, empty, 8) == 0) + return PM3_SUCCESS; + + bool use_sc = IsCryptoHelperPresent(); + if (use_sc == false) + return PM3_SUCCESS; + + // crypto helper available. + switch (blockno) { + case 6: { DecodeBlock6(result->blockdata); + break; } + case 7: { +// case 8: +// case 9: { + PrintAndLogEx(INFO, "Trying to decrypt..."); + + uint8_t dec_data[8]; + Decrypt(result->blockdata, dec_data); + + if (memcmp(dec_data, empty, 8) != 0) { + + //todo: remove preamble/sentinal + + uint32_t top = 0, mid, bot; + mid = bytes_to_num(dec_data, 4); + bot = bytes_to_num(dec_data + 4, 4); + + PrintAndLogEx(INFO, "Block 7 binary"); + + char hexstr[8 + 1] = {0}; + hex_to_buffer((uint8_t *)hexstr, dec_data, 8, sizeof(hexstr) - 1, 0, 0, true); + + char binstr[8 * 8 + 1] = {0}; + hextobinstring(binstr, hexstr); + uint8_t i = 0; + while (i < strlen(binstr) && binstr[i++] == '0'); + + PrintAndLogEx(SUCCESS, "%s", binstr + i); + + PrintAndLogEx(INFO, "Wiegand decode"); + wiegand_message_t packed = initialize_message_object(top, mid, bot); + HIDTryUnpack(&packed, true); + PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + } else { + PrintAndLogEx(INFO, "No credential found."); + } + } } return PM3_SUCCESS; @@ -1973,7 +2003,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { if (!auth) PrintAndLogEx(FAILED, "warning: no authentication used with read, only a few specific blocks can be read accurately without authentication."); - return ReadBlock(KEY, blockno, keyType, elite, rawkey, verbose, auth); + return iclass_read_block(KEY, blockno, keyType, elite, rawkey, verbose, auth); } static int CmdHFiClass_loclass(const char *Cmd) { From e476e7f504f1f73b83d34798c83b4b10c9977411 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 20:13:56 +0200 Subject: [PATCH 058/139] coding style --- armsrc/iclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index d180aa6e0..84f854c9c 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1307,7 +1307,7 @@ void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { BigBuf_free(); } -static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { +static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data) { uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; memcpy(write + 2, data, 12); // data + mac @@ -1344,7 +1344,7 @@ static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { // turn off afterwards void iClass_WriteBlock(uint8_t blockno, uint8_t *data) { LED_A_ON(); - uint8_t isOK = iClass_WriteBlock_ext(blockno, data); + uint8_t isOK = iclass_writeblock_ext(blockno, data); switch_off(); reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); } @@ -1356,7 +1356,7 @@ void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { uint16_t total_blocks = (endblock - startblock) + 1; for (uint8_t b = startblock; b < total_blocks; b++) { - if (iClass_WriteBlock_ext(b, data + ((b - startblock) * 12))) { + if (iclass_writeblock_ext(b, data + ((b - startblock) * 12))) { Dbprintf("Write block [%02x] successful", b); written++; } else { From 4493153dbb7a674c3ab504b8c9da47ab067a1948 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 20:58:24 +0200 Subject: [PATCH 059/139] verbose.. --- client/src/cmdhficlass.c | 85 +++++++++++++++++----------------------- common/cardhelper.c | 11 +++--- common/cardhelper.h | 2 +- 3 files changed, 42 insertions(+), 56 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 8bdde6592..b4fc7dcb2 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -918,7 +918,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { if (errors || cmdp < 1) return usage_hf_iclass_decrypt(); - bool use_sc = IsCryptoHelperPresent(); + bool use_sc = IsCryptoHelperPresent(true); if (have_key == false && use_sc == false) { int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); @@ -1092,7 +1092,7 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { if (errors || cmdp < 1) return usage_hf_iclass_encrypt(); - bool use_sc = IsCryptoHelperPresent(); + bool use_sc = IsCryptoHelperPresent(true); if (have_key == false && use_sc == false) { size_t keylen = 0; @@ -1814,7 +1814,6 @@ static int CmdHFiClassCloneTag(const char *Cmd) { static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth) { - int numberAuthRetries = ICLASS_AUTH_RETRY; // return data. struct p { bool isOK; @@ -1822,61 +1821,51 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo } PACKED; struct p *result = NULL; - do { - // block 0,1 should always be able to read, and block 5 on some cards. - if (auth || blockno >= 2) { - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (select_and_auth(KEY, MAC, div_key, (keyType == 0x18), elite, rawkey, verbose) == false) { - numberAuthRetries--; - DropField(); - continue; - } - } else { - uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (select_only(CSN, CCNR, (keyType == 0x18), verbose) == false) { - numberAuthRetries--; - DropField(); - continue; - } + // block 0,1 should always be able to read, and block 5 on some cards. + if (auth || blockno >= 2) { + uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; + uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + if (select_and_auth(KEY, MAC, div_key, (keyType == 0x18), elite, rawkey, verbose) == false) { + return PM3_ESOFT; } - - PacketResponseNG resp; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_READBL, (uint8_t *)&blockno, sizeof(uint8_t)); - - if (WaitForResponseTimeout(CMD_HF_ICLASS_READBL, &resp, 2000) == 0) { - if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); - DropField(); - return PM3_ETIMEOUT; + } else { + uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + if (select_only(CSN, CCNR, (keyType == 0x18), verbose) == false) { + return PM3_ESOFT; } + } - if (resp.status != PM3_SUCCESS) { - if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); - DropField(); - return PM3_EWRONGANSWER; - } + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandNG(CMD_HF_ICLASS_READBL, (uint8_t *)&blockno, sizeof(uint8_t)); - result = (struct p *)resp.data.asBytes; - if (result->isOK) - break; + if (WaitForResponseTimeout(CMD_HF_ICLASS_READBL, &resp, 2000) == 0) { + if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); + DropField(); + return PM3_ETIMEOUT; + } - } while (numberAuthRetries); + if (resp.status != PM3_SUCCESS) { + if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); + return PM3_EWRONGANSWER; + } + + result = (struct p *)resp.data.asBytes; + if (result->isOK == false) + return PM3_ESOFT; DropField(); - if (numberAuthRetries == 0) { - PrintAndLogEx(ERR, "failed to authenticate and read block"); - return PM3_ESOFT; - } - PrintAndLogEx(SUCCESS, "block %02X: " _GREEN_("%s"), blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); if (memcmp(result->blockdata, empty, 8) == 0) return PM3_SUCCESS; - bool use_sc = IsCryptoHelperPresent(); + if (blockno < 6 || blockno > 7) + return PM3_SUCCESS; + + bool use_sc = IsCryptoHelperPresent(verbose); if (use_sc == false) return PM3_SUCCESS; @@ -1887,8 +1876,6 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo break; } case 7: { -// case 8: -// case 9: { PrintAndLogEx(INFO, "Trying to decrypt..."); uint8_t dec_data[8]; @@ -1902,7 +1889,7 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo mid = bytes_to_num(dec_data, 4); bot = bytes_to_num(dec_data + 4, 4); - PrintAndLogEx(INFO, "Block 7 binary"); + PrintAndLogEx(INFO, "Binary"); char hexstr[8 + 1] = {0}; hex_to_buffer((uint8_t *)hexstr, dec_data, 8, sizeof(hexstr) - 1, 0, 0, true); @@ -1914,7 +1901,7 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo PrintAndLogEx(SUCCESS, "%s", binstr + i); - PrintAndLogEx(INFO, "Wiegand decode"); + PrintAndLogEx(INFO, "-----------------------------------------------------------------"); wiegand_message_t packed = initialize_message_object(top, mid, bot); HIDTryUnpack(&packed, true); PrintAndLogEx(INFO, "-----------------------------------------------------------------"); diff --git a/common/cardhelper.c b/common/cardhelper.c index 03af2d799..fbdaf2002 100644 --- a/common/cardhelper.c +++ b/common/cardhelper.c @@ -22,7 +22,7 @@ static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // look for CryptoHelper -bool IsCryptoHelperPresent(void) { +bool IsCryptoHelperPresent(bool verbose) { if (IfPm3Smartcard()) { int resp_len = 0; @@ -31,14 +31,13 @@ bool IsCryptoHelperPresent(void) { ExchangeAPDUSC(true, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len); if (strstr("CryptoHelper", (char *)resp) == 0) { - PrintAndLogEx(INFO, "Found smart card helper"); + if (verbose) { + PrintAndLogEx(INFO, "Found smart card helper"); + } return true; - } else { - return false; } - } else { - return false; } + return false; } static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) { diff --git a/common/cardhelper.h b/common/cardhelper.h index fcdd73cfe..eaf7ff38f 100644 --- a/common/cardhelper.h +++ b/common/cardhelper.h @@ -14,7 +14,7 @@ #include #include "common.h" -bool IsCryptoHelperPresent(void); +bool IsCryptoHelperPresent(bool verbose); bool Encrypt(uint8_t *src, uint8_t *dest); bool Decrypt(uint8_t *src, uint8_t *dest); void DecodeBlock6(uint8_t *src); From 830ecd6e135d85df5f907a1cb4902e39cda05b43 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 22:05:11 +0200 Subject: [PATCH 060/139] debugs --- armsrc/BigBuf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 9b3733d6f..f5a64bfa2 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -186,11 +186,12 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ } if (duration > 0x7FFF) { - if (DBGLEVEL >= DBG_ERROR) { + /* + if (DBGLEVEL >= DBG_DEBUG) { Dbprintf("Error in LogTrace: duration too long for 15 bits encoding: 0x%08x start: 0x%08x end: 0x%08x", duration, timestamp_start, timestamp_end); } + */ duration /= 32; -// duration = 0; } hdr->timestamp = timestamp_start; From f00c0eb5cf91d9efb6db450d943f7799c1acc940 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 22:05:38 +0200 Subject: [PATCH 061/139] prep for timings --- armsrc/iclass.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 84f854c9c..c5fc534f4 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -752,12 +752,12 @@ send: // THE READER CODE -static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time) { +static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time) { CodeIso15693AsReader(frame, len); tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, start_time); - uint32_t end_time = *start_time + (32 * ((8 * ts->max) - 4)); // substract the 4 padding bits after EOF - LogTrace(frame, len, (*start_time * 4), (end_time * 4), NULL, true); + *end_time = *start_time + (32 * ((8 * ts->max) - 4)); // substract the 4 padding bits after EOF + LogTrace(frame, len, (*start_time * 4), (*end_time * 4), NULL, true); } static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* resp, size_t max_resp_size, @@ -765,7 +765,7 @@ static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* uint16_t timeout, uint32_t *eof_time) { while (tries-- > 0) { - iclass_send_as_reader(cmd, cmdsize, &start_time); + iclass_send_as_reader(cmd, cmdsize, &start_time, eof_time); if (resp == NULL) return true; @@ -773,7 +773,7 @@ static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time)) { return true; } -// start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; } return false; } @@ -802,19 +802,15 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t // wakeup uint32_t start_time = GetCountSspClk(); - iclass_send_as_reader(act_all, 1, &start_time); + iclass_send_as_reader(act_all, 1, &start_time, eof_time); int len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time); if (len < 0) return false; -/* - bool ok = iclass_send_cmd_with_retries(act_all, 1, resp, sizeof(resp), 1, 5, start_time, ICLASS_READER_TIMEOUT_ACTALL, eof_time); - if (ok == false) - return false; -*/ + // send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(identify, 1, &start_time); + iclass_send_as_reader(identify, 1, &start_time, eof_time); // expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); @@ -826,7 +822,7 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t // select the card start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(select, sizeof(select), &start_time); + iclass_send_as_reader(select, sizeof(select), &start_time, eof_time); // expect a 10-byte response here, 8 byte CSN and 2 byte CRC len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); @@ -838,7 +834,7 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t // card selected, now read config (block1) (only 8 bytes no CRC) start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time); + iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, eof_time); // expect a 8-byte response here len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); @@ -850,7 +846,7 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time); + iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, eof_time); // expect a 8-byte response here len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); @@ -1215,7 +1211,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; // Auth Sequence MUST begin with reading e-purse. (block2) // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) - iclass_send_as_reader(readcheck_cc, sizeof(readcheck_cc), &start_time); + iclass_send_as_reader(readcheck_cc, sizeof(readcheck_cc), &start_time, &eof_time); LED_B_OFF(); } From dd7a3c208ce3720fa83fc41823d532ced30d1819 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 22:06:15 +0200 Subject: [PATCH 062/139] init arrays... --- armsrc/iso15693.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 82640d0cb..c12e2837b 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -621,7 +621,7 @@ static void DecodeTagReset(DecodeTag_t *DecodeTag) { int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { int samples = 0, ret = 0; - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE] = {0}; // the Decoder data structure DecodeTag_t DecodeTag = { 0 }; @@ -678,7 +678,7 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo } if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { - ret = -1; // timeout + ret = -3; // timeout break; } @@ -704,7 +704,7 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); } - if (ret == -1) { + if (ret == -1) { return ret; } @@ -1016,7 +1016,7 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo int samples = 0; bool gotFrame = false; - uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE] = {0}; // the decoder data structure DecodeReader_t DecodeReader = {0}; @@ -1148,7 +1148,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { set_tracing(true); // The DMA buffer, used to stream samples from the FPGA - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE] = {0}; // Count of samples received so far, so that we can include timing // information in the trace buffer. From 2fa9bd585fd3e8305ae0ce86380775dc074f6a61 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 22:06:50 +0200 Subject: [PATCH 063/139] style --- client/src/comms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/comms.c b/client/src/comms.c index 5976cfcc1..209fd47cd 100644 --- a/client/src/comms.c +++ b/client/src/comms.c @@ -303,7 +303,7 @@ static void PacketResponseReceived(PacketResponseNG *packet) { break; } case CMD_DEBUG_PRINT_INTEGERS: { - if (! packet->ng) + if (packet->ng == false) PrintAndLogEx(NORMAL, "[" _MAGENTA_("pm3") "] ["_BLUE_("#")"] " "%" PRIx64 ", %" PRIx64 ", %" PRIx64 "", packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]); break; } From 4b14f21c77717d21509906b2fe7a53e71b92545e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 13 Jul 2020 23:27:16 +0200 Subject: [PATCH 064/139] fix iclass simulation --- armsrc/iclass.c | 393 ++++++++++++++++++++++++++---------------------- 1 file changed, 213 insertions(+), 180 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index c5fc534f4..d7c57ee01 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -148,8 +148,6 @@ static void CodeIClassTagSOF(void) { // turn off afterwards void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { - if (DBGLEVEL > 3) Dbprintf("[+] iClass_simulate Enter"); - LEDsoff(); Iso15693InitTag(); @@ -176,7 +174,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); } else if (simType == ICLASS_SIM_MODE_READER_ATTACK) { - Dbprintf("[+] going into attack mode, %d CSNS sent", numberOfCSNS); + Dbprintf("going into attack mode, %d CSNS sent", numberOfCSNS); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time // in order to collect MAC's from the reader. This can later be used in an offlne-attack // in order to obtain the keys, as in the "dismantling iclass"-paper. @@ -204,7 +202,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain // the collected data (mac_response) is doubled out since we are trying to collect both keys in the keyroll process. // Keyroll iceman 9 csns * 8 * 2 = 144 // keyroll CARL55 15csns * 8 * 2 = 15 * 8 * 2 = 240 - Dbprintf("[+] going into attack keyroll mode, %d CSNS sent", numberOfCSNS); + Dbprintf("going into attack keyroll mode, %d CSNS sent", numberOfCSNS); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time // in order to collect MAC's from the reader. This can later be used in an offlne-attack // in order to obtain the keys, as in the "dismantling iclass"-paper. @@ -218,14 +216,14 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain memcpy(emulator, datain + (i * 8), 8); // keyroll 1 - if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { + if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); // Button pressed goto out; } // keyroll 2 - if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + (i + numberOfCSNS) * EPURSE_MAC_SIZE)) { + if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + (i + numberOfCSNS) * EPURSE_MAC_SIZE)) { reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); // Button pressed goto out; @@ -237,7 +235,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain } else { // We may want a mode here where we hardcode the csns to use (from proxclone). // That will speed things up a little, but not required just yet. - DbpString("[-] the mode is not implemented, reserved for future use"); + DbpString("the mode is not implemented, reserved for future use"); } out: @@ -471,116 +469,139 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { block = receivedCmd[1]; if (cmd == ICLASS_CMD_ACTALL && len == 1) { // 0x0A - // Reader in anticollission phase + // Reader in anti collision phase if (chip_state != HALTED) { modulated_response = resp_sof; modulated_response_size = resp_sof_len; chip_state = ACTIVATED; + } + goto send; + + } else if (cmd == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // 0x0C + // Reader asks for anti collision CSN + if (chip_state == SELECTED || chip_state == ACTIVATED) { + modulated_response = resp_anticoll; + modulated_response_size = resp_anticoll_len; + trace_data = anticoll_data; + trace_data_size = sizeof(anticoll_data); + } + goto send; + + } else if (cmd == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // 0x0C + + if (chip_state != SELECTED) { goto send; } - - } else if (cmd == ICLASS_CMD_READ_OR_IDENTIFY) { // 0x0C - if (len == 1) { - // Reader asks for anticollission CSN - if (chip_state == SELECTED || chip_state == ACTIVATED) { - modulated_response = resp_anticoll; - modulated_response_size = resp_anticoll_len; //order = 2; - trace_data = anticoll_data; - trace_data_size = sizeof(anticoll_data); + // block0,1,2,5 is always readable. + switch (block) { + case 0: { // csn (0c 00) + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); goto send; } - } + case 1: { // configuration (0c 01) + modulated_response = resp_conf; + modulated_response_size = resp_conf_len; + trace_data = conf_block; + trace_data_size = sizeof(conf_block); + goto send; + } + case 2: {// e-purse (0c 02) + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + // set epurse of sim2,4 attack + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, card_challenge_data, 8); + } + goto send; + } + case 3: + case 4: { // Kd, Kc, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + goto send; + } + case 5: { // Application Issuer Area (0c 05) + modulated_response = resp_aia; + modulated_response_size = resp_aia_len; + trace_data = aia_data; + trace_data_size = sizeof(aia_data); + goto send; + } + default : { + if (simulationMode == ICLASS_SIM_MODE_FULL) { // 0x0C + //Read block + //Take the data... + memcpy(data_generic_trace, emulator + (block << 3), 8); + AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(modulated_response, ts->buf, ts->max); + modulated_response_size = ts->max; + } + goto send; + } + } // swith - if (len == 4) { - if (chip_state == SELECTED) { - // block0,1,2,5 is always readable. - switch (block) { - case 0: { // csn (0c 00) - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - goto send; - } - case 1: { // configuration (0c 01) - modulated_response = resp_conf; - modulated_response_size = resp_conf_len; - trace_data = conf_block; - trace_data_size = sizeof(conf_block); - goto send; - } - case 2: {// e-purse (0c 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - // set epurse of sim2,4 attack - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, card_challenge_data, 8); - } - goto send; - } - case 3: - case 4: { // Kd, Kc, always respond with 0xff bytes - modulated_response = resp_ff; - modulated_response_size = resp_ff_len; - trace_data = ff_data; - trace_data_size = sizeof(ff_data); - goto send; - } - case 5: { // Application Issuer Area (0c 05) - modulated_response = resp_aia; - modulated_response_size = resp_aia_len; - trace_data = aia_data; - trace_data_size = sizeof(aia_data); - goto send; - } - default : { - if (simulationMode == ICLASS_SIM_MODE_FULL) { // 0x0C - //Read block - //Take the data... - memcpy(data_generic_trace, emulator + (block << 3), 8); - AddCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(modulated_response, ts->buf, ts->max); - modulated_response_size = ts->max; - goto send; - } - break; - } - } // swith - } // selected - } // if 4 - } else if (cmd == ICLASS_CMD_SELECT) { // 0x81 + } else if (cmd == ICLASS_CMD_SELECT && len == 9) { // 0x81 // Reader selects anticollission CSN. // Tag sends the corresponding real CSN - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; //order = 3; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); + if (chip_state == ACTIVATED || chip_state == SELECTED) { + if (!memcmp(receivedCmd + 1, anticoll_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } else { + chip_state = IDLE; + } + } else if (chip_state == HALTED) { + // RESELECT with CSN + if (!memcmp(receivedCmd + 1, csn_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } + } goto send; } else if (cmd == ICLASS_CMD_READCHECK) { // 0x88 // Read e-purse KD (88 02) KC (18 02) - if (chip_state == SELECTED) { - if ( ICLASS_DEBIT(cmd) ){ - cipher_state = &cipher_state_KD[current_page]; - diversified_key = diversified_kd; - } else { - cipher_state = &cipher_state_KC[current_page]; - diversified_key = diversified_kc; - } - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); + if (chip_state != SELECTED) { goto send; } - } else if (cmd == ICLASS_CMD_CHECK) { // 0x05 + if ( ICLASS_DEBIT(cmd) ){ + cipher_state = &cipher_state_KD[current_page]; + diversified_key = diversified_kd; + } else { + cipher_state = &cipher_state_KC[current_page]; + diversified_key = diversified_kc; + } + + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + goto send; + + } else if (cmd == ICLASS_CMD_CHECK && len == 9) { // 0x05 + // Reader random and reader MAC!!! + if (chip_state != SELECTED) { + goto send; + } + if (simulationMode == ICLASS_SIM_MODE_FULL) { // NR, from reader, is in receivedCmd +1 opt_doTagMAC_2(*cipher_state, receivedCmd + 1, data_generic_trace, diversified_key); @@ -598,17 +619,18 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { modulated_response_size = 0; trace_data = NULL; trace_data_size = 0; + chip_state = HALTED; - if (simulationMode == MODE_EXIT_AFTER_MAC) { + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { if (DBGLEVEL == DBG_EXTENDED) { - Dbprintf("[+] CSN: %02x %02x %02x %02x %02x %02x %02x %02x", csn[0], csn[1], csn[2], csn[3], csn[4], csn[5], csn[6], csn[7]); - Dbprintf("[+] RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x", len, + Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x", csn[0], csn[1], csn[2], csn[3], csn[4], csn[5], csn[6], csn[7]); + Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x", len, receivedCmd[0], receivedCmd[1], receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5], receivedCmd[6], receivedCmd[7], receivedCmd[8]); } else { - Dbprintf("[+] CSN: %02x .... %02x OK", csn[0], csn[7]); + Dbprintf("CSN: %02x .... %02x OK", csn[0], csn[7]); } if (reader_mac_buf != NULL) { // save NR and MAC for sim 2,4 @@ -616,119 +638,130 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } exit_loop = true; } + } goto send; } else if (cmd == ICLASS_CMD_HALT && options == 0 && len == 1) { - if (chip_state == SELECTED) { - // Reader ends the session - modulated_response = resp_sof; - modulated_response_size = resp_sof_len; - chip_state = HALTED; + if (chip_state != SELECTED) { goto send; } + // Reader ends the session + modulated_response = resp_sof; + modulated_response_size = resp_sof_len; + chip_state = HALTED; + goto send; } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06 - if (chip_state == SELECTED) { - //Read block - memcpy(data_generic_trace, emulator + (current_page * page_size) + (block * 8), 8 * 4); - AddCrc(data_generic_trace, 8 * 4); - trace_data = data_generic_trace; - trace_data_size = 34; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(modulated_response, ts->buf, ts->max); - modulated_response_size = ts->max; + if (chip_state != SELECTED) { goto send; } + //Read block + memcpy(data_generic_trace, emulator + (current_page * page_size) + (block * 8), 8 * 4); + AddCrc(data_generic_trace, 8 * 4); + trace_data = data_generic_trace; + trace_data_size = 34; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(modulated_response, ts->buf, ts->max); + modulated_response_size = ts->max; + goto send; } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { // We're expected to respond with the data+crc, exactly what's already in the receivedCmd // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b - if (chip_state == SELECTED) { + if (chip_state != SELECTED) { + goto send; + } - if (block == 2) { // update e-purse - memcpy(card_challenge_data, receivedCmd + 2, 8); - CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); - memcpy(resp_cc, ts->buf, ts->max); - resp_cc_len = ts->max; - cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); - cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); - - } else if (block == 3) { // update Kd - for (int i = 0; i < 8; i++) { - if (personalization_mode) { - diversified_kd[i] = receivedCmd[2 + i]; - } else { - diversified_kd[i] ^= receivedCmd[2 + i]; - } + if (block == 2) { // update e-purse + memcpy(card_challenge_data, receivedCmd + 2, 8); + CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); + memcpy(resp_cc, ts->buf, ts->max); + resp_cc_len = ts->max; + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); + cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); + + } else if (block == 3) { // update Kd + for (int i = 0; i < 8; i++) { + if (personalization_mode) { + diversified_kd[i] = receivedCmd[2 + i]; + } else { + diversified_kd[i] ^= receivedCmd[2 + i]; } - cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); - - } else if (block == 4) { // update Kc - for (int i = 0; i < 8; i++) { - if (personalization_mode) { - diversified_kc[i] = receivedCmd[2 + i]; - } else { - diversified_kc[i] ^= receivedCmd[2 + i]; - } - } - cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); } - - // update emulator + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); + if (simulationMode == ICLASS_SIM_MODE_FULL) { + memcpy(emulator + (current_page * page_size) + (8 * 3), diversified_kd, 8); + } + } else if (block == 4) { // update Kc + for (int i = 0; i < 8; i++) { + if (personalization_mode) { + diversified_kc[i] = receivedCmd[2 + i]; + } else { + diversified_kc[i] ^= receivedCmd[2 + i]; + } + } + cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); + if (simulationMode == ICLASS_SIM_MODE_FULL) { + memcpy(emulator + (current_page * page_size) + (8 * 4), diversified_kc, 8); + } + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { + // update emulator memory memcpy(emulator + (current_page * page_size) + (8 * block), receivedCmd + 2, 8); + } - memcpy(data_generic_trace, receivedCmd + 2, 8); + memcpy(data_generic_trace, receivedCmd + 2, 8); + AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ts->buf, ts->max); + modulated_response = data_response; + modulated_response_size = ts->max; + goto send; + + } else if (cmd == ICLASS_CMD_PAGESEL && len == 4) { // 0x84 + // Pagesel, + // - enables to select a page in the selected chip memory and return its configuration block + // Chips with a single page will not answer to this command + // Otherwise, we should answer 8bytes (conf block 1) + 2bytes CRC + if (chip_state != SELECTED) { + goto send; + } + + if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { + + current_page = receivedCmd[1]; + + memcpy(data_generic_trace, emulator + (current_page * page_size) + (8 * 1), 8); + memcpy(diversified_kd, emulator + (current_page * page_size) + (8 * 3), 8); + memcpy(diversified_kc, emulator + (current_page * page_size) + (8 * 4), 8); + + cipher_state = &cipher_state_KD[current_page]; + + personalization_mode = data_generic_trace[7] & 0x80; AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); memcpy(data_response, ts->buf, ts->max); modulated_response = data_response; modulated_response_size = ts->max; } goto send; - - } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { // 0x84 - // Pagesel, - // - enables to select a page in the selected chip memory and return its configuration block - // Chips with a single page will not answer to this command - // Otherwise, we should answer 8bytes (conf block 1) + 2bytes CRC - if (chip_state == SELECTED) { - - if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { - - current_page = receivedCmd[1]; - - memcpy(data_generic_trace, emulator + (current_page * page_size) + (8 * 1), 8); - memcpy(diversified_kd, emulator + (current_page * page_size) + (8 * 3), 8); - memcpy(diversified_kc, emulator + (current_page * page_size) + (8 * 4), 8); - - cipher_state = &cipher_state_KD[current_page]; - - personalization_mode = data_generic_trace[7] & 0x80; - AddCrc(data_generic_trace, 8); - - trace_data = data_generic_trace; - trace_data_size = 10; - - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ts->buf, ts->max); - modulated_response = data_response; - modulated_response_size = ts->max; - } - } -// } else if(receivedCmd[0] == ICLASS_CMD_DETECT) { // 0x0F - } else if (receivedCmd[0] == 0x26 && len == 5) { +// } else if(cmd == ICLASS_CMD_DETECT) { // 0x0F + } else if (cmd == 0x26 && len == 5) { // standard ISO15693 INVENTORY command. Ignore. } else { // Never seen this command before if (DBGLEVEL >= DBG_EXTENDED) - print_result("[-] Unhandled command received ", receivedCmd, len); + print_result("Unhandled command received ", receivedCmd, len); } send: @@ -745,7 +778,7 @@ send: LEDsoff(); if (button_pressed) - DbpString("[+] button pressed"); + DbpString("button pressed"); return button_pressed; } From 0f507c24e1722f868bebb598c03f4cce9c9e6eaa Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 00:16:25 +0200 Subject: [PATCH 065/139] chg: readblock assuming better --- client/src/cmdhficlass.c | 45 ++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index b4fc7dcb2..4d21ca3d1 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -371,6 +371,15 @@ typedef enum { TRIPLEDES } BLOCK79ENCRYPTION; +static inline uint32_t leadingzeros(uint64_t a) { +#if defined __GNUC__ + return __builtin_clzll(a); +#else + return 0; +#endif +} + + static uint8_t isset(uint8_t val, uint8_t mask) { return (val & mask); } @@ -1857,14 +1866,14 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo DropField(); - PrintAndLogEx(SUCCESS, "block %02X: " _GREEN_("%s"), blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); + PrintAndLogEx(SUCCESS, " block %02X : " _GREEN_("%s"), blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); if (memcmp(result->blockdata, empty, 8) == 0) return PM3_SUCCESS; if (blockno < 6 || blockno > 7) return PM3_SUCCESS; - + bool use_sc = IsCryptoHelperPresent(verbose); if (use_sc == false) return PM3_SUCCESS; @@ -1876,10 +1885,16 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo break; } case 7: { - PrintAndLogEx(INFO, "Trying to decrypt..."); - + PrintAndLogEx(INFO, "-----------------------------------------------------------------"); uint8_t dec_data[8]; - Decrypt(result->blockdata, dec_data); + uint64_t a = bytes_to_num(result->blockdata, 8); + if (leadingzeros(a) < 16) { + PrintAndLogEx(INFO, "data looks encrypted, false positive is possible"); + Decrypt(result->blockdata, dec_data); + PrintAndLogEx(SUCCESS, "decrypted : " _GREEN_("%s"), sprint_hex(dec_data, sizeof(dec_data))); + } else { + PrintAndLogEx(INFO, "data looks unencrypted, trying to decode"); + } if (memcmp(dec_data, empty, 8) != 0) { @@ -1889,28 +1904,26 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo mid = bytes_to_num(dec_data, 4); bot = bytes_to_num(dec_data + 4, 4); - PrintAndLogEx(INFO, "Binary"); - - char hexstr[8 + 1] = {0}; + char hexstr[16 + 1] = {0}; hex_to_buffer((uint8_t *)hexstr, dec_data, 8, sizeof(hexstr) - 1, 0, 0, true); - - char binstr[8 * 8 + 1] = {0}; + char binstr[64 + 1] = {0}; hextobinstring(binstr, hexstr); uint8_t i = 0; while (i < strlen(binstr) && binstr[i++] == '0'); - PrintAndLogEx(SUCCESS, "%s", binstr + i); - + i &= 0x3C; + PrintAndLogEx(SUCCESS, " bin : %s", binstr + i); PrintAndLogEx(INFO, "-----------------------------------------------------------------"); wiegand_message_t packed = initialize_message_object(top, mid, bot); HIDTryUnpack(&packed, true); - PrintAndLogEx(INFO, "-----------------------------------------------------------------"); } else { - PrintAndLogEx(INFO, "No credential found."); + PrintAndLogEx(INFO, "no credential found"); } - } - } + PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + break; + } + } return PM3_SUCCESS; } From 889d1c93cb0ad63f02315e49174876fbba6bc360 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:25:56 +0200 Subject: [PATCH 066/139] fix: coverity mem leak --- client/src/cmdhficlass.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 4d21ca3d1..4f51042e9 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -536,9 +536,11 @@ static int CmdHFiClassSniff(const char *Cmd) { arg_lit0("j", "jam", "Jam (prevent) e-purse updates"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - + + CLIExecWithReturn(ctx, Cmd, argtable, true); bool jam_epurse_update = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + const uint8_t update_epurse_sequence[2] = {0x87, 0x02}; struct { @@ -1888,7 +1890,7 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo PrintAndLogEx(INFO, "-----------------------------------------------------------------"); uint8_t dec_data[8]; uint64_t a = bytes_to_num(result->blockdata, 8); - if (leadingzeros(a) < 16) { + if (leadingzeros(a) < 12) { PrintAndLogEx(INFO, "data looks encrypted, false positive is possible"); Decrypt(result->blockdata, dec_data); PrintAndLogEx(SUCCESS, "decrypted : " _GREEN_("%s"), sprint_hex(dec_data, sizeof(dec_data))); From bac126530c68afa798fd4574e19cb7804886b170 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:43:54 +0200 Subject: [PATCH 067/139] prep for stand mode --- armsrc/iclass.c | 75 ++++++++++++++++++++++++++++++++++++------------- armsrc/iclass.h | 4 ++- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index d7c57ee01..078da13e5 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -147,6 +147,10 @@ static void CodeIClassTagSOF(void) { */ // turn off afterwards void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { + iclass_simulate(arg0, arg1, arg2, datain, NULL, NULL); +} + +void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen) { LEDsoff(); @@ -155,54 +159,63 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain clear_trace(); set_tracing(true); - uint32_t simType = arg0; - uint32_t numberOfCSNS = arg1; - //Use the emulator memory for SIM uint8_t *emulator = BigBuf_get_EM_addr(); uint8_t mac_responses[PM3_CMD_DATA_SIZE] = { 0 }; - if (simType == ICLASS_SIM_MODE_CSN) { + if (sim_type == ICLASS_SIM_MODE_CSN) { // Use the CSN from commandline memcpy(emulator, datain, 8); doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); - } else if (simType == ICLASS_SIM_MODE_CSN_DEFAULT) { + + } else if (sim_type == ICLASS_SIM_MODE_CSN_DEFAULT) { //Default CSN uint8_t csn[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0 }; // Use the CSN from commandline memcpy(emulator, csn, 8); doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); - } else if (simType == ICLASS_SIM_MODE_READER_ATTACK) { - Dbprintf("going into attack mode, %d CSNS sent", numberOfCSNS); + } else if (sim_type == ICLASS_SIM_MODE_READER_ATTACK) { + + Dbprintf("going into attack mode, %d CSNS sent", num_csns); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time // in order to collect MAC's from the reader. This can later be used in an offlne-attack // in order to obtain the keys, as in the "dismantling iclass"-paper. #define EPURSE_MAC_SIZE 16 int i = 0; - for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < PM3_CMD_DATA_SIZE; i++) { + for (; i < num_csns && i * EPURSE_MAC_SIZE + 8 < PM3_CMD_DATA_SIZE; i++) { memcpy(emulator, datain + (i * 8), 8); if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { + + if (dataoutlen) + *dataoutlen = i * EPURSE_MAC_SIZE; + // Button pressed - reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i, 0, mac_responses, i * EPURSE_MAC_SIZE); + if (send_reply) + reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i, 0, mac_responses, i * EPURSE_MAC_SIZE); goto out; } } - reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i, 0, mac_responses, i * EPURSE_MAC_SIZE); + if (dataoutlen) + *dataoutlen = i * EPURSE_MAC_SIZE; - } else if (simType == ICLASS_SIM_MODE_FULL) { + if (send_reply) + reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i, 0, mac_responses, i * EPURSE_MAC_SIZE); + + } else if (sim_type == ICLASS_SIM_MODE_FULL) { //This is 'full sim' mode, where we use the emulator storage for data. //ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command doIClassSimulation(ICLASS_SIM_MODE_FULL, NULL); - } else if (simType == ICLASS_SIM_MODE_READER_ATTACK_KEYROLL) { + + } else if (sim_type == ICLASS_SIM_MODE_READER_ATTACK_KEYROLL) { // This is the KEYROLL version of sim 2. // the collected data (mac_response) is doubled out since we are trying to collect both keys in the keyroll process. // Keyroll iceman 9 csns * 8 * 2 = 144 // keyroll CARL55 15csns * 8 * 2 = 15 * 8 * 2 = 240 - Dbprintf("going into attack keyroll mode, %d CSNS sent", numberOfCSNS); + Dbprintf("going into attack keyroll mode, %d CSNS sent", num_csns); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time // in order to collect MAC's from the reader. This can later be used in an offlne-attack // in order to obtain the keys, as in the "dismantling iclass"-paper. @@ -211,27 +224,44 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain // attack below is same as SIM 2, but we run the CSN twice to collected the mac for both keys. int i = 0; // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. iceman fork uses 9 CSNS - for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < PM3_CMD_DATA_SIZE; i++) { + for (; i < num_csns && i * EPURSE_MAC_SIZE + 8 < PM3_CMD_DATA_SIZE; i++) { memcpy(emulator, datain + (i * 8), 8); // keyroll 1 if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { - reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + + if (dataoutlen) + *dataoutlen = i * EPURSE_MAC_SIZE * 2; + + if (send_reply) + reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + // Button pressed goto out; } // keyroll 2 - if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + (i + numberOfCSNS) * EPURSE_MAC_SIZE)) { - reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + (i + num_csns) * EPURSE_MAC_SIZE)) { + + if (dataoutlen) + *dataoutlen = i * EPURSE_MAC_SIZE * 2; + + if (send_reply) + reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + // Button pressed goto out; } } - // double the amount of collected data. - reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + if (dataoutlen) + *dataoutlen = i * EPURSE_MAC_SIZE * 2; + + // double the amount of collected data. + if (send_reply) + reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + } else { // We may want a mode here where we hardcode the csns to use (from proxclone). // That will speed things up a little, but not required just yet. @@ -239,6 +269,9 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain } out: + if (dataout && dataoutlen) + memcpy(dataout, mac_responses, *dataoutlen); + switch_off(); BigBuf_free_keep_EM(); } @@ -683,7 +716,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { resp_cc_len = ts->max; cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); - + if (simulationMode == ICLASS_SIM_MODE_FULL) { + memcpy(emulator + (current_page * page_size) + (8 * 2), card_challenge_data, 8); + } } else if (block == 3) { // update Kd for (int i = 0; i < 8; i++) { if (personalization_mode) { diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 20a862535..3b4de40f0 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -14,7 +14,6 @@ #include "common.h" void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string); -void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void ReaderIClass(uint8_t arg0); void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac); void iClass_Authentication(uint8_t *mac); @@ -27,4 +26,7 @@ void iClass_ReadCheck(uint8_t blockno, uint8_t keytype); int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); + +void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen); #endif From 4dabccf9dbe46853855e454b82ea5cc41ee824f9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:44:23 +0200 Subject: [PATCH 068/139] style --- armsrc/spiffs.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/armsrc/spiffs.c b/armsrc/spiffs.c index 025146b55..10c923c14 100644 --- a/armsrc/spiffs.c +++ b/armsrc/spiffs.c @@ -496,10 +496,10 @@ int rdv40_spiffs_read_as_symlink(char *filename, uint8_t *dst, uint32_t size, RD // rdv40_spiffs_read_as_symlink((uint8_t *)"world",(uint8_t *) buffer, orig_file_size, RDV40_SPIFFS_SAFETY_SAFE); // TODO : FORBID creating a symlink with a basename (before.lnk) which already exists as a file ! int rdv40_spiffs_make_symlink(char *linkdest, char *filename, RDV40SpiFFSSafetyLevel level) { - RDV40_SPIFFS_SAFE_FUNCTION( // - char linkfilename[SPIFFS_OBJ_NAME_LEN]; // + RDV40_SPIFFS_SAFE_FUNCTION( + char linkfilename[SPIFFS_OBJ_NAME_LEN]; sprintf(linkfilename, "%s.lnk", filename); - write_to_spiffs((char *)linkfilename, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN); // + write_to_spiffs((char *)linkfilename, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN); ) } @@ -510,20 +510,20 @@ int rdv40_spiffs_make_symlink(char *linkdest, char *filename, RDV40SpiFFSSafetyL // preexistance, avoiding a link being created if filename exists, or avoiding a file being created if // symlink exists with same name int rdv40_spiffs_read_as_filetype(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) { - RDV40_SPIFFS_SAFE_FUNCTION( // - RDV40SpiFFSFileType filetype = filetype_in_spiffs((char *)filename); // - switch (filetype) { - case RDV40_SPIFFS_FILETYPE_REAL: - rdv40_spiffs_read((char *)filename, (uint8_t *)dst, size, level); - break; - case RDV40_SPIFFS_FILETYPE_SYMLINK: - rdv40_spiffs_read_as_symlink((char *)filename, (uint8_t *)dst, size, level); - break; - case RDV40_SPIFFS_FILETYPE_BOTH: - case RDV40_SPIFFS_FILETYPE_UNKNOWN: - default: + RDV40_SPIFFS_SAFE_FUNCTION( + RDV40SpiFFSFileType filetype = filetype_in_spiffs((char *)filename); + switch (filetype) { + case RDV40_SPIFFS_FILETYPE_REAL: + rdv40_spiffs_read((char *)filename, (uint8_t *)dst, size, level); + break; + case RDV40_SPIFFS_FILETYPE_SYMLINK: + rdv40_spiffs_read_as_symlink((char *)filename, (uint8_t *)dst, size, level); + break; + case RDV40_SPIFFS_FILETYPE_BOTH: + case RDV40_SPIFFS_FILETYPE_UNKNOWN: + default: ; - } // + } ) } From d2a66cecba6ea66f0e0d7d85b74fb7fe47f27563 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:44:38 +0200 Subject: [PATCH 069/139] style --- armsrc/BigBuf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index f5a64bfa2..7cb440d82 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -114,8 +114,6 @@ void BigBuf_free_keep_EM(void) { s_bigbuf_hi = emulator_memory - (uint8_t *)BigBuf; else s_bigbuf_hi = s_bigbuf_size; - - // shouldn't this empty BigBuf also? } void BigBuf_print_status(void) { From ce981d91247bdfc45a4bd568cfc4f2698afd1139 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:46:05 +0200 Subject: [PATCH 070/139] fpga 14b merge p.N --- armsrc/iso14443b.c | 322 ++++++++++++++++++++++----------------------- 1 file changed, 159 insertions(+), 163 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index b06dbcb44..d9d08a966 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -138,9 +138,9 @@ static uint32_t iso14b_timeout = TR0; // them yet, just leaves them ready to send in ToSend[]. //----------------------------------------------------------------------------- static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { - int i; + int i; - tosend_reset(); + tosend_reset(); // Transmit a burst of ones, as the initial thing that lets the // reader get phase sync. @@ -152,56 +152,56 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { // Send TR1. // 10-11 ETU * 4times samples ONES - for (i = 0; i < 20; i++) { - SEND4STUFFBIT(1); - } + for (i = 0; i < 20; i++) { + SEND4STUFFBIT(1); + } // Send SOF. // 10-11 ETU * 4times samples ZEROS - for (i = 0; i < 10; i++) { - SEND4STUFFBIT(0); - } + for (i = 0; i < 10; i++) { + SEND4STUFFBIT(0); + } // 2-3 ETU * 4times samples ONES - for (i = 0; i < 2; i++) { - SEND4STUFFBIT(1); - } + for (i = 0; i < 2; i++) { + SEND4STUFFBIT(1); + } // data - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) { // Start bit - SEND4STUFFBIT(0); + SEND4STUFFBIT(0); - // Data bits - uint8_t b = cmd[i]; - for (int j = 0; j < 8; j++) { + // Data bits + uint8_t b = cmd[i]; + for (int j = 0; j < 8; j++) { SEND4STUFFBIT(b & 1); - b >>= 1; - } + b >>= 1; + } - // Stop bit - SEND4STUFFBIT(1); + // Stop bit + SEND4STUFFBIT(1); // Extra Guard bit // For PICC it ranges 0-18us (1etu = 9us) //SEND4STUFFBIT(1); - } + } // Send EOF. // 10-11 ETU * 4 sample rate = ZEROS - for(i = 0; i < 10; i++) { - SEND4STUFFBIT(0); - } + for(i = 0; i < 10; i++) { + SEND4STUFFBIT(0); + } // why this? - for(i = 0; i < 2; i++) { - SEND4STUFFBIT(1); - } + for(i = 0; i < 2; i++) { + SEND4STUFFBIT(1); + } tosend_t *ts = get_tosend(); - // Convert from last byte pos to length - ts->max++; + // Convert from last byte pos to length + ts->max++; } //----------------------------------------------------------------------------- @@ -451,10 +451,10 @@ static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) { while (BUTTON_PRESS() == false) { WDT_HIT(); - 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 (Handle14443bReaderUartBit(b & mask)) { + 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 (Handle14443bReaderUartBit(b & mask)) { *len = Uart.byteCnt; return true; } @@ -497,13 +497,13 @@ static void TransmitFor14443b_AsTag(uint8_t *response, uint16_t len) { void SimulateIso14443bTag(uint32_t pupi) { LED_A_ON(); - // the only commands we understand is WUPB, AFI=0, Select All, N=1: + // the only commands we understand is WUPB, AFI=0, Select All, N=1: // static const uint8_t cmdWUPB[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; // WUPB - // ... and REQB, AFI=0, Normal Request, N=1: + // ... and REQB, AFI=0, Normal Request, N=1: // static const uint8_t cmdREQB[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xFF }; // REQB - // ... and HLTB -// static const uint8_t cmdHLTB[] = { 0x50, 0xff, 0xff, 0xff, 0xff }; // HLTB - // ... and ATTRIB + // ... and HLTB +// static const uint8_t cmdHLTB[] = { 0x50, 0xff, 0xff, 0xff, 0xff }; // HLTB + // ... and ATTRIB // static const uint8_t cmdATTRIB[] = { ISO14443B_ATTRIB, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // ATTRIB // ... if not PUPI/UID is supplied we always respond with ATQB, PUPI = 820de174, Application Data = 0x20381922, @@ -532,7 +532,7 @@ void SimulateIso14443bTag(uint32_t pupi) { // connect Demodulated Signal to ADC: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Set up the synchronous serial port + // Set up the synchronous serial port FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); // allocate command receive buffer @@ -720,10 +720,7 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { } \ } -// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(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 SUBCARRIER_DETECT_THRESHOLD 8 +#define SUBCARRIER_DETECT_THRESHOLD 8 //note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow #define CHECK_FOR_SUBCARRIER(void) { v = MAX(myI, myQ) + (MIN(myI, myQ) >> 1); } @@ -773,8 +770,8 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { } else { // maximum length of TR1 = 200 1/fs if (Demod.posCount > 200 / 4){ - Demod.state = DEMOD_UNSYNCD; - } + Demod.state = DEMOD_UNSYNCD; + } } Demod.posCount++; break; @@ -792,7 +789,7 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { LED_C_ON(); // Got SOF Demod.state = DEMOD_AWAITING_START_BIT; Demod.posCount = 0; - Demod.bitCount = 0; + Demod.bitCount = 0; Demod.len = 0; } } else { @@ -811,12 +808,12 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { if (v > 0) { if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs - LED_C_OFF(); - if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass - return true; - } else { - Demod.state = DEMOD_UNSYNCD; - } + LED_C_OFF(); + if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass + return true; + } else { + Demod.state = DEMOD_UNSYNCD; + } } } else { // start bit detected Demod.bitCount = 0; @@ -856,8 +853,8 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { // left shift to drop the startbit uint8_t b = (s >> 1); Demod.output[Demod.len] = b; - Demod.len++; - Demod.bitCount = 0; + Demod.len++; + Demod.bitCount = 0; Demod.state = DEMOD_AWAITING_START_BIT; } else { // this one is a bit hard, either its a correc byte or its unsynced. @@ -883,27 +880,26 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { /* * Demodulate the samples we received from the tag, also log to tracebuffer - * quiet: set to 'TRUE' to disable debug output */ static int GetTagSamplesFor14443bDemod(int timeout) { - int ret = 0; - int maxBehindBy = 0; - int lastRxCounter, samples = 0; - int8_t ci, cq; + int ret = 0; + int maxBehindBy = 0; + int lastRxCounter, samples = 0; + int8_t ci, cq; uint32_t time_0 = 0, time_stop = 0; BigBuf_free(); - // The response (tag -> reader) that we're receiving. - uint8_t *receivedResponse = 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 - uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); + // The DMA buffer, used to stream samples from the FPGA + uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); // Set up the demodulator for tag -> reader responses. Demod14bInit(receivedResponse); - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) // Setup and start DMA. FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); @@ -912,60 +908,60 @@ static int GetTagSamplesFor14443bDemod(int timeout) { return -1; } - uint16_t *upTo = dmaBuf; - lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + uint16_t *upTo = dmaBuf; + lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; - // Signal field is ON with the appropriate LED: - LED_D_ON(); + // 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 | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); - for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1); - if (behindBy > maxBehindBy) { - maxBehindBy = behindBy; - } + for(;;) { + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1); + if (behindBy > maxBehindBy) { + maxBehindBy = behindBy; + } - if (behindBy < 1) continue; + if (behindBy < 1) continue; - ci = *upTo >> 8; - cq = *upTo; - upTo++; - lastRxCounter--; - if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; - } + ci = *upTo >> 8; + cq = *upTo; + upTo++; + lastRxCounter--; + if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; + } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers - } - samples++; + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers + } + samples++; - if (Handle14443bTagSamplesDemod(ci, cq)) { - ret = Demod.len; - break; - } + if (Handle14443bTagSamplesDemod(ci, cq)) { + ret = Demod.len; + break; + } - if(samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) { - ret = -1; - LED_C_OFF(); - break; - } + if(samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) { + ret = -1; + LED_C_OFF(); + break; + } } FpgaDisableSscDma(); - if (ret < 0) { - return ret; - } - - if (Demod.len > 0) { - LogTrace(Demod.output, Demod.len, time_0, time_stop, NULL, false); + if (ret < 0) { + return ret; } - return ret; + if (Demod.len > 0) { + LogTrace(Demod.output, Demod.len, time_0, time_stop, NULL, false); + } + + return ret; } //----------------------------------------------------------------------------- @@ -973,27 +969,27 @@ static int GetTagSamplesFor14443bDemod(int timeout) { //----------------------------------------------------------------------------- static void TransmitFor14443b_AsReader(void) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); - LED_B_ON(); + LED_B_ON(); tosend_t *ts = get_tosend(); - for (int c = 0; c < ts->max; c++) { - uint8_t data = ts->buf[c]; - for (int i = 0; i < 8; i++) { - uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; - - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - - AT91C_BASE_SSC->SSC_THR = send_word; - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - AT91C_BASE_SSC->SSC_THR = send_word; + for (int c = 0; c < ts->max; c++) { + uint8_t data = ts->buf[c]; + for (int i = 0; i < 8; i++) { + uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; + + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + + AT91C_BASE_SSC->SSC_THR = send_word; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; - data <<= 1; - } + data <<= 1; + } WDT_HIT(); } - LED_B_OFF(); + LED_B_OFF(); } //----------------------------------------------------------------------------- @@ -1021,7 +1017,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { // Send SOF // 10-11 ETUs of ZERO for (int i = 0; i < 10; i++) - tosend_stuffbit(0); + tosend_stuffbit(0); // 2-3 ETUs of ONE @@ -1057,16 +1053,16 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { // Send EOF // 10-11 ETUs of ZERO for (int i = 0; i < 10; i++) - tosend_stuffbit(0); + tosend_stuffbit(0); // Transition time. TR0 - guard time // 8ETUS minum? // Per specification, Subcarrier must be stopped no later than 2 ETUs after EOF. // I'm guessing this is for the FPGA to be able to send all bits before we switch to listening mode - - // ensure that last byte is filled up + + // ensure that last byte is filled up for (int i = 0; i < 8 ; ++i) - tosend_stuffbit(1); + tosend_stuffbit(1); // TR1 - Synchronization time // Convert from last character reference to length @@ -1090,7 +1086,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) { * TODO: check CRC and preamble */ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) { - LED_A_ON(); + LED_A_ON(); uint8_t message_frame[message_length + 4]; // PCB message_frame[0] = 0x0A | pcb_blocknum; @@ -1109,9 +1105,9 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r FpgaDisableTracing(); if (ret < 3) { - LED_A_OFF(); + LED_A_OFF(); return 0; - } + } // VALIDATE CRC if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) { @@ -1123,7 +1119,7 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r memcpy(response, Demod.output, Demod.len); return Demod.len; - LED_A_OFF(); + LED_A_OFF(); } /** @@ -1280,7 +1276,7 @@ void iso14443b_setup(void) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Set up the synchronous serial port - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // Signal field is on with the appropriate LED FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); @@ -1439,15 +1435,15 @@ void RAMFUNC SniffIso14443b(void) { iso1444b_setup_sniff(); // The DMA buffer, used to stream samples from the FPGA - uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); - uint16_t *upTo = dmaBuf; - int lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; - int8_t ci, cq; - int maxBehindBy = 0; + uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); + uint16_t *upTo = dmaBuf; + int lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + int8_t 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; + // Count of samples received so far, so that we can include timing + // information in the trace buffer. + int samples = 0; // Setup and start DMA. if (!FpgaSetupSscDma((uint8_t *) dmaBuf, ISO14443B_DMA_BUFFER_SIZE)) { @@ -1462,38 +1458,38 @@ void RAMFUNC SniffIso14443b(void) { // loop and listen for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE - 1); - if (behindBy > maxBehindBy) { - maxBehindBy = behindBy; - } + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE - 1); + if (behindBy > maxBehindBy) { + maxBehindBy = behindBy; + } if (behindBy < 1) continue; - ci = *upTo >> 8; - cq = *upTo; - upTo++; - lastRxCounter--; + ci = *upTo >> 8; + cq = *upTo; + upTo++; + lastRxCounter--; if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning again - lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; - if (behindBy > (9 * ISO14443B_DMA_BUFFER_SIZE / 10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); - break; - } - } + upTo = dmaBuf; // start reading the circular buffer from the beginning again + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; + if (behindBy > (9 * ISO14443B_DMA_BUFFER_SIZE / 10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + break; + } + } if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers - WDT_HIT(); - if (BUTTON_PRESS()) { - DbpString("Button pressed, cancelled"); - break; - } - } + WDT_HIT(); + if (BUTTON_PRESS()) { + DbpString("Button pressed, cancelled"); + break; + } + } - samples++; + samples++; // no need to try decoding reader data if the tag is sending if (TagIsActive == false) { @@ -1538,7 +1534,7 @@ void RAMFUNC SniffIso14443b(void) { } } - FpgaDisableSscDma(); + FpgaDisableSscDma(); if (DBGLEVEL >= 2) { DbpString("[+] Sniff statistics:"); Dbprintf("[+] uart State: %x ByteCount: %i ByteCountMax: %i", Uart.state, Uart.byteCnt, Uart.byteCntMax); From a95f4b3745481ca38520dc2310a68550dd4b46a5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:46:32 +0200 Subject: [PATCH 071/139] chg: check buttonpress --- armsrc/iso15693.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index c12e2837b..ff59d260a 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1066,16 +1066,16 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo samples++; } - if (gotFrame) { - break; - } - if (BUTTON_PRESS()) { DecodeReader.byteCount = -1; break; } WDT_HIT(); + + if (gotFrame) { + break; + } } FpgaDisableSscDma(); From 49192ca4c47665b0478f98cfa1d9d8d772465ec2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:47:47 +0200 Subject: [PATCH 072/139] add: new standalone mode. hf_iceclass --- armsrc/Standalone/Makefile.hal | 7 +- armsrc/Standalone/Makefile.inc | 6 +- armsrc/Standalone/hf_iceclass.c | 163 ++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 armsrc/Standalone/hf_iceclass.c diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index c6dc9952e..bd66d538c 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -44,6 +44,9 @@ define KNOWN_STANDALONE_DEFINITIONS | HF_COLIN | Mifare ultra fast sniff/sim/clone | | (RDV4 only) | - Colin Brigato | +----------------------------------------------------------+ +| HF_ICECLASS | Simulate HID iCLASS legacy ags | +| (RDV4 only) | storing in flashmem | ++----------------------------------------------------------+ | HF_LEGIC | Read/simulate Legic Prime tags | | | storing in flashmem | +----------------------------------------------------------+ @@ -59,9 +62,9 @@ define KNOWN_STANDALONE_DEFINITIONS endef STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN -STANDALONE_MODES += HF_14ASNIFF HF_BOG HF_COLIN HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_YOUNG +STANDALONE_MODES += HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_YOUNG STANDALONE_MODES_REQ_SMARTCARD := -STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN +STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),) STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE) ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index a06cfe75e..131e26e79 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -57,7 +57,11 @@ endif ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS))) SRC_STANDALONE = hf_legic.c endif -# WITH_STANDALONE_LF_MSDSAL +# WITH_STANDALONE_HF_MSDSAL ifneq (,$(findstring WITH_STANDALONE_HF_MSDSAL,$(APP_CFLAGS))) SRC_STANDALONE = hf_msdsal.c endif +# WITH_STANDALONE_HF_ICECLASS +ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS))) + SRC_STANDALONE = hf_iceclass.c +endif diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c new file mode 100644 index 000000000..778a9808a --- /dev/null +++ b/armsrc/Standalone/hf_iceclass.c @@ -0,0 +1,163 @@ +//----------------------------------------------------------------------------- +// Christian Herrmann, 2020 +// +// 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. +//----------------------------------------------------------------------------- +// main code for hf_iceclass by Iceman +//----------------------------------------------------------------------------- +#include "standalone.h" // standalone definitions +#include "proxmark3_arm.h" +#include "appmain.h" +#include "BigBuf.h" +#include "fpgaloader.h" +#include "util.h" +#include "dbprint.h" +#include "spiffs.h" +#include "iclass.h" +#include "optimized_cipher.h" + +#define NUM_CSNS 9 +#define MAC_RESPONSES_SIZE (16 * NUM_CSNS) +#define HF_ICLASS_FULLSIM_ORG_BIN "iceclass-orig.bin" +#define HF_ICLASS_FULLSIM_POST_BIN "iceclass-modified.bin" +#define HF_ICLASS_FULLSIM_POST_EML "iceclass-modified-lasttag.bin.eml" +#define HF_ICLASS_ATTACK_BIN "iceclass_mac_attack.bin" + +static uint8_t legacy_aa1_key[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78}; + +static uint8_t csns[8 * NUM_CSNS] = { + 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, + 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0, + 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0, + 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0, + 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0, + 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0, + 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0, + 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0, + 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0 + //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0 +}; + +static void DownloadLogInstructions(uint8_t t) { + Dbprintf(""); + switch (t) { + case ICLASS_SIM_MODE_FULL: { + Dbprintf("The emulator memory was saved to flash. Try the following from flash and display it"); + Dbprintf("1. " _YELLOW_("mem spiffs dump o "HF_ICLASS_FULLSIM_POST_BIN" f "HF_ICLASS_FULLSIM_POST_BIN" e")); + Dbprintf("2. " _YELLOW_("exit proxmark3 client")); + Dbprintf("3. " _YELLOW_("cat "HF_ICLASS_FULLSIM_POST_EML)); + break; + } + case ICLASS_SIM_MODE_READER_ATTACK: { + Dbprintf("The emulator memory was saved to flash. Try the following from flash and display it"); + Dbprintf("1. " _YELLOW_("mem spiffs dump o "HF_ICLASS_FULLSIM_POST_BIN" f "HF_ICLASS_FULLSIM_POST_BIN" e")); + Dbprintf("2. " _YELLOW_("hf iclass loclass f "HF_ICLASS_ATTACK_BIN)); + break; + } + } +} + +void ModInfo(void) { + DbpString(" HF iCLASS mode - aka iceCLASS (iceman)"); +} + +void RunMod(void) { + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + BigBuf_Clear(); + + StandAloneMode(); + Dbprintf(_YELLOW_("HF iCLASS mode a.k.a iceCLASS started")); + + uint8_t simtype = ICLASS_SIM_MODE_FULL; + + for (;;) { + WDT_HIT(); + + // exit from RunMod, send a usbcommand. + if (data_available()) break; + + // Was our button held down or pressed? + int button_pressed = BUTTON_HELD(1000); + if (button_pressed != BUTTON_NO_CLICK) { + break; + } + + switch (simtype) { + case ICLASS_SIM_MODE_FULL: { + + Dbprintf("enter full simulation mode"); + + rdv40_spiffs_lazy_mount(); + // Look for a dump file in FLASH MEM. + if (exists_in_spiffs(HF_ICLASS_FULLSIM_ORG_BIN) == false) { + Dbprintf("error, '" _YELLOW_(HF_ICLASS_FULLSIM_ORG_BIN) "' file missing"); + Dbprintf("changing to reader attack mode instead"); + simtype = ICLASS_SIM_MODE_READER_ATTACK; + break; + } + + SpinOff(0); + uint8_t *emul = BigBuf_get_EM_addr(); + uint32_t fsize = size_in_spiffs(HF_ICLASS_FULLSIM_ORG_BIN); + int res = rdv40_spiffs_read_as_filetype(HF_ICLASS_FULLSIM_ORG_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + Dbprintf("Found `" _YELLOW_(HF_ICLASS_FULLSIM_ORG_BIN) "` , loaded %u bytes to emulator memory", fsize); + + if ( memcmp(emul + (3 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 0) { + // create diversified key if not in dump. + uint8_t ccnr[12] = {0}; + memcpy(ccnr, emul + (2 * 8), 8); + bool use_elite = false; + + iclass_calc_div_key(emul, legacy_aa1_key, emul + (3 * 8), use_elite); + + Dbhexdump(8, emul + (3 * 8), false); + } + + iclass_simulate(ICLASS_SIM_MODE_FULL, 0 , false, NULL, NULL, NULL); + + LED_B_ON(); + rdv40_spiffs_lazy_mount(); + res = rdv40_spiffs_write(HF_ICLASS_FULLSIM_POST_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + LED_B_OFF(); + if (res != 0) { + Dbprintf("error writing '"HF_ICLASS_FULLSIM_POST_BIN"' to flash ( %d )", res); + } + DownloadLogInstructions(simtype); + simtype = 0; + break; + } + case ICLASS_SIM_MODE_READER_ATTACK: { + + Dbprintf("enter reader attack mode"); + uint16_t mac_response_len = 0; + uint8_t mac_responses[MAC_RESPONSES_SIZE] = {0}; + + iclass_simulate(ICLASS_SIM_MODE_READER_ATTACK, NUM_CSNS, false, csns, mac_responses, &mac_response_len); + + if (mac_response_len > 0) { + + LED_B_ON(); + rdv40_spiffs_lazy_mount(); + int res = rdv40_spiffs_write(HF_ICLASS_ATTACK_BIN, mac_responses, mac_response_len, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + LED_B_OFF(); + if (res != 0) { + Dbprintf("error writing '"HF_ICLASS_ATTACK_BIN"' to flash ( %d )", res); + } + } + DownloadLogInstructions(simtype); + simtype = 0; + break; + } + } // switch + } // for loop + + + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +} From 804e2661f3abf8e8d7a2e39c9bd9a9d9297f881c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:55:44 +0200 Subject: [PATCH 073/139] key file py script - @ikarus --- tools/pm3_key_file_diff.py | 80 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100755 tools/pm3_key_file_diff.py diff --git a/tools/pm3_key_file_diff.py b/tools/pm3_key_file_diff.py new file mode 100755 index 000000000..4069d6684 --- /dev/null +++ b/tools/pm3_key_file_diff.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +######################################################################## +# +# Copyright 2018 Gerhard Klostermeier +# +# 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 3 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, see . +# +######################################################################## +# +# Usage: ./key-file-diff.py +# +######################################################################## +# +# Info: +# - Read two key files and show the keys that are in file B but not in A. +# - Keys must be 12 hex characters long and at the beginning of a line. +# +######################################################################## + + +import re + + +def main(args): + """ + Read two key files and show the keys that are in file B but not in A. + :param args: Path to two key files A and B (positional shell parameters). + :return: 0 if everything went fine. + """ + key_file_a = args[1] + key_file_b = args[2] + + with open(key_file_a, 'r') as f: + keys_a = parse_keys(f) + with open(key_file_b, 'r') as f: + keys_b = parse_keys(f) + + # Show all keys that are in B but not in A. + keys_diff = keys_b.difference(keys_a) + for key in keys_diff: + print(key) + + return 0 + + +def parse_keys(file): + """ + Parse keys from a file and return them as a set. + Keys must be 12 hex characters long and at the beginning of a line. + :param file: Path to a file containing keys. + :return: A set of keys read from the file. + """ + keys = set() + key_regex = re.compile('^[0-9a-fA-F]{12}') + for line in file: + key = key_regex.match(line) + try: + key = key.group(0).upper() + keys.add(key) + except AttributeError: + pass + return keys + + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv)) From 99e61f82c03149e905296998d082bfe9d7d19977 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 15:57:21 +0200 Subject: [PATCH 074/139] rework --- armsrc/Standalone/lf_em4100rwc.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/armsrc/Standalone/lf_em4100rwc.c b/armsrc/Standalone/lf_em4100rwc.c index c54e54fa2..7b269e89b 100644 --- a/armsrc/Standalone/lf_em4100rwc.c +++ b/armsrc/Standalone/lf_em4100rwc.c @@ -34,7 +34,7 @@ #endif #define MAX_IND 16 // 4 LEDs - 2^4 combinations -#define CLOCK 64 //for 125kHz +#define LF_CLOCK 64 // for 125kHz // low & high - array for storage IDs. Its length must be equal. // Predefined IDs must be stored in low[]. @@ -57,34 +57,35 @@ static uint64_t rev_quads(uint64_t bits) { } static void fillbuff(uint8_t bit) { - memset(bba + buflen, bit, CLOCK / 2); - buflen += (CLOCK / 2); - memset(bba + buflen, bit ^ 1, CLOCK / 2); - buflen += (CLOCK / 2); + memset(bba + buflen, bit, LF_CLOCK / 2); + buflen += (LF_CLOCK / 2); + memset(bba + buflen, bit ^ 1, LF_CLOCK / 2); + buflen += (LF_CLOCK / 2); } static void construct_EM410x_emul(uint64_t id) { - + + int i, j; int binary[4] = {0}; int parity[4] = {0}; buflen = 0; - for (uint8_t i = 0; i < 9; i++) + for (i = 0; i < 9; i++) fillbuff(1); - for (uint8_t i = 0; i < 10; i++) { - for (uint8_t j = 3; j > 0; j--, id /= 2) + for (i = 0; i < 10; i++) { + for (j = 3; j >= 0; j--, id /= 2) binary[j] = id % 2; - for (uint8_t j = 0; j < 4; j++) + for (j = 0; j < 4; j++) fillbuff(binary[j]); fillbuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]); - for (uint8_t j = 0; j < 4; j++) + for (j = 0; j < 4; j++) parity[j] ^= binary[j]; } - for (uint8_t j = 0; j < 4; j++) + for (j = 0; j < 4; j++) fillbuff(parity[j]); fillbuff(0); @@ -207,7 +208,7 @@ void RunMod(void) { state = 0; } else if (button_pressed == BUTTON_SINGLE_CLICK) { // Click - write ID to tag - copy_em410x_to_t55xx(0, CLOCK, (uint32_t)(low[selected] >> 32), (uint32_t)(low[selected] & 0xffffffff)); + copy_em410x_to_t55xx(0, LF_CLOCK, (uint32_t)(low[selected] >> 32), (uint32_t)(low[selected] & 0xffffffff)); led_slot(selected); state = 0; // Switch to select mode } From 091f9fb94cbb0a6255a53c404288f5ec84f4f8a7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 23:11:44 +0200 Subject: [PATCH 075/139] chg: adapt the eml block size based on filename --- client/src/cmdflashmemspiffs.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/src/cmdflashmemspiffs.c b/client/src/cmdflashmemspiffs.c index b994ea56c..d7f2b016c 100644 --- a/client/src/cmdflashmemspiffs.c +++ b/client/src/cmdflashmemspiffs.c @@ -322,7 +322,14 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) { if (filename[0] != '\0') { saveFile(filename, "", dump, len); if (eml) { - saveFileEML(filename, dump, len, 16); + uint8_t eml_len = 16; + + if (strstr(filename, "iclass") != NULL) + eml_len = 8; + else if (strstr(filename, "mfu") != NULL) + eml_len = 4; + + saveFileEML(filename, dump, len, eml_len); } } From 1a1ebcc330ca306461752d3304c367b94f1513d1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 23:12:28 +0200 Subject: [PATCH 076/139] adapt for external auth calls --- armsrc/iclass.c | 22 ++++++++++++++++++---- armsrc/iclass.h | 13 ++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 078da13e5..f232c35ed 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1153,6 +1153,10 @@ void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { // which needs to authenticate before doing more things like read/write // selects and authenticate to a card, sends back div_key and mac to client. void iClass_Authentication(uint8_t *bytes) { + iclass_auth(bytes, true, NULL); +} + +bool iclass_auth(uint8_t *bytes, bool send_reply, uint8_t *dataout) { struct p { uint8_t key[8]; @@ -1176,8 +1180,10 @@ void iClass_Authentication(uint8_t *bytes) { packet.isOK = select_iclass_tag(card_data, payload->use_credit_key, &eof_time); if (packet.isOK == false) { - reply_ng(CMD_HF_ICLASS_AUTH, PM3_ESOFT, (uint8_t *)&packet, sizeof(packet)); - return; + if (send_reply) + reply_ng(CMD_HF_ICLASS_AUTH, PM3_ESOFT, (uint8_t *)&packet, sizeof(packet)); + + return false; } uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -1201,7 +1207,15 @@ void iClass_Authentication(uint8_t *bytes) { uint8_t resp[ICLASS_BUFFER_SIZE]; packet.isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - reply_ng(CMD_HF_ICLASS_AUTH, (packet.isOK)? PM3_SUCCESS : PM3_ESOFT, (uint8_t *)&packet, sizeof(packet)); + if (send_reply) + reply_ng(CMD_HF_ICLASS_AUTH, (packet.isOK)? PM3_SUCCESS : PM3_ESOFT, (uint8_t *)&packet, sizeof(packet)); + + if (dataout) { + memcpy(dataout, card_data, sizeof(card_data)); + memcpy(dataout + (3 * 8), packet.div_key, sizeof(packet.div_key)); + } + + return true; } typedef struct iclass_premac { @@ -1300,7 +1314,7 @@ out: // Tries to read block. // retries 10times. -static bool iclass_readblock(uint8_t blockno, uint8_t *data) { +bool iclass_readblock(uint8_t blockno, uint8_t *data) { uint8_t resp[10]; uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; AddCrc(c + 1, 1); diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 3b4de40f0..fa256c925 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -16,17 +16,20 @@ void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string); void ReaderIClass(uint8_t arg0); void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac); -void iClass_Authentication(uint8_t *mac); -void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain); + void iClass_WriteBlock(uint8_t blockno, uint8_t *data); -void iClass_ReadBlk(uint8_t blockno); void iClass_Dump(uint8_t blockno, uint8_t numblks); void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); void iClass_ReadCheck(uint8_t blockno, uint8_t keytype); - int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); - void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen); + +void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain); +void iClass_Authentication(uint8_t *bytes); +bool iclass_auth(uint8_t *bytes, bool send_reply, uint8_t *dataout); + +void iClass_ReadBlk(uint8_t blockno); +bool iclass_readblock(uint8_t blockno, uint8_t *data); #endif From 5039d69c6bc5c412ba9cc22cae2ebc68d18b52bd Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 14 Jul 2020 23:12:54 +0200 Subject: [PATCH 077/139] rename fct --- client/src/cmdhficlass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 4f51042e9..2aeb9a03f 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1057,7 +1057,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { return PM3_SUCCESS; } -static void iClassEncryptBlkData(uint8_t *blk_data, uint8_t *key) { +static void iclass_encrypt_block_data(uint8_t *blk_data, uint8_t *key) { uint8_t encrypted_data[16]; uint8_t *encrypted = encrypted_data; mbedtls_des3_context ctx; @@ -1118,7 +1118,7 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { if (use_sc) { Encrypt(blk_data, blk_data); } else { - iClassEncryptBlkData(blk_data, key); + iclass_encrypt_block_data(blk_data, key); } PrintAndLogEx(SUCCESS, "encrypted block %s", sprint_hex(blk_data, 8)); return PM3_SUCCESS; From c99ed14c6e2486d7e36de3e86c7a17d7c5050338 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 15 Jul 2020 01:29:44 +0200 Subject: [PATCH 078/139] textual --- client/src/cmdflashmemspiffs.c | 57 ++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/client/src/cmdflashmemspiffs.c b/client/src/cmdflashmemspiffs.c index d7f2b016c..887784428 100644 --- a/client/src/cmdflashmemspiffs.c +++ b/client/src/cmdflashmemspiffs.c @@ -19,49 +19,58 @@ static int CmdHelp(const char *Cmd); static int usage_flashmemspiffs_remove(void) { - PrintAndLogEx(NORMAL, "Remove a file from spiffs filesystem"); - PrintAndLogEx(NORMAL, " Usage: mem spiffs remove "); + PrintAndLogEx(NORMAL, "Remove a file from spiffs filesystem\n"); + PrintAndLogEx(NORMAL, "Usage: mem spiffs remove "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs remove lasttag.bin")); return PM3_SUCCESS; } static int usage_flashmemspiffs_rename(void) { - PrintAndLogEx(NORMAL, "Rename/move a file in spiffs filesystem"); - PrintAndLogEx(NORMAL, " Usage: mem spiffs rename "); + PrintAndLogEx(NORMAL, "Rename/move a file in spiffs filesystem\n"); + PrintAndLogEx(NORMAL, "Usage: mem spiffs rename "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs rename lasttag.bin oldtag.bin")); return PM3_SUCCESS; } static int usage_flashmemspiffs_copy(void) { - PrintAndLogEx(NORMAL, "Copy a file to another (destructively) in spiffs filesystem"); - PrintAndLogEx(NORMAL, " Usage: mem spiffs copy "); + PrintAndLogEx(NORMAL, "Copy a file to another (destructively) in spiffs filesystem\n"); + PrintAndLogEx(NORMAL, "Usage: mem spiffs copy "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs copy lasttag.bin lasttag_cpy.bin")); return PM3_SUCCESS; } static int usage_flashmemspiffs_dump(void) { PrintAndLogEx(NORMAL, "Dumps flash memory on device into a file or in console"); - PrintAndLogEx(NORMAL, "Size is handled by first sending a STAT command against file existence"); - PrintAndLogEx(NORMAL, " Usage: mem spiffs dump o [f [e]] [p]"); - PrintAndLogEx(NORMAL, " o : filename in SPIFFS"); - PrintAndLogEx(NORMAL, " f : file name to save to"); - PrintAndLogEx(NORMAL, " p : print dump in console"); - PrintAndLogEx(NORMAL, " e : also save in EML format (good for tags save and dictonnary files)"); + PrintAndLogEx(NORMAL, "Size is handled by first sending a STAT command against file existence\n"); + PrintAndLogEx(NORMAL, "Usage: mem spiffs dump o [f [e]] [p]"); + PrintAndLogEx(NORMAL, " o - filename in SPIFFS"); + PrintAndLogEx(NORMAL, " f - file name to save to "); + PrintAndLogEx(NORMAL, " p - print dump in console"); + PrintAndLogEx(NORMAL, " e - also save in EML format (good for tags save and dictonnary files)"); PrintAndLogEx(NORMAL, " You must specify at lease option f or option p, both if you wish"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem spiffs dump o hf_colin/lasttag f lasttag e"); - PrintAndLogEx(NORMAL, " mem spiffs dump o hf_colin/lasttag p"); + PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs dump o lasttag.bin f lasttag e")); + PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs dump o lasttag.bin p")); return PM3_SUCCESS; } static int usage_flashmemspiffs_load(void) { PrintAndLogEx(NORMAL, "Uploads binary-wise file into device filesystem"); - PrintAndLogEx(NORMAL, "Usage: mem spiffs load o f "); PrintAndLogEx(NORMAL, "Warning: mem area to be written must have been wiped first"); - PrintAndLogEx(NORMAL, "(this is already taken care when loading dictionaries)"); - PrintAndLogEx(NORMAL, " o : destination filename"); - PrintAndLogEx(NORMAL, " f : local filename"); + PrintAndLogEx(NORMAL, "(this is already taken care when loading dictionaries)\n"); + PrintAndLogEx(NORMAL, "Usage: mem spiffs load o f "); + PrintAndLogEx(NORMAL, " o - destination filename"); + PrintAndLogEx(NORMAL, " f - local filename"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem spiffs load f myfile o myapp.conf"); + PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs load f myfile o myapp.conf")); return PM3_SUCCESS; } @@ -277,12 +286,12 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) { } if ((filename[0] == '\0') && (!print)) { - PrintAndLogEx(FAILED, "No print asked and Local dump Filename missing or invalid"); + PrintAndLogEx(FAILED, "No print asked and local dump filename missing or invalid"); errors = true; } if (destfilename[0] == '\0') { - PrintAndLogEx(FAILED, "SPIFFS Filename missing or invalid"); + PrintAndLogEx(FAILED, "SPIFFS filename missing or invalid"); errors = true; } @@ -320,15 +329,15 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) { } if (filename[0] != '\0') { - saveFile(filename, "", dump, len); + saveFile(filename, ".bin", dump, len); if (eml) { uint8_t eml_len = 16; - if (strstr(filename, "iclass") != NULL) + if (strstr(filename, "class") != NULL) eml_len = 8; else if (strstr(filename, "mfu") != NULL) eml_len = 4; - + saveFileEML(filename, dump, len, eml_len); } } From ce0a2744cb719b0fe5515377c67c4ce3e86514cd Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 15 Jul 2020 01:31:13 +0200 Subject: [PATCH 079/139] hf_iceclass --- armsrc/Standalone/hf_iceclass.c | 323 ++++++++++++++++++++++++-------- 1 file changed, 248 insertions(+), 75 deletions(-) diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 778a9808a..2d5bbb22f 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -20,11 +20,51 @@ #define NUM_CSNS 9 #define MAC_RESPONSES_SIZE (16 * NUM_CSNS) -#define HF_ICLASS_FULLSIM_ORG_BIN "iceclass-orig.bin" -#define HF_ICLASS_FULLSIM_POST_BIN "iceclass-modified.bin" -#define HF_ICLASS_FULLSIM_POST_EML "iceclass-modified-lasttag.bin.eml" -#define HF_ICLASS_ATTACK_BIN "iceclass_mac_attack.bin" +#define HF_ICLASS_FULLSIM_ORIG_BIN "iceclass-orig.bin" +#define HF_ICLASS_FULLSIM_MOD "iceclass-modified" +#define HF_ICLASS_FULLSIM_MOD_BIN HF_ICLASS_FULLSIM_MOD".bin" +#define HF_ICLASS_FULLSIM_MOD_EML HF_ICLASS_FULLSIM_MOD".eml" +#define HF_ICLASS_ATTACK_BIN "iclass_mac_attack.bin" +#define ICE_STATE_NONE 0 +#define ICE_STATE_FULLSIM 1 +#define ICE_STATE_ATTACK 2 +#define ICE_STATE_READER 3 + +typedef struct { + uint8_t app_limit; //[8] + uint8_t otp[2]; //[9-10] + uint8_t block_writelock;//[11] + uint8_t chip_config; //[12] + uint8_t mem_config; //[13] + uint8_t eas; //[14] + uint8_t fuses; //[15] +} picopass_conf_block_t; + +// iclass card descriptors +char * card_types[] = { + "PicoPass 16K / 16", // 000 + "PicoPass 32K with current book 16K / 16", // 001 + "Unknown Card Type!", // 010 + "Unknown Card Type!", // 011 + "PicoPass 2K", // 100 + "Unknown Card Type!", // 101 + "PicoPass 16K / 2", // 110 + "PicoPass 32K with current book 16K / 2", // 111 +}; + +uint8_t card_app2_limit[] = { + 0xff, + 0xff, + 0xff, + 0xff, + 0x1f, + 0xff, + 0xff, + 0xff, +}; + +static uint8_t aa2_key[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static uint8_t legacy_aa1_key[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78}; static uint8_t csns[8 * NUM_CSNS] = { @@ -40,25 +80,198 @@ static uint8_t csns[8 * NUM_CSNS] = { //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0 }; -static void DownloadLogInstructions(uint8_t t) { +static void download_instructions(uint8_t t) { Dbprintf(""); switch (t) { - case ICLASS_SIM_MODE_FULL: { + case ICE_STATE_FULLSIM: { Dbprintf("The emulator memory was saved to flash. Try the following from flash and display it"); - Dbprintf("1. " _YELLOW_("mem spiffs dump o "HF_ICLASS_FULLSIM_POST_BIN" f "HF_ICLASS_FULLSIM_POST_BIN" e")); + Dbprintf("1. " _YELLOW_("mem spiffs dump o "HF_ICLASS_FULLSIM_MOD_BIN" f "HF_ICLASS_FULLSIM_MOD" e")); Dbprintf("2. " _YELLOW_("exit proxmark3 client")); - Dbprintf("3. " _YELLOW_("cat "HF_ICLASS_FULLSIM_POST_EML)); + Dbprintf("3. " _YELLOW_("cat "HF_ICLASS_FULLSIM_MOD_EML)); break; } - case ICLASS_SIM_MODE_READER_ATTACK: { + case ICE_STATE_ATTACK: { Dbprintf("The emulator memory was saved to flash. Try the following from flash and display it"); - Dbprintf("1. " _YELLOW_("mem spiffs dump o "HF_ICLASS_FULLSIM_POST_BIN" f "HF_ICLASS_FULLSIM_POST_BIN" e")); + Dbprintf("1. " _YELLOW_("mem spiffs dump o "HF_ICLASS_ATTACK_BIN" f "HF_ICLASS_ATTACK_BIN)); Dbprintf("2. " _YELLOW_("hf iclass loclass f "HF_ICLASS_ATTACK_BIN)); break; } + case ICE_STATE_READER: { + Dbprintf("The found tags was saved to flash. Try to download from flash and display it"); + Dbprintf("1. " _YELLOW_("mem spiffs tree")); + Dbprintf("2. " _YELLOW_("mem spiffs dump h")); + break; + } } } +static void save_to_flash(uint8_t *data, uint16_t datalen) { + + rdv40_spiffs_lazy_mount(); + + char fn[SPIFFS_OBJ_NAME_LEN]; + sprintf(fn, "iclass-%02X%02X%02X%02X%02X%02X%02X%02X.bin", + data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7] + ); + + if (exists_in_spiffs(fn) == false) { + int res = rdv40_spiffs_write(fn, data, datalen, RDV40_SPIFFS_SAFETY_SAFE); + if (res == SPIFFS_OK) { + Dbprintf("Saved to `" _YELLOW_("%s") "`", fn); + } else { + Dbprintf("error writing `" _YELLOW_("%s") "`", fn); + } + } + + rdv40_spiffs_lazy_unmount(); +} + +static int fullsim_mode(void) { + + rdv40_spiffs_lazy_mount(); + + // Look for a dump file in FLASH MEM. + if (exists_in_spiffs(HF_ICLASS_FULLSIM_ORIG_BIN) == false) { + Dbprintf("error, '" _YELLOW_(HF_ICLASS_FULLSIM_ORIG_BIN) "' file missing"); + return PM3_EIO; + } + + SpinOff(0); + uint8_t *emul = BigBuf_get_EM_addr(); + uint32_t fsize = size_in_spiffs(HF_ICLASS_FULLSIM_ORIG_BIN); + int res = rdv40_spiffs_read_as_filetype(HF_ICLASS_FULLSIM_ORIG_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + Dbprintf("Found `" _YELLOW_(HF_ICLASS_FULLSIM_ORIG_BIN) "` , loaded %u bytes to emulator memory", fsize); + + if ( memcmp(emul + (3 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 0) { + // create diversified key if not in dump. + uint8_t ccnr[12] = {0}; + memcpy(ccnr, emul + (2 * 8), 8); + bool use_elite = false; + + iclass_calc_div_key(emul, legacy_aa1_key, emul + (3 * 8), use_elite); +// Dbhexdump(8, emul + (3 * 8), false); + } + + iclass_simulate(ICLASS_SIM_MODE_FULL, 0 , false, NULL, NULL, NULL); + + LED_B_ON(); + rdv40_spiffs_lazy_mount(); + res = rdv40_spiffs_write(HF_ICLASS_FULLSIM_MOD_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + LED_B_OFF(); + if (res != 0) { + Dbprintf("error writing '"HF_ICLASS_FULLSIM_MOD_BIN"' to flash ( %d )", res); + } + + return PM3_SUCCESS; +} + +static int reader_attack_mode(void) { + + BigBuf_free(); + uint16_t mac_response_len = 0; + uint8_t *mac_responses = BigBuf_malloc(MAC_RESPONSES_SIZE); + + iclass_simulate(ICLASS_SIM_MODE_READER_ATTACK, NUM_CSNS, false, csns, mac_responses, &mac_response_len); + + if (mac_response_len > 0) { + + LED_B_ON(); + rdv40_spiffs_lazy_mount(); + int res = rdv40_spiffs_write(HF_ICLASS_ATTACK_BIN, mac_responses, mac_response_len, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + LED_B_OFF(); + if (res != 0) { + Dbprintf("error writing '"HF_ICLASS_ATTACK_BIN"' to flash ( %d )", res); + } + } + return PM3_SUCCESS; +} + +static int reader_dump_mode(void) { + + BigBuf_free(); + uint8_t *card_data = BigBuf_malloc(0xFF * 8); + memset(card_data, 0xFF, sizeof(card_data)); + + struct p { + uint8_t key[8]; + bool use_raw; + bool use_elite; + bool use_credit_key; + } PACKED; + + for (;;) { + + if (BUTTON_PRESS()) { + DbpString("button pressed"); + break; + } + + // AA1 + struct p payload = { + .use_raw = false, + .use_elite = false, + .use_credit_key = false, + }; + memcpy(payload.key, legacy_aa1_key, sizeof(payload.key)); + + bool isOK = iclass_auth((uint8_t*)&payload, false, card_data); + if (isOK == false) { + continue; + } + + picopass_conf_block_t *conf = (picopass_conf_block_t*)(card_data + 8); + + // get 3 config bits + uint8_t type = (conf->chip_config & 0x10) >> 2; + type |= (conf->mem_config & 0x80) >> 6; + type |= (conf->mem_config & 0x20) >> 5; + + uint8_t app1_limit = conf->app_limit - 5; // minus header blocks + uint8_t app2_limit = card_app2_limit[type]; + + + uint16_t dumped = 0; + uint8_t block; + for (block = 5; block < app1_limit; block++) { + isOK = iclass_readblock(block, card_data + (8 * block)); + if (isOK) { + dumped++; + } + } + + // AA2 + payload.use_credit_key = true; + memcpy(payload.key, aa2_key, sizeof(payload.key)); + + isOK = iclass_auth((uint8_t*)&payload, false, card_data); + if (isOK) { + for (; block < app2_limit; block++) { + isOK = iclass_readblock(block, card_data + (8 * block)); + if (isOK) { + dumped++; + } + } + } + + Dbprintf("Found %s", card_types[type]); +/* + Dbprintf("APP1 Blocks: %d", app1_limit); + Dbprintf("APP2 Blocks: %d", app2_limit - app1_limit - 5); // minus app1 and header + Dbprintf("Got %d blocks (saving %u, %u bytes )", dumped, dumped + 5, ((dumped+5)*8) ); +*/ + if (5 + dumped > app1_limit) { + save_to_flash(card_data, (5 + dumped) * 8 ); + } + } + + Dbprintf("exit read & dump mode"); + return PM3_SUCCESS; +} + void ModInfo(void) { DbpString(" HF iCLASS mode - aka iceCLASS (iceman)"); } @@ -71,12 +284,10 @@ void RunMod(void) { StandAloneMode(); Dbprintf(_YELLOW_("HF iCLASS mode a.k.a iceCLASS started")); - uint8_t simtype = ICLASS_SIM_MODE_FULL; + uint8_t mode = ICE_STATE_READER; for (;;) { WDT_HIT(); - - // exit from RunMod, send a usbcommand. if (data_available()) break; // Was our button held down or pressed? @@ -85,78 +296,40 @@ void RunMod(void) { break; } - switch (simtype) { - case ICLASS_SIM_MODE_FULL: { + int res; + switch (mode) { + case ICE_STATE_FULLSIM: { Dbprintf("enter full simulation mode"); + res = fullsim_mode(); + if (res == PM3_SUCCESS) + download_instructions(mode); - rdv40_spiffs_lazy_mount(); - // Look for a dump file in FLASH MEM. - if (exists_in_spiffs(HF_ICLASS_FULLSIM_ORG_BIN) == false) { - Dbprintf("error, '" _YELLOW_(HF_ICLASS_FULLSIM_ORG_BIN) "' file missing"); - Dbprintf("changing to reader attack mode instead"); - simtype = ICLASS_SIM_MODE_READER_ATTACK; - break; - } - - SpinOff(0); - uint8_t *emul = BigBuf_get_EM_addr(); - uint32_t fsize = size_in_spiffs(HF_ICLASS_FULLSIM_ORG_BIN); - int res = rdv40_spiffs_read_as_filetype(HF_ICLASS_FULLSIM_ORG_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); - rdv40_spiffs_lazy_unmount(); - Dbprintf("Found `" _YELLOW_(HF_ICLASS_FULLSIM_ORG_BIN) "` , loaded %u bytes to emulator memory", fsize); - - if ( memcmp(emul + (3 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 0) { - // create diversified key if not in dump. - uint8_t ccnr[12] = {0}; - memcpy(ccnr, emul + (2 * 8), 8); - bool use_elite = false; - - iclass_calc_div_key(emul, legacy_aa1_key, emul + (3 * 8), use_elite); - - Dbhexdump(8, emul + (3 * 8), false); - } - - iclass_simulate(ICLASS_SIM_MODE_FULL, 0 , false, NULL, NULL, NULL); - - LED_B_ON(); - rdv40_spiffs_lazy_mount(); - res = rdv40_spiffs_write(HF_ICLASS_FULLSIM_POST_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); - rdv40_spiffs_lazy_unmount(); - LED_B_OFF(); - if (res != 0) { - Dbprintf("error writing '"HF_ICLASS_FULLSIM_POST_BIN"' to flash ( %d )", res); - } - DownloadLogInstructions(simtype); - simtype = 0; + switch_off(); break; } - case ICLASS_SIM_MODE_READER_ATTACK: { - + case ICE_STATE_ATTACK: { Dbprintf("enter reader attack mode"); - uint16_t mac_response_len = 0; - uint8_t mac_responses[MAC_RESPONSES_SIZE] = {0}; + res = reader_attack_mode(); + if (res == PM3_SUCCESS) + download_instructions(mode); - iclass_simulate(ICLASS_SIM_MODE_READER_ATTACK, NUM_CSNS, false, csns, mac_responses, &mac_response_len); - - if (mac_response_len > 0) { - - LED_B_ON(); - rdv40_spiffs_lazy_mount(); - int res = rdv40_spiffs_write(HF_ICLASS_ATTACK_BIN, mac_responses, mac_response_len, RDV40_SPIFFS_SAFETY_SAFE); - rdv40_spiffs_lazy_unmount(); - LED_B_OFF(); - if (res != 0) { - Dbprintf("error writing '"HF_ICLASS_ATTACK_BIN"' to flash ( %d )", res); - } - } - DownloadLogInstructions(simtype); - simtype = 0; + mode = ICE_STATE_NONE; + switch_off(); break; } - } // switch - } // for loop + case ICE_STATE_READER: { + Dbprintf("enter read & dump mode"); + res = reader_dump_mode(); + if (res == PM3_SUCCESS) + download_instructions(mode); + mode = ICE_STATE_NONE; + switch_off(); + break; + } + } + } LEDsoff(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); From 8d5315b6afeeb20141ace10072d6e87c358aa33a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 15 Jul 2020 11:34:14 +0200 Subject: [PATCH 080/139] fixes to mode --- armsrc/Standalone/hf_iceclass.c | 132 +++++++++++++++++++++++++------- include/pm3_cmd.h | 1 + 2 files changed, 107 insertions(+), 26 deletions(-) diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 2d5bbb22f..19aa9626d 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -26,10 +26,15 @@ #define HF_ICLASS_FULLSIM_MOD_EML HF_ICLASS_FULLSIM_MOD".eml" #define HF_ICLASS_ATTACK_BIN "iclass_mac_attack.bin" -#define ICE_STATE_NONE 0 -#define ICE_STATE_FULLSIM 1 -#define ICE_STATE_ATTACK 2 -#define ICE_STATE_READER 3 +#define HF_ICLASS_CC_A "iceclass_cc_a.bin" +#define HF_ICLASS_CC_B "iceclass_cc_b.bin" +char* cc_files[] = { HF_ICLASS_CC_A, HF_ICLASS_CC_B }; + +#define ICE_STATE_NONE 0 +#define ICE_STATE_FULLSIM 1 +#define ICE_STATE_ATTACK 2 +#define ICE_STATE_READER 3 +#define ICE_STATE_CONFIGCARD 4 typedef struct { uint8_t app_limit; //[8] @@ -130,28 +135,23 @@ static void save_to_flash(uint8_t *data, uint16_t datalen) { static int fullsim_mode(void) { rdv40_spiffs_lazy_mount(); - - // Look for a dump file in FLASH MEM. - if (exists_in_spiffs(HF_ICLASS_FULLSIM_ORIG_BIN) == false) { - Dbprintf("error, '" _YELLOW_(HF_ICLASS_FULLSIM_ORIG_BIN) "' file missing"); - return PM3_EIO; - } SpinOff(0); uint8_t *emul = BigBuf_get_EM_addr(); uint32_t fsize = size_in_spiffs(HF_ICLASS_FULLSIM_ORIG_BIN); int res = rdv40_spiffs_read_as_filetype(HF_ICLASS_FULLSIM_ORIG_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); rdv40_spiffs_lazy_unmount(); - Dbprintf("Found `" _YELLOW_(HF_ICLASS_FULLSIM_ORIG_BIN) "` , loaded %u bytes to emulator memory", fsize); + if (res == SPIFFS_OK) { + Dbprintf("loaded '" _YELLOW_(HF_ICLASS_FULLSIM_ORIG_BIN) "' (%u bytes) to emulator memory", fsize); + } + // create diversified key if not in dump. if ( memcmp(emul + (3 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 0) { - // create diversified key if not in dump. uint8_t ccnr[12] = {0}; memcpy(ccnr, emul + (2 * 8), 8); bool use_elite = false; - + iclass_calc_div_key(emul, legacy_aa1_key, emul + (3 * 8), use_elite); -// Dbhexdump(8, emul + (3 * 8), false); } iclass_simulate(ICLASS_SIM_MODE_FULL, 0 , false, NULL, NULL, NULL); @@ -161,7 +161,7 @@ static int fullsim_mode(void) { res = rdv40_spiffs_write(HF_ICLASS_FULLSIM_MOD_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); rdv40_spiffs_lazy_unmount(); LED_B_OFF(); - if (res != 0) { + if (res != SPIFFS_OK) { Dbprintf("error writing '"HF_ICLASS_FULLSIM_MOD_BIN"' to flash ( %d )", res); } @@ -177,13 +177,36 @@ static int reader_attack_mode(void) { iclass_simulate(ICLASS_SIM_MODE_READER_ATTACK, NUM_CSNS, false, csns, mac_responses, &mac_response_len); if (mac_response_len > 0) { + + bool success = (mac_response_len == MAC_RESPONSES_SIZE); + uint8_t num_mac = (mac_response_len >> 4); + Dbprintf("%u out of %d MAC obtained [%s]", num_mac, NUM_CSNS, (success) ? _GREEN_("OK") : _RED_("FAIL")); + + size_t dumplen = NUM_CSNS * 24; + + uint8_t *dump = BigBuf_malloc(dumplen); + if (dump == false) { + Dbprintf("failed to allocate memory"); + return PM3_EMALLOC; + } + + memset(dump, 0, dumplen);//<-- Need zeroes for the EPURSE - field + + for (uint8_t i = 0 ; i < NUM_CSNS ; i++) { + //copy CSN + memcpy(dump + (i * 24), csns + (i * 8), 8); + //copy epurse + memcpy(dump + (i * 24) + 8, mac_responses + (i * 16), 8); + // NR_MAC (eight bytes from the response) ( 8b csn + 8b epurse == 16) + memcpy(dump + (i * 24) + 16, mac_responses + (i * 16) + 8, 8); + } LED_B_ON(); rdv40_spiffs_lazy_mount(); - int res = rdv40_spiffs_write(HF_ICLASS_ATTACK_BIN, mac_responses, mac_response_len, RDV40_SPIFFS_SAFETY_SAFE); + int res = rdv40_spiffs_write(HF_ICLASS_ATTACK_BIN, dump, dumplen, RDV40_SPIFFS_SAFETY_SAFE); rdv40_spiffs_lazy_unmount(); LED_B_OFF(); - if (res != 0) { + if (res != SPIFFS_OK) { Dbprintf("error writing '"HF_ICLASS_ATTACK_BIN"' to flash ( %d )", res); } } @@ -272,6 +295,29 @@ static int reader_dump_mode(void) { return PM3_SUCCESS; } +static int config_sim_mode(void) { + + uint8_t *emul = BigBuf_get_EM_addr(); + + for (uint8_t i = 0; i < 2; i++) { + SpinOff(0); + uint32_t fsize = size_in_spiffs(cc_files[i]); + + rdv40_spiffs_lazy_mount(); + int res = rdv40_spiffs_read_as_filetype(cc_files[i], emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + + if (res == SPIFFS_OK) { + Dbprintf("loaded '" _YELLOW_("%s") "' (%u bytes) to emulator memory", cc_files[i], fsize); + } + + iclass_simulate(ICLASS_SIM_MODE_FULL, 0 , false, NULL, NULL, NULL); + } + + rdv40_spiffs_lazy_unmount(); + return PM3_SUCCESS; +} + void ModInfo(void) { DbpString(" HF iCLASS mode - aka iceCLASS (iceman)"); } @@ -284,28 +330,45 @@ void RunMod(void) { StandAloneMode(); Dbprintf(_YELLOW_("HF iCLASS mode a.k.a iceCLASS started")); - uint8_t mode = ICE_STATE_READER; + uint8_t mode = ICE_STATE_ATTACK; for (;;) { + WDT_HIT(); + + if (mode == ICE_STATE_NONE) break; if (data_available()) break; +/* // Was our button held down or pressed? int button_pressed = BUTTON_HELD(1000); if (button_pressed != BUTTON_NO_CLICK) { break; } + */ int res; switch (mode) { case ICE_STATE_FULLSIM: { Dbprintf("enter full simulation mode"); - res = fullsim_mode(); - if (res == PM3_SUCCESS) - download_instructions(mode); + + // Look for iCLASS dump file + rdv40_spiffs_lazy_mount(); + if (exists_in_spiffs(HF_ICLASS_FULLSIM_ORIG_BIN) == false) { + Dbprintf("error, '" _YELLOW_(HF_ICLASS_FULLSIM_ORIG_BIN) "' file missing"); + mode = ICE_STATE_NONE; + } + rdv40_spiffs_lazy_unmount(); - switch_off(); + if (mode == ICE_STATE_FULLSIM) { + res = fullsim_mode(); + if (res == PM3_SUCCESS) { + download_instructions(mode); + } + } + // the button press to exit sim, is captured in main loop here + mode = ICE_STATE_NONE; break; } case ICE_STATE_ATTACK: { @@ -315,7 +378,6 @@ void RunMod(void) { download_instructions(mode); mode = ICE_STATE_NONE; - switch_off(); break; } case ICE_STATE_READER: { @@ -325,12 +387,30 @@ void RunMod(void) { download_instructions(mode); mode = ICE_STATE_NONE; - switch_off(); + break; + } + case ICE_STATE_CONFIGCARD: { + Dbprintf("enter config card simulation mode"); + + // Look for config cards + rdv40_spiffs_lazy_mount(); + for (uint8_t i =0; i < 2; i++) { + if (exists_in_spiffs(cc_files[i]) == false) { + Dbprintf("error, '" _YELLOW_("%s") "' file missing", cc_files[i]); + mode = ICE_STATE_NONE; + } + } + rdv40_spiffs_lazy_unmount(); + + if (mode == ICE_STATE_CONFIGCARD) + config_sim_mode(); + + mode = ICE_STATE_NONE; break; } } } - LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + switch_off(); + Dbprintf("-=[ exit iceCLASS ]=-"); } diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index b85d996d6..3568bd50a 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -601,6 +601,7 @@ typedef struct { #define ICLASS_SIM_MODE_FULL 3 #define ICLASS_SIM_MODE_READER_ATTACK_KEYROLL 4 #define ICLASS_SIM_MODE_EXIT_AFTER_MAC 5 // note: device internal only +#define ICLASS_SIM_MODE_CONFIG_CARD 6 #define MODE_SIM_CSN 0 #define MODE_EXIT_AFTER_MAC 1 From d9571d8df7b28c8c98f924b51d8c1172c45e8d89 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 15 Jul 2020 11:35:03 +0200 Subject: [PATCH 081/139] loclass, print helptxt --- client/src/cmdhficlass.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 2aeb9a03f..80f6dfab5 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2018,9 +2018,6 @@ static int CmdHFiClass_loclass(const char *Cmd) { char fileName[FILE_PATH_SIZE] = {0}; if (param_getstr(Cmd, 1, fileName, sizeof(fileName)) > 0) { return bruteforceFileNoKeys(fileName); - } else { - PrintAndLogEx(WARNING, "You must specify a filename"); - return PM3_EFILE; } } else if (opt == 't') { char opt2 = tolower(param_getchar(Cmd, 1)); @@ -2035,7 +2032,8 @@ static int CmdHFiClass_loclass(const char *Cmd) { return PM3_ESOFT; } - return PM3_SUCCESS; + + return usage_hf_iclass_loclass(); } void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) { From a59aa7a570056129867da5575dfa831c933d6ad4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 15 Jul 2020 11:35:27 +0200 Subject: [PATCH 082/139] rename fct --- armsrc/iclass.c | 18 +++++++++++------- armsrc/iclass.h | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index f232c35ed..d8892a74c 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -166,14 +166,14 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ if (sim_type == ICLASS_SIM_MODE_CSN) { // Use the CSN from commandline memcpy(emulator, datain, 8); - doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); + do_iclass_simulation(ICLASS_SIM_MODE_CSN, NULL); } else if (sim_type == ICLASS_SIM_MODE_CSN_DEFAULT) { //Default CSN uint8_t csn[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0 }; // Use the CSN from commandline memcpy(emulator, csn, 8); - doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); + do_iclass_simulation(ICLASS_SIM_MODE_CSN, NULL); } else if (sim_type == ICLASS_SIM_MODE_READER_ATTACK) { @@ -187,7 +187,7 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ memcpy(emulator, datain + (i * 8), 8); - if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { + if (do_iclass_simulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { if (dataoutlen) *dataoutlen = i * EPURSE_MAC_SIZE; @@ -207,7 +207,11 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ } else if (sim_type == ICLASS_SIM_MODE_FULL) { //This is 'full sim' mode, where we use the emulator storage for data. //ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command - doIClassSimulation(ICLASS_SIM_MODE_FULL, NULL); + do_iclass_simulation(ICLASS_SIM_MODE_FULL, NULL); + } else if (sim_type == ICLASS_SIM_MODE_CONFIG_CARD) { + // config card + do_iclass_simulation(ICLASS_SIM_MODE_FULL, NULL); + // swap bin } else if (sim_type == ICLASS_SIM_MODE_READER_ATTACK_KEYROLL) { @@ -229,7 +233,7 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ memcpy(emulator, datain + (i * 8), 8); // keyroll 1 - if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { + if (do_iclass_simulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { if (dataoutlen) *dataoutlen = i * EPURSE_MAC_SIZE * 2; @@ -242,7 +246,7 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ } // keyroll 2 - if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + (i + num_csns) * EPURSE_MAC_SIZE)) { + if (do_iclass_simulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses + (i + num_csns) * EPURSE_MAC_SIZE)) { if (dataoutlen) *dataoutlen = i * EPURSE_MAC_SIZE * 2; @@ -281,7 +285,7 @@ out: * @param csn - csn to use * @param breakAfterMacReceived if true, returns after reader MAC has been received. */ -int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { +int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { // free eventually allocated BigBuf memory BigBuf_free_keep_EM(); diff --git a/armsrc/iclass.h b/armsrc/iclass.h index fa256c925..cc93f771c 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -22,7 +22,7 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks); void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); void iClass_ReadCheck(uint8_t blockno, uint8_t keytype); -int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); +int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf); void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen); From 85be784d26827ed467abb54e29980133de5ea654 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 15 Jul 2020 11:55:21 +0200 Subject: [PATCH 083/139] ev3 detection enabled --- client/src/cmdhfmfdes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e7a8e3746..0e7e0f678 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -382,7 +382,7 @@ static char *getVersionStr(uint8_t major, uint8_t minor) { sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor); else if (major == 0x12 && minor == 0x00) sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor); - else if (major == 0x13 && minor == 0x00) + else if (major == 0x33 && minor == 0x00) sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor); else if (major == 0x30 && minor == 0x00) sprintf(retStr, "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor); @@ -644,8 +644,8 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) { return DESFIRE_EV1; if (major == 0x12 && minor == 0x00) return DESFIRE_EV2; -// if (major == 0x13 && minor == 0x00) -// return DESFIRE_EV3; + if (major == 0x33 && minor == 0x00) + return DESFIRE_EV3; if (major == 0x30 && minor == 0x00) return DESFIRE_LIGHT; if (major == 0x11 && minor == 0x00) From 3354f0d9d36ef171f5a3e3c43b9ddcf6f1844ea2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 15 Jul 2020 15:16:35 +0200 Subject: [PATCH 084/139] unified static dma buffer as bigbuf_malloc, less pressure on stack size --- armsrc/BigBuf.c | 64 +++++++++++++--- armsrc/BigBuf.h | 14 +++- armsrc/iso14443a.c | 23 +++--- armsrc/iso14443b.c | 185 ++++++++++++++++++--------------------------- armsrc/iso15693.c | 83 ++++++++++---------- 5 files changed, 194 insertions(+), 175 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 7cb440d82..338206d6e 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -36,6 +36,33 @@ static uint32_t s_bigbuf_hi = 0; // pointer to the emulator memory. static uint8_t *emulator_memory = NULL; +//============================================================================= +// The ToSend buffer. +// A buffer where we can queue things up to be sent through the FPGA, for +// any purpose (fake tag, as reader, whatever). We go MSB first, since that +// is the order in which they go out on the wire. +//============================================================================= +static tosend_t toSend = { + .max = -1, + .bit = 8, + .buf = NULL +}; +//============================================================================= +// The dmaBuf 16bit buffer. +// A buffer where we recive IQ samples sent from the FPGA, for demodulating +//============================================================================= +static dmabuf16_t dma_16 = { + .size = DMA_BUFFER_SIZE, + .buf = NULL +}; +// dmaBuf 8bit buffer +static dmabuf8_t dma_8 = { + .size = DMA_BUFFER_SIZE, + .buf = NULL +}; + + + // trace related variables static uint32_t trace_len = 0; static bool tracing = true; @@ -106,6 +133,9 @@ void BigBuf_free(void) { s_bigbuf_hi = s_bigbuf_size; emulator_memory = NULL; // shouldn't this empty BigBuf also? + toSend.buf = NULL; + dma_16.buf = NULL; + dma_8.buf = NULL; } // free allocated chunks EXCEPT the emulator memory @@ -114,6 +144,10 @@ void BigBuf_free_keep_EM(void) { s_bigbuf_hi = emulator_memory - (uint8_t *)BigBuf; else s_bigbuf_hi = s_bigbuf_size; + + toSend.buf = NULL; + dma_16.buf = NULL; + dma_8.buf = NULL; } void BigBuf_print_status(void) { @@ -123,6 +157,10 @@ void BigBuf_print_status(void) { DbpString(_CYAN_("Tracing")); Dbprintf(" tracing ................%d", tracing); Dbprintf(" traceLen ...............%d", trace_len); + + Dbprintf(" dma8 memory.............%d", dma_8.buf - BigBuf_get_addr()); + Dbprintf(" dma16 memory............%d", (uint8_t*)dma_16.buf - BigBuf_get_addr()); + Dbprintf(" toSend memory...........%d", toSend.buf - BigBuf_get_addr() ); } // return the maximum trace length (i.e. the unallocated size of BigBuf) @@ -228,17 +266,6 @@ uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length) { } -//============================================================================= -// The ToSend buffer. -// A buffer where we can queue things up to be sent through the FPGA, for -// any purpose (fake tag, as reader, whatever). We go MSB first, since that -// is the order in which they go out on the wire. -//============================================================================= -static tosend_t toSend = { - .max = -1, - .bit = 8, - .buf = NULL -}; // get the address of the ToSend buffer. Allocate part of Bigbuf for it, if not yet done tosend_t *get_tosend(void) { @@ -270,3 +297,18 @@ void tosend_stuffbit(int b) { toSend.bit = 0; } } + +dmabuf16_t *get_dma16(void) { + if (dma_16.buf == NULL) + dma_16.buf = (uint16_t*)BigBuf_malloc(DMA_BUFFER_SIZE); + + return &dma_16; +} + +dmabuf8_t *get_dma8(void) { + if (dma_8.buf == NULL) + dma_8.buf = BigBuf_malloc(DMA_BUFFER_SIZE); + + return &dma_8; +} + diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 33c454226..2f381f36b 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -19,7 +19,7 @@ #define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC #define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these #define CARD_MEMORY_SIZE 4096 -#define DMA_BUFFER_SIZE 128 +#define DMA_BUFFER_SIZE 256 // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits #define TOSEND_BUFFER_SIZE (9 * MAX_FRAME_SIZE + 1 + 1 + 2) @@ -56,4 +56,16 @@ tosend_t *get_tosend(void); void tosend_reset(void); void tosend_stuffbit(int b); +typedef struct { + uint16_t size; + uint8_t *buf; +} dmabuf8_t; + +typedef struct { + uint16_t size; + uint16_t *buf; +} dmabuf16_t; + +dmabuf8_t *get_dma8(void); +dmabuf16_t *get_dma16(void); #endif /* __BIGBUF_H */ diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index bac3008f9..53d1f6814 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -585,10 +585,6 @@ void RAMFUNC SniffIso14443a(uint8_t param) { uint8_t *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE); - // The DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - uint8_t *data = dmaBuf; - uint8_t previous_data = 0; int maxDataLen = 0, dataLen; bool TagIsActive = false; @@ -602,8 +598,12 @@ void RAMFUNC SniffIso14443a(uint8_t param) { DbpString("Starting to sniff"); + // The DMA buffer, used to stream samples from the FPGA + dmabuf8_t *dma = get_dma8(); + uint8_t *data = dma->buf; + // Setup and start DMA. - if (!FpgaSetupSscDma((uint8_t *) dmaBuf, DMA_BUFFER_SIZE)) { + if (!FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE)) { if (DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); return; } @@ -621,7 +621,7 @@ void RAMFUNC SniffIso14443a(uint8_t param) { WDT_HIT(); LED_A_ON(); - int register readBufDataP = data - dmaBuf; + int register readBufDataP = data - dma->buf; int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; if (readBufDataP <= dmaBufDataP) dataLen = dmaBufDataP - readBufDataP; @@ -640,13 +640,13 @@ void RAMFUNC SniffIso14443a(uint8_t param) { // primary buffer was stopped( <-- we lost data! if (!AT91C_BASE_PDC_SSC->PDC_RCR) { - AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) dma->buf; AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE; Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary } // secondary buffer sets as primary, secondary buffer was stopped if (!AT91C_BASE_PDC_SSC->PDC_RNCR) { - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } @@ -710,16 +710,15 @@ void RAMFUNC SniffIso14443a(uint8_t param) { previous_data = *data; rx_samples++; data++; - if (data == dmaBuf + DMA_BUFFER_SIZE) { - data = dmaBuf; + if (data == dma->buf + DMA_BUFFER_SIZE) { + data = dma->buf; } } // end main loop FpgaDisableTracing(); if (DBGLEVEL >= DBG_ERROR) { - Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len); - Dbprintf("traceLen=" _YELLOW_("%d")", Uart.output[0]="_YELLOW_("%08x"), BigBuf_get_traceLen(), (uint32_t)Uart.output[0]); + Dbprintf("trace len = " _YELLOW_("%d"), BigBuf_get_traceLen()); } switch_off(); } diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index d9d08a966..e26ebb017 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -26,11 +26,8 @@ #include "ticks.h" -#ifndef ISO14443B_DMA_BUFFER_SIZE -# define ISO14443B_DMA_BUFFER_SIZE 128 -#endif #ifndef RECEIVE_MASK -# define RECEIVE_MASK (ISO14443B_DMA_BUFFER_SIZE-1) +# define RECEIVE_MASK (DMA_BUFFER_SIZE - 1) #endif #define RECEIVE_SAMPLES_TIMEOUT 64 @@ -480,13 +477,7 @@ static void TransmitFor14443b_AsTag(uint8_t *response, uint16_t len) { // Put byte into tx holding register as soon as it is ready if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = response[++i]; - } - - // Prevent rx holding register from overflowing - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint32_t b = AT91C_BASE_SSC->SSC_RHR; - (void)b; + AT91C_BASE_SSC->SSC_THR = response[i++]; } } } @@ -702,40 +693,17 @@ void SimulateIso14443bTag(uint32_t pupi) { * false if we are still waiting for some more * */ -static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { - int v = 0, myI = ABS(ci), myQ = ABS(cq); - -// 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(void) { \ - if (Demod.sumI > 0) { \ - v = ci; \ - } else { \ - v = -ci; \ - } \ - if (Demod.sumQ > 0) { \ - v += cq; \ - } else { \ - v -= cq; \ - } \ - } +static RAMFUNC int Handle14443bTagSamplesDemod(uint16_t amplitude) { #define SUBCARRIER_DETECT_THRESHOLD 8 -//note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow -#define CHECK_FOR_SUBCARRIER(void) { v = MAX(myI, myQ) + (MIN(myI, myQ) >> 1); } - switch (Demod.state) { case DEMOD_UNSYNCD: - CHECK_FOR_SUBCARRIER(); - - // subcarrier detected - - if (v > SUBCARRIER_DETECT_THRESHOLD) { + if (amplitude > SUBCARRIER_DETECT_THRESHOLD) { Demod.state = DEMOD_PHASE_REF_TRAINING; - Demod.sumI = ci; - Demod.sumQ = cq; + Demod.sumI = amplitude; + Demod.sumQ = amplitude; Demod.posCount = 1; } break; @@ -743,13 +711,11 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { case DEMOD_PHASE_REF_TRAINING: if (Demod.posCount < 8) { - CHECK_FOR_SUBCARRIER(); - - if (v > SUBCARRIER_DETECT_THRESHOLD) { + if (amplitude > 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.sumI += amplitude; + Demod.sumQ += amplitude; Demod.posCount++; } else { // subcarrier lost @@ -762,9 +728,7 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: - MAKE_SOFT_DECISION(); - - if (v < 0) { // logic '0' detected + if (amplitude == 0) { // logic '0' detected Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; Demod.posCount = 0; // start of SOF sequence } else { @@ -779,9 +743,7 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { case DEMOD_GOT_FALLING_EDGE_OF_SOF: Demod.posCount++; - MAKE_SOFT_DECISION(); - - if (v > 0) { + if (amplitude > 0) { // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges if (Demod.posCount < 9 * 2) { Demod.state = DEMOD_UNSYNCD; @@ -804,9 +766,7 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { case DEMOD_AWAITING_START_BIT: Demod.posCount++; - MAKE_SOFT_DECISION(); - - if (v > 0) { + if (amplitude > 0) { if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs LED_C_OFF(); if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass @@ -818,7 +778,7 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { } else { // start bit detected Demod.bitCount = 0; Demod.posCount = 1; // this was the first half - Demod.thisBit = v; + Demod.thisBit = amplitude; Demod.shiftReg = 0; Demod.state = DEMOD_RECEIVING_DATA; } @@ -826,15 +786,13 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { case DEMOD_RECEIVING_DATA: - MAKE_SOFT_DECISION(); - if (Demod.posCount == 0) { // first half of bit - Demod.thisBit = v; + Demod.thisBit = amplitude; Demod.posCount = 1; } else { // second half of bit - Demod.thisBit += v; + Demod.thisBit += amplitude; Demod.shiftReg >>= 1; // OR in a logic '1' @@ -882,64 +840,66 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { * Demodulate the samples we received from the tag, also log to tracebuffer */ static int GetTagSamplesFor14443bDemod(int timeout) { - int ret = 0; - int maxBehindBy = 0; - int lastRxCounter, samples = 0; - int8_t ci, cq; - uint32_t time_0 = 0, time_stop = 0; + + int samples = 0, ret = 0; 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 - uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); // Set up the demodulator for tag -> reader responses. - Demod14bInit(receivedResponse); + Demod14bInit(BigBuf_malloc(MAX_FRAME_SIZE)); // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) // Setup and start DMA. FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - if (FpgaSetupSscDma((uint8_t *) dmaBuf, ISO14443B_DMA_BUFFER_SIZE) == false) { + + // The DMA buffer, used to stream samples from the FPGA + dmabuf16_t *dma = get_dma16(); + if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) { if (DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); return -1; } - uint16_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 | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); +// uint32_t dma_start_time; + uint16_t *upTo = dma->buf; + for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1); - if (behindBy > maxBehindBy) { - maxBehindBy = behindBy; - } + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); - if (behindBy < 1) continue; + if (behindBy == 0) continue; - ci = *upTo >> 8; - cq = *upTo; - upTo++; - lastRxCounter--; - if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; - } - - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers - } samples++; + /* + if (samples == 1) { + // DMA has transferred the very first data + dma_start_time = GetCountSspClk() & 0xfffffff0; + } + */ - if (Handle14443bTagSamplesDemod(ci, cq)) { + volatile uint16_t tagdata = *upTo++; + + if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dma->buf; // start reading the circular buffer from the beginning + if (behindBy > (9 * DMA_BUFFER_SIZE / 10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + ret = -1; + break; + } + } + + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers + } + + if (Handle14443bTagSamplesDemod(tagdata)) { ret = Demod.len; break; } @@ -958,7 +918,7 @@ static int GetTagSamplesFor14443bDemod(int timeout) { } if (Demod.len > 0) { - LogTrace(Demod.output, Demod.len, time_0, time_stop, NULL, false); + LogTrace(Demod.output, Demod.len, 0, 0, NULL, false); } return ret; @@ -976,12 +936,14 @@ static void TransmitFor14443b_AsReader(void) { for (int c = 0; c < ts->max; c++) { uint8_t data = ts->buf[c]; + for (int i = 0; i < 8; i++) { uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; AT91C_BASE_SSC->SSC_THR = send_word; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; AT91C_BASE_SSC->SSC_THR = send_word; @@ -1388,7 +1350,7 @@ static void iso1444b_setup_sniff(void) { 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); + Dbprintf("[+] DMA: %i bytes", DMA_BUFFER_SIZE); } // connect Demodulated Signal to ADC: @@ -1432,12 +1394,7 @@ void RAMFUNC SniffIso14443b(void) { bool TagIsActive = false; bool ReaderIsActive = false; - iso1444b_setup_sniff(); - - // The DMA buffer, used to stream samples from the FPGA - uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); - uint16_t *upTo = dmaBuf; - int lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + int lastRxCounter = DMA_BUFFER_SIZE; int8_t ci, cq; int maxBehindBy = 0; @@ -1445,8 +1402,14 @@ void RAMFUNC SniffIso14443b(void) { // information in the trace buffer. int samples = 0; + iso1444b_setup_sniff(); + + // The DMA buffer, used to stream samples from the FPGA + dmabuf16_t *dma = get_dma16(); + uint16_t *upTo = dma->buf; + // Setup and start DMA. - if (!FpgaSetupSscDma((uint8_t *) dmaBuf, ISO14443B_DMA_BUFFER_SIZE)) { + if (!FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE)) { if (DBGLEVEL > 1) Dbprintf("[!] FpgaSetupSscDma failed. Exiting"); BigBuf_free(); return; @@ -1458,29 +1421,31 @@ void RAMFUNC SniffIso14443b(void) { // loop and listen for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE - 1); + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE - 1); if (behindBy > maxBehindBy) { maxBehindBy = behindBy; } - if (behindBy < 1) continue; + if (behindBy == 0) continue; ci = *upTo >> 8; cq = *upTo; + uint16_t tagdata = *upTo; + upTo++; lastRxCounter--; - if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning again - lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; - if (behindBy > (9 * ISO14443B_DMA_BUFFER_SIZE / 10)) { + if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dma->buf; // start reading the circular buffer from the beginning again + lastRxCounter += DMA_BUFFER_SIZE; + if (behindBy > (9 * DMA_BUFFER_SIZE / 10)) { Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); break; } } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers WDT_HIT(); if (BUTTON_PRESS()) { @@ -1522,7 +1487,7 @@ void RAMFUNC SniffIso14443b(void) { // is this | 0x01 the error? & 0xfe in https://github.com/Proxmark/proxmark3/issues/103 // LSB is a fpga signal bit. - if (Handle14443bTagSamplesDemod(ci/2, cq/2) >= 0) { + if (Handle14443bTagSamplesDemod(tagdata) >= 0) { time_stop = GetCountSspClk() - time_0; LogTrace(Demod.output, Demod.len, time_start, time_stop, NULL, false); Uart14bReset(); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index ff59d260a..36530f72b 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -91,7 +91,7 @@ /////////////////////////////////////////////////////////////////////// // buffers -#define ISO15693_DMA_BUFFER_SIZE 256 // must be a power of 2 +//#define ISO15693_DMA_BUFFER_SIZE 256 // must be a power of 2 #define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet #define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet @@ -305,7 +305,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint8_t bits_to_shift = 0x00; uint8_t bits_to_send = 0x00; for (size_t c = 0; c < len; c++) { - for (int i = (c==0?4:7); i >= 0; i--) { + for (int i = (c == 0 ? 4 : 7); i >= 0; i--) { uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; for (int j = 0; j < (slow ? 4 : 1); ) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { @@ -406,7 +406,7 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De DecodeTag->threshold_sof = (amplitude - DecodeTag->previous_amplitude) / 2; } else { DecodeTag->posCount = 2; - DecodeTag->threshold_sof = DecodeTag->threshold_sof/2; + DecodeTag->threshold_sof = DecodeTag->threshold_sof / 2; } // DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_SOF_HIGH; @@ -621,7 +621,6 @@ static void DecodeTagReset(DecodeTag_t *DecodeTag) { int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { int samples = 0, ret = 0; - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE] = {0}; // the Decoder data structure DecodeTag_t DecodeTag = { 0 }; @@ -635,13 +634,18 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo // Setup and start DMA. FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + + // The DMA buffer, used to stream samples from the FPGA + dmabuf16_t *dma = get_dma16(); + + FpgaSetupSscDma((uint8_t*) dma->buf, DMA_BUFFER_SIZE); + uint32_t dma_start_time = 0; - uint16_t *upTo = dmaBuf; + uint16_t *upTo = dma->buf; for(;;) { - uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); if (behindBy == 0) continue; @@ -653,17 +657,17 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo volatile uint16_t tagdata = *upTo++; - if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9 * ISO15693_DMA_BUFFER_SIZE / 10)) { + if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dma->buf; // start reading the circular buffer from the beginning + if (behindBy > (9 * DMA_BUFFER_SIZE / 10)) { Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); ret = -1; break; } } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers } if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) { @@ -1016,8 +1020,6 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo int samples = 0; bool gotFrame = false; - uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE] = {0}; - // the decoder data structure DecodeReader_t DecodeReader = {0}; DecodeReaderInit(&DecodeReader, received, max_len, 0, NULL); @@ -1036,25 +1038,26 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8; // Setup and start DMA. - FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE); - uint8_t *upTo = dmaBuf; + dmabuf8_t *dma = get_dma8(); + FpgaSetupSscDma(dma->buf, DMA_BUFFER_SIZE); + uint8_t *upTo = dma->buf; for (;;) { - uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE - 1); + uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); if (behindBy == 0) continue; volatile uint8_t b = *upTo++; - if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dma->buf; // start reading the circular buffer from the beginning + if (behindBy > (9 * DMA_BUFFER_SIZE / 10)) { Dbprintf("About to blow circular buffer - aborted! behindBy %d", behindBy); break; } } if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers } for (int i = 7; i >= 0; i--) { @@ -1146,12 +1149,8 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { clear_trace(); set_tracing(true); - - // The DMA buffer, used to stream samples from the FPGA - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE] = {0}; - + // Count of samples received so far, so that we can include timing - // information in the trace buffer. int samples = 0; DecodeTag_t DecodeTag = {0}; @@ -1168,29 +1167,32 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); - Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); + Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE * sizeof(uint16_t)); } Dbprintf("Sniff started. Press PM3 Button to stop."); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); LED_D_OFF(); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); StartCountSspClk(); - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + + // The DMA buffer, used to stream samples from the FPGA + dmabuf16_t *dma = get_dma16(); + FpgaSetupSscDma((uint8_t*)dma->buf, DMA_BUFFER_SIZE); + uint16_t *upTo = dma->buf; bool TagIsActive = false; bool ReaderIsActive = false; bool ExpectTagAnswer = false; uint32_t dma_start_time = 0; - uint16_t *upTo = dmaBuf; - uint16_t max_behindBy = 0; // And now we loop, receiving samples. for(;;) { - uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); if (behindBy > max_behindBy) { max_behindBy = behindBy; } @@ -1204,17 +1206,16 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { } uint16_t sniffdata = *upTo++; - - if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { - + + if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dma->buf; // start reading the circular buffer from the beginning + if (behindBy > (9 * DMA_BUFFER_SIZE / 10)) { Dbprintf("About to blow circular buffer - aborted! behindBy=%d, samples=%d", behindBy, samples); break; } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers WDT_HIT(); if (BUTTON_PRESS()) { DbpString("Sniff stopped."); From a1529b44ca77236cc15fd099e39a2fa6fd0e9b3b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 19 Jul 2020 20:45:47 +0200 Subject: [PATCH 085/139] fix auth and --- armsrc/appmain.c | 6 + armsrc/iclass.c | 55 ++------ armsrc/iso15693.c | 228 +++++++++++++++++------------- client/src/cmdhficlass.c | 293 +++++++++++++++++++++++++-------------- client/src/cmdhficlass.h | 13 -- common/cardhelper.c | 11 ++ common/cardhelper.h | 1 + include/pm3_cmd.h | 17 +++ 8 files changed, 367 insertions(+), 257 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 094982a3c..7f4f24c43 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -960,6 +960,7 @@ static void PacketReceived(PacketCommandNG *packet) { case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type SniffHitag2(); // SniffHitag2(packet->oldarg[0]); + reply_ng(CMD_LF_HITAG_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content @@ -1027,6 +1028,7 @@ static void PacketReceived(PacketCommandNG *packet) { } PACKED; struct p *payload = (struct p *) packet->data.asBytes; SniffIso15693(payload->jam_search_len, payload->jam_search_string); + reply_ng(CMD_HF_ISO15693_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_ISO15693_COMMAND: { @@ -1089,6 +1091,7 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_HF_ISO14443B_SNIFF: { SniffIso14443b(); + reply_ng(CMD_HF_ISO14443B_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_ISO14443B_SIMULATE: { @@ -1113,6 +1116,7 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_HF_FELICA_SNIFF: { felica_sniff(packet->oldarg[0], packet->oldarg[1]); + reply_ng(CMD_HF_FELICA_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_FELICALITE_DUMP: { @@ -1124,6 +1128,7 @@ static void PacketReceived(PacketCommandNG *packet) { #ifdef WITH_ISO14443a case CMD_HF_ISO14443A_SNIFF: { SniffIso14443a(packet->data.asBytes[0]); + reply_ng(CMD_HF_ISO14443A_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_ISO14443A_READER: { @@ -1380,6 +1385,7 @@ static void PacketReceived(PacketCommandNG *packet) { } PACKED; struct p *payload = (struct p *) packet->data.asBytes; SniffIClass(payload->jam_search_len, payload->jam_search_string); + reply_ng(CMD_HF_ICLASS_SNIFF, PM3_SUCCESS, NULL, 0); break; } case CMD_HF_ICLASS_SIMULATE: { diff --git a/armsrc/iclass.c b/armsrc/iclass.c index d8892a74c..fa161b813 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -38,7 +38,7 @@ // The length of a received command will in most cases be no more than 18 bytes. // we expect max 34 bytes as tag answer (response to READ4) #ifndef ICLASS_BUFFER_SIZE -#define ICLASS_BUFFER_SIZE 34 +#define ICLASS_BUFFER_SIZE 34 + 2 #endif // iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after @@ -481,7 +481,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t cmd, options, block; int len = 0; - bool exit_loop = 0; + bool exit_loop = false; while (exit_loop == false) { WDT_HIT(); @@ -863,12 +863,11 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; static uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; - static uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; + uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used // bit 7: parity. - if (use_credit_key) read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; @@ -878,7 +877,6 @@ static bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t int len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time); if (len < 0) return false; - // send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -936,7 +934,7 @@ void ReaderIClass(uint8_t flags) { uint8_t card_data[6 * 8] = {0xFF}; // uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; memset(resp, 0xFF, sizeof(resp)); // bool flag_readonce = flags & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully @@ -1162,21 +1160,9 @@ void iClass_Authentication(uint8_t *bytes) { bool iclass_auth(uint8_t *bytes, bool send_reply, uint8_t *dataout) { - struct p { - uint8_t key[8]; - bool use_raw; - bool use_elite; - bool use_credit_key; - } PACKED; - struct p *payload = (struct p *)bytes; - - // device response message - struct { - bool isOK; - uint8_t div_key[8]; - uint8_t mac[4]; - } PACKED packet; - + iclass_auth_req_t *payload = (iclass_auth_req_t *)bytes; + iclass_auth_resp_t packet; + Iso15693InitReader(); uint8_t card_data[3 * 8] = {0xFF}; @@ -1208,7 +1194,7 @@ bool iclass_auth(uint8_t *bytes, bool send_reply, uint8_t *dataout) { check[7] = packet.mac[2]; check[8] = packet.mac[3]; - uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; packet.isOK = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); if (send_reply) @@ -1236,12 +1222,12 @@ typedef struct iclass_premac { void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { uint8_t i = 0, isOK = 0; - uint8_t lastChunk = ((arg0 >> 8) & 0xFF); +// uint8_t lastChunk = ((arg0 >> 8) & 0xFF); bool use_credit_key = ((arg0 >> 16) & 0xFF); uint8_t keyCount = arg1 & 0xFF; uint8_t check[9] = { ICLASS_CMD_CHECK }; - uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; if (use_credit_key) @@ -1260,8 +1246,8 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { Iso15693InitReader(); - uint32_t start_time = 0; - uint32_t eof_time = 0; + uint32_t start_time = 0, eof_time = 0; + if (select_iclass_tag(card_data, use_credit_key, &eof_time) == false) goto out; @@ -1305,15 +1291,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { out: // send keyindex. reply_mix(CMD_HF_ICLASS_CHKKEYS, isOK, i, 0, 0, 0); - - if (isOK >= 1 || lastChunk) { - LED_A_OFF(); - } - switch_off(); - - LED_B_OFF(); - LED_C_OFF(); } // Tries to read block. @@ -1338,8 +1316,8 @@ void iClass_ReadBlk(uint8_t blockno) { LED_A_ON(); result.isOK = iclass_readblock(blockno, result.blockdata); - switch_off(); reply_ng(CMD_HF_ICLASS_READBL, PM3_SUCCESS, (uint8_t *)&result, sizeof(result)); + switch_off(); } // Dump command seems to dump a block related portion of card memory. @@ -1372,11 +1350,6 @@ void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { switch_off(); - // return pointer to dump memory in arg3 - // iceman: why not return | dataout - getbigbuf ? Should give exact location. -// Dbprintf("ICE:: dataout, %u max trace %u, bb start %u, data-bb %u ", dataout, BigBuf_max_traceLen(), BigBuf_get_addr(), dataout - BigBuf_get_addr() ); -// Dbprintf("ICE:: bb size %u, malloced %u (255*8)", BigBuf_get_size(), BigBuf_get_size() - (dataout - BigBuf_get_addr()) ); -// reply_mix(CMD_ACK, isOK, blkcnt, BigBuf_max_traceLen(), 0, 0); struct p { bool isOK; uint8_t block_cnt; @@ -1384,7 +1357,7 @@ void iClass_Dump(uint8_t start_blockno, uint8_t numblks) { } PACKED payload; payload.isOK = isOK; payload.block_cnt = blkcnt; - payload.bb_offset = BigBuf_max_traceLen(); + payload.bb_offset = dataout - BigBuf_get_addr(); reply_ng(CMD_HF_ICLASS_DUMP, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); BigBuf_free(); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 36530f72b..df576d3b3 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -91,7 +91,6 @@ /////////////////////////////////////////////////////////////////////// // buffers -//#define ISO15693_DMA_BUFFER_SIZE 256 // must be a power of 2 #define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet #define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet @@ -106,7 +105,6 @@ #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) static void BuildIdentifyRequest(uint8_t *cmd); -static void BuildInventoryResponse(uint8_t *uid); // --------------------------- // Signal Processing @@ -255,12 +253,13 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { *start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time } - while (GetCountSspClk() < *start_time) - /* wait */ ; + // wait + while (GetCountSspClk() < *start_time) ; LED_B_ON(); for (int c = 0; c < len; c++) { volatile uint8_t data = cmd[c]; + for (uint8_t i = 0; i < 8; i++) { uint16_t send_word = (data & 0x80) ? 0xffff : 0x0000; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; @@ -294,8 +293,8 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, } } - while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) - /* wait */ ; + // wait + while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) ; uint8_t shift_delay = modulation_start_time & 0x00000007; @@ -304,9 +303,12 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, LED_C_ON(); uint8_t bits_to_shift = 0x00; uint8_t bits_to_send = 0x00; + for (size_t c = 0; c < len; c++) { for (int i = (c == 0 ? 4 : 7); i >= 0; i--) { + uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; + for (int j = 0; j < (slow ? 4 : 1); ) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; @@ -380,7 +382,7 @@ typedef struct DecodeTag { //----------------------------------------------------------------------------- static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { switch (DecodeTag->state) { - case STATE_TAG_SOF_LOW: + case STATE_TAG_SOF_LOW: { // waiting for a rising edge if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) { if (DecodeTag->posCount > 10) { @@ -395,8 +397,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De DecodeTag->previous_amplitude = amplitude; } break; - - case STATE_TAG_SOF_RISING_EDGE: + } + case STATE_TAG_SOF_RISING_EDGE: { if (amplitude > DecodeTag->threshold_sof + DecodeTag->previous_amplitude) { // edge still rising if (amplitude > DecodeTag->threshold_sof + DecodeTag->threshold_sof) { // steeper edge, take this as time reference DecodeTag->posCount = 1; @@ -411,8 +413,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De // DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_SOF_HIGH; break; - - case STATE_TAG_SOF_HIGH: + } + case STATE_TAG_SOF_HIGH: { // waiting for 10 times high. Take average over the last 8 if (amplitude > DecodeTag->threshold_sof) { DecodeTag->posCount++; @@ -429,8 +431,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De DecodeTag->state = STATE_TAG_SOF_LOW; } break; - - case STATE_TAG_SOF_HIGH_END: + } + case STATE_TAG_SOF_HIGH_END: { // check for falling edge if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) { DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) @@ -458,8 +460,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De } } break; - - case STATE_TAG_RECEIVING_DATA: + } + case STATE_TAG_RECEIVING_DATA: { // FpgaDisableTracing(); // DEBUGGING // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", // amplitude, @@ -547,8 +549,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De } DecodeTag->posCount++; break; - - case STATE_TAG_EOF: + } + case STATE_TAG_EOF: { if (DecodeTag->posCount == 1) { DecodeTag->sum1 = 0; DecodeTag->sum2 = 0; @@ -571,8 +573,8 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De } DecodeTag->posCount++; break; - - case STATE_TAG_EOF_TAIL: + } + case STATE_TAG_EOF_TAIL: { if (DecodeTag->posCount == 1) { DecodeTag->sum1 = 0; DecodeTag->sum2 = 0; @@ -595,6 +597,7 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De } DecodeTag->posCount++; break; + } } return false; @@ -690,20 +693,22 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo FpgaDisableSscDma(); + uint32_t sof_time = *eof_time - (DecodeTag.len * 8 * 8 * 16) // time for byte transfers - (32 * 16) // time for SOF transfer - (DecodeTag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d", + Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d, maxlen = %u", samples, ret, DecodeTag.state, DecodeTag.lastBit, DecodeTag.len, DecodeTag.bitCount, - DecodeTag.posCount + DecodeTag.posCount, + DecodeTag.max_len ); Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); } @@ -890,11 +895,11 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: DecodeReader->posCount++; if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit?1:0; + DecodeReader->sum1 = bit ? 1 : 0; } else if (DecodeReader->posCount <= 4) { if (bit) DecodeReader->sum1++; } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit?1:0; + DecodeReader->sum2 = bit ? 1 : 0; } else { if (bit) DecodeReader->sum2++; } @@ -935,11 +940,11 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: DecodeReader->posCount++; if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit?1:0; + DecodeReader->sum1 = bit ? 1 : 0; } else if (DecodeReader->posCount <= 4) { if (bit) DecodeReader->sum1++; } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit?1:0; + DecodeReader->sum2 = bit ? 1 : 0; } else if (bit) { DecodeReader->sum2++; } @@ -976,20 +981,20 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR case STATE_READER_RECEIVE_JAMMING: DecodeReader->posCount++; if (DecodeReader->Coding == CODING_1_OUT_OF_4) { - if (DecodeReader->posCount == 7*16) { // 7 bits jammed + if (DecodeReader->posCount == 7 * 16) { // 7 bits jammed FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming // FpgaDisableTracing(); LED_D_OFF(); - } else if (DecodeReader->posCount == 8*16) { + } else if (DecodeReader->posCount == 8 * 16) { DecodeReader->posCount = 0; DecodeReader->output[DecodeReader->byteCount++] = 0x00; DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; } } else { - if (DecodeReader->posCount == 7*256) { // 7 bits jammend + if (DecodeReader->posCount == 7 * 256) { // 7 bits jammend FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming LED_D_OFF(); - } else if (DecodeReader->posCount == 8*256) { + } else if (DecodeReader->posCount == 8 * 256) { DecodeReader->posCount = 0; DecodeReader->output[DecodeReader->byteCount++] = 0x00; DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; @@ -1083,8 +1088,11 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo FpgaDisableSscDma(); - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", + samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, + DecodeReader.bitCount, DecodeReader.posCount); + } if (DecodeReader.byteCount > 0) { uint32_t sof_time = *eof_time @@ -1154,11 +1162,11 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { int samples = 0; DecodeTag_t DecodeTag = {0}; - uint8_t response[ISO15693_MAX_RESPONSE_LENGTH]; + uint8_t response[ISO15693_MAX_RESPONSE_LENGTH] = {0}; DecodeTagInit(&DecodeTag, response, sizeof(response)); DecodeReader_t DecodeReader = {0}; - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH] = {0}; DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd), jam_search_len, jam_search_string); // Print some debug information about the buffer sizes @@ -1166,7 +1174,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { Dbprintf("Sniffing buffers initialized:"); Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); - Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); + Dbprintf(" Tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE * sizeof(uint16_t)); } @@ -1184,9 +1192,9 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { FpgaSetupSscDma((uint8_t*)dma->buf, DMA_BUFFER_SIZE); uint16_t *upTo = dma->buf; - bool TagIsActive = false; - bool ReaderIsActive = false; - bool ExpectTagAnswer = false; + bool tag_is_active = false; + bool reader_is_active = false; + bool expect_tag_answer = false; uint32_t dma_start_time = 0; uint16_t max_behindBy = 0; @@ -1225,7 +1233,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { } // no need to try decoding reader data if the tag is sending - if (TagIsActive == false) { + if (tag_is_active == false) { if (Handle15693SampleFromReader(sniffdata & 0x02, &DecodeReader)) { @@ -1242,8 +1250,8 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // And also reset the demod code, which might have been // false-triggered by the commands from the reader. DecodeTagReset(&DecodeTag); - ReaderIsActive = false; - ExpectTagAnswer = true; + reader_is_active = false; + expect_tag_answer = true; } else if (Handle15693SampleFromReader(sniffdata & 0x01, &DecodeReader)) { @@ -1261,15 +1269,15 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // And also reset the demod code, which might have been // false-triggered by the commands from the reader. DecodeTagReset(&DecodeTag); - ReaderIsActive = false; - ExpectTagAnswer = true; + reader_is_active = false; + expect_tag_answer = true; } else { - ReaderIsActive = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); + reader_is_active = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); } } - if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + if (!reader_is_active && expect_tag_answer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet if (Handle15693SamplesFromTag(sniffdata >> 2, &DecodeTag)) { uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF @@ -1285,19 +1293,18 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // And ready to receive another response. DecodeTagReset(&DecodeTag); DecodeReaderReset(&DecodeReader); - ExpectTagAnswer = false; - TagIsActive = false; + expect_tag_answer = false; + tag_is_active = false; } else { - TagIsActive = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); + tag_is_active = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); } } } - - FpgaDisableSscDma(); + switch_off(); DbpString("Sniff statistics:"); - Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", ExpectTagAnswer, TagIsActive, ReaderIsActive); + Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", expect_tag_answer, tag_is_active, reader_is_active); Dbprintf(" DecodeTag State: %d", DecodeTag.state); Dbprintf(" DecodeTag byteCnt: %d", DecodeTag.len); Dbprintf(" DecodeTag posCount: %d", DecodeTag.posCount); @@ -1305,18 +1312,18 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { Dbprintf(" DecodeReader byteCnt: %d", DecodeReader.byteCount); Dbprintf(" DecodeReader posCount: %d", DecodeReader.posCount); Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); - Dbprintf(" Max behindBy: %d", max_behindBy); + Dbprintf(" Max behindBy: %d", max_behindBy); } // Initialize Proxmark3 as ISO15693 reader void Iso15693InitReader(void) { - + + LEDsoff(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Start from off (no field generated) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - SpinDelay(50); + SpinDelay(10); // switch field on FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); @@ -1329,7 +1336,7 @@ void Iso15693InitReader(void) { set_tracing(true); // give tags some time to energize - SpinDelay(200); + SpinDelay(250); StartCountSspClk(); } @@ -1354,31 +1361,6 @@ static void BuildIdentifyRequest(uint8_t *cmd) { AddCrc15(cmd, 3); } -// uid is in transmission order (which is reverse of display order) - -// When SIM: now the VICC>VCD responses when we are simulating a tag -static void BuildInventoryResponse(uint8_t *uid) { - - uint8_t cmd[CMD_INV_RESP] = {0}; - - cmd[0] = 0; // No error, no protocol format extension - cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported - - // 64-bit UID - cmd[2] = uid[7]; - cmd[3] = uid[6]; - cmd[4] = uid[5]; - cmd[5] = uid[4]; - cmd[6] = uid[3]; - cmd[7] = uid[2]; - cmd[8] = uid[1]; - cmd[9] = uid[0]; - - // CRC - AddCrc15(cmd, 10); - CodeIso15693AsTag(cmd, CMD_INV_RESP); -} - // Universal Method for sending to and recv bytes from a tag // init ... should we initialize the reader? // speed ... 0 low speed, 1 hi speed @@ -1403,7 +1385,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, &start_time); - uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // substract the 4 padding bits after EOF + uint32_t end_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF LogTrace(send, sendlen, (start_time * 4), (end_time * 4), NULL, true); int res = 0; @@ -1573,9 +1555,9 @@ void Iso15693InitTag(void) { FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + clear_trace(); set_tracing(true); - // turn on clock StartCountSspClk(); } @@ -1583,44 +1565,90 @@ void Iso15693InitTag(void) { // all demodulation performed in arm rather than host. - greg void SimTagIso15693(uint8_t *uid) { + // free eventually allocated BigBuf memory + BigBuf_free_keep_EM(); + Iso15693InitTag(); LED_A_ON(); Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]); - uint8_t buf[ISO15_MAX_FRAME]; - memset(buf, 0x00, sizeof(buf)); - LED_C_ON(); - // Build a suitable reponse to the reader INVENTORY cocmmand - // not so obvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. - BuildInventoryResponse(uid); + // Build INVENTORY command + uint8_t resp_inv[CMD_INV_RESP] = {0}; + + resp_inv[0] = 0; // No error, no protocol format extension + resp_inv[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported + + // 64-bit UID + resp_inv[2] = uid[7]; + resp_inv[3] = uid[6]; + resp_inv[4] = uid[5]; + resp_inv[5] = uid[4]; + resp_inv[6] = uid[3]; + resp_inv[7] = uid[2]; + resp_inv[8] = uid[1]; + resp_inv[9] = uid[0]; + + // CRC + AddCrc15(resp_inv, 10); + CodeIso15693AsTag(resp_inv, CMD_INV_RESP); tosend_t *ts = get_tosend(); - while (!BUTTON_PRESS()) { + enum { NO_FIELD, IDLE, ACTIVATED, SELECTED, HALTED } chip_state = NO_FIELD; + + bool button_pressed = false; + int vHf = 0; // in mV + + bool exit_loop = false; + while (exit_loop == false) { WDT_HIT(); + // find reader field + if (chip_state == NO_FIELD) { + +#if defined RDV4 + vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; +#else + vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; +#endif + if (vHf > MF_MINFIELDV) { + chip_state = IDLE; + LED_A_ON(); + } else { + continue; + } + } + // Listen to reader uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; - uint32_t eof_time = 0, start_time = 0; - int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); - - if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { // TODO: check more flags - bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); - start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - TransmitTo15693Reader(ts->buf, ts->max, &start_time, 0, slow); + uint32_t reader_eof_time = 0; + int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &reader_eof_time); + if (cmd_len < 0) { + Dbprintf("button pressed, exiting"); + button_pressed = true; + exit_loop = true; + break; } - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf(" %d bytes read from reader:", cmd_len); - Dbhexdump(cmd_len, cmd, false); + // TODO: check more flags + if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { + bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); + uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; + TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); + LogTrace(resp_inv, CMD_INV_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); + + chip_state = SELECTED; } } - + switch_off(); + + if (button_pressed) + DbpString("button pressed"); } // Since there is no standardized way of reading the AFI out of a tag, we will brute force it diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 80f6dfab5..d063f1607 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -47,7 +47,7 @@ static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }; static int usage_hf_iclass_sim(void) { @@ -379,6 +379,28 @@ static inline uint32_t leadingzeros(uint64_t a) { #endif } +// iclass card descriptors +const char * card_types[] = { + "PicoPass 16K / 16", // 000 + "PicoPass 32K with current book 16K / 16", // 001 + "Unknown Card Type!", // 010 + "Unknown Card Type!", // 011 + "PicoPass 2K", // 100 + "Unknown Card Type!", // 101 + "PicoPass 16K / 2", // 110 + "PicoPass 32K with current book 16K / 2", // 111 +}; + +uint8_t card_app2_limit[] = { + 0xff, + 0xff, + 0xff, + 0xff, + 0x1f, + 0xff, + 0xff, + 0xff, +}; static uint8_t isset(uint8_t val, uint8_t mask) { return (val & mask); @@ -434,7 +456,7 @@ static void fuse_config(const picopass_hdr *hdr) { ); } -static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t *app_areas, uint8_t *kb) { +static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb) { // mem-bit 5, mem-bit 7, chip-bit 4: defines chip type uint8_t k16 = isset(mem_cfg, 0x80); //uint8_t k2 = isset(mem_cfg, 0x08); @@ -443,47 +465,54 @@ static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, ui if (isset(chip_cfg, 0x10) && !k16 && !book) { *kb = 2; *app_areas = 2; - *max_blk = 31; } else if (isset(chip_cfg, 0x10) && k16 && !book) { *kb = 16; *app_areas = 2; - *max_blk = 255; //16kb } else if (notset(chip_cfg, 0x10) && !k16 && !book) { *kb = 16; *app_areas = 16; - *max_blk = 255; //16kb } else if (isset(chip_cfg, 0x10) && k16 && book) { *kb = 32; *app_areas = 3; - *max_blk = 255; //16kb } else if (notset(chip_cfg, 0x10) && !k16 && book) { *kb = 32; *app_areas = 17; - *max_blk = 255; //16kb } else { *kb = 32; *app_areas = 2; - *max_blk = 255; } } +static uint8_t get_mem_config(const picopass_hdr *hdr) { + uint8_t mem = hdr->conf.mem_config; + uint8_t chip = hdr->conf.chip_config; + // three configuration bits that decides sizes + uint8_t type = (chip & 0x10) >> 2; + type |= (mem & 0x80) >> 6; + type |= (mem & 0x20) >> 5; + return type; +} + static void mem_app_config(const picopass_hdr *hdr) { uint8_t mem = hdr->conf.mem_config; uint8_t chip = hdr->conf.chip_config; - uint8_t applimit = hdr->conf.app_limit; uint8_t kb = 2; uint8_t app_areas = 2; - uint8_t max_blk = 31; - getMemConfig(mem, chip, &max_blk, &app_areas, &kb); + getMemConfig(mem, chip, &app_areas, &kb); - if (applimit < 6) applimit = 26; - if (kb == 2 && (applimit > 0x1f)) applimit = 26; + // three configuration bits that decides sizes + uint8_t type = (chip & 0x10) >> 2; + type |= (mem & 0x80) >> 6; + type |= (mem & 0x20) >> 5; + + uint8_t app1_limit = hdr->conf.app_limit - 5; // minus header blocks + uint8_t app2_limit = card_app2_limit[type]; PrintAndLogEx(INFO, "------ " _CYAN_("Memory") " ------"); - PrintAndLogEx(INFO, " %u KBits/%u App Areas (%u bytes), max blocks 0x%02X (%02d)", kb, app_areas, max_blk * 8, mem, mem); - PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", applimit - 5 , applimit, applimit); - PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", max_blk - applimit, applimit + 1, max_blk, applimit + 1, max_blk); + PrintAndLogEx(INFO, " %u KBits/%u App Areas (%u bytes)", kb, app_areas, app2_limit * 8); + PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit , app1_limit + 5, app1_limit + 5); + PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit); PrintAndLogEx(INFO, "------ " _CYAN_("KeyAccess") " ------"); PrintAndLogEx(INFO, " Kd = Debit key (AA1), Kc = Credit key (AA2)"); @@ -552,7 +581,15 @@ static int CmdHFiClassSniff(const char *Cmd) { payload.jam_search_len = sizeof(update_epurse_sequence); memcpy(payload.jam_search_string, update_epurse_sequence, sizeof(payload.jam_search_string)); } + + PacketResponseNG resp; + clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_SNIFF, (uint8_t *)&payload, sizeof(payload)); + + WaitForResponse(CMD_HF_ICLASS_SNIFF, &resp); + + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass list") "` to look at the collected trace"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save h") "` to save tracelog for later analysing"); return PM3_SUCCESS; } @@ -956,6 +993,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { } if (have_file) { + picopass_hdr *hdr = (picopass_hdr *)decrypted; uint8_t mem = hdr->conf.mem_config; @@ -963,10 +1001,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { uint8_t applimit = hdr->conf.app_limit; uint8_t kb = 2; uint8_t app_areas = 2; - uint8_t max_blk = 31; - getMemConfig(mem, chip, &max_blk, &app_areas, &kb); - - + getMemConfig(mem, chip, &app_areas, &kb); BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03); @@ -976,7 +1011,8 @@ static int CmdHFiClassDecrypt(const char *Cmd) { PrintAndLogEx(WARNING, "Actual file len " _YELLOW_("%zu") " vs HID app-limit len " _YELLOW_("%u"), decryptedlen, applimit * 8); PrintAndLogEx(INFO, "Setting limit to " _GREEN_("%u"), limit * 8); } - uint8_t numblocks4userid = GetNumberBlocksForUserId(decrypted + (6 * 8)); + + //uint8_t numblocks4userid = GetNumberBlocksForUserId(decrypted + (6 * 8)); for (uint16_t blocknum = 0; blocknum < limit; ++blocknum) { @@ -987,7 +1023,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { continue; // Decrypted block 7,8,9 if configured. - if (blocknum > 6 && blocknum <= 6 + numblocks4userid && memcmp(enc_data, empty, 8) != 0) { + if (blocknum > 6 && blocknum <= 9 && memcmp(enc_data, empty, 8) != 0) { if (use_sc) { Decrypt(enc_data, decrypted + idx); } else { @@ -996,13 +1032,14 @@ static int CmdHFiClassDecrypt(const char *Cmd) { } } - //Use the first block (CSN) for filename + // use the first block (CSN) for filename char *fptr = calloc(50, sizeof(uint8_t)); - if (!fptr) { + if (fptr == false) { PrintAndLogEx(WARNING, "Failed to allocate memory"); free(decrypted); return PM3_EMALLOC; } + strcat(fptr, "hf-iclass-"); FillFileNameByUID(fptr, hdr->csn, "-dump-decrypted", sizeof(hdr->csn)); @@ -1013,6 +1050,8 @@ static int CmdHFiClassDecrypt(const char *Cmd) { PrintAndLogEx(INFO, "Following output skips CSN / block0"); printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen); + PrintAndLogEx(NORMAL, ""); + // decode block 6 if (memcmp(decrypted + (8 * 6), empty, 8) != 0) { if (use_sc) { @@ -1029,7 +1068,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { mid = bytes_to_num(decrypted + (8 * 7), 4); bot = bytes_to_num(decrypted + (8 * 7) + 4, 4); - PrintAndLogEx(INFO, "Block 7 binary"); + PrintAndLogEx(INFO, "Block 7 decoder"); char hexstr[8 + 1] = {0}; hex_to_buffer((uint8_t *)hexstr, decrypted + (8 * 7), 8, sizeof(hexstr) - 1, 0, 0, true); @@ -1039,15 +1078,36 @@ static int CmdHFiClassDecrypt(const char *Cmd) { uint8_t i = 0; while (i < strlen(binstr) && binstr[i++] == '0'); - PrintAndLogEx(SUCCESS, "%s", binstr + i); + PrintAndLogEx(SUCCESS, "Binary..................... " _GREEN_("%s"), binstr + i); PrintAndLogEx(INFO, "Wiegand decode"); wiegand_message_t packed = initialize_message_object(top, mid, bot); HIDTryUnpack(&packed, true); - PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + } else { PrintAndLogEx(INFO, "No credential found."); } + + // decode block 9 + if (memcmp(decrypted + (8 * 9), empty, 8) != 0) { + + uint8_t usr_blk_len = GetNumberBlocksForUserId(decrypted + (8 * 6)); + if (usr_blk_len < 3) { + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Block 9 decoder"); + uint8_t pinsize = 10; + if (use_sc) { + pinsize = GetPinSize(decrypted + (8 * 6)); + } + uint64_t pin = bytes_to_num(decrypted + (8 * 9), 5); + char tmp[17] = {0}; + sprintf(tmp, "%."PRIu64, BCD2DEC(pin)); + PrintAndLogEx(INFO, "PIN........................ " _GREEN_("%.*s"), pinsize, tmp); + } + } + + PrintAndLogEx(INFO, "-----------------------------------------------------------------"); free(decrypted); free(fptr); @@ -1178,7 +1238,7 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u .use_credit_key = use_credit_key }; memcpy(payload.key, KEY, 8); - + SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t*)&payload, sizeof(payload)); PacketResponseNG resp; clearCommandBuffer(); @@ -1205,7 +1265,9 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u if (MAC) memcpy(MAC, packet->mac, sizeof(packet->mac)); - if (verbose) PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); + if (verbose) + PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); + return true; } @@ -1214,15 +1276,11 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t c_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t blockno = 0; - uint8_t numblks = 0; - uint8_t maxBlk = 31; - uint8_t app_areas = 1; - uint8_t kb = 2; uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t CreditKEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t keyNbr = 0; uint8_t dataLen = 0; + uint8_t app_limit1, app_limit2 = 0; uint8_t fileNameLen = 0; char filename[FILE_PATH_SIZE] = {0}; char tempStr[50] = {0}; @@ -1329,6 +1387,7 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t readStatus = resp.oldarg[0] & 0xff; uint8_t *data = resp.data.asBytes; + picopass_hdr *hdr = (picopass_hdr *)data; if (readStatus == 0) { PrintAndLogEx(FAILED, "no tag found"); @@ -1338,11 +1397,14 @@ static int CmdHFiClassDump(const char *Cmd) { if (readStatus & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC)) { memcpy(tag_data, data, 8 * 3); - blockno += 2; // 2 to force re-read of block 2 later. (seems to respond differently..) - numblks = data[8]; - getMemConfig(data[13], data[12], &maxBlk, &app_areas, &kb); - // large memory - not able to dump pages currently - if (numblks > maxBlk) numblks = maxBlk; + + uint8_t type = get_mem_config(hdr); + app_limit1 = hdr->conf.app_limit; + app_limit2 = card_app2_limit[type]; + } else { + PrintAndLogEx(FAILED, "failed to read block 0,1,2"); + DropField(); + return PM3_ESOFT; } // authenticate debit key and get div_key - later store in dump block 3 @@ -1356,8 +1418,8 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t start_blockno; uint8_t numblks; } PACKED payload; - payload.start_blockno = blockno; - payload.numblks = numblks - blockno + 1; + payload.start_blockno = 5; + payload.numblks = app_limit1 - 5; clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); @@ -1397,20 +1459,24 @@ static int CmdHFiClassDump(const char *Cmd) { return PM3_ESOFT; } + uint16_t offset = (5 * 8); uint32_t startindex = packet->bb_offset; - if (blocks_read * 8 > sizeof(tag_data) - (blockno * 8)) { + if (blocks_read * 8 > sizeof(tag_data) - offset) { PrintAndLogEx(FAILED, "data exceeded buffer size!"); - blocks_read = (sizeof(tag_data) / 8) - blockno; + blocks_read = (sizeof(tag_data) / 8) - 5; } // response ok - now get bigbuf content of the dump - if (!GetFromDevice(BIG_BUF, tag_data + (blockno * 8), blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { + if (!GetFromDevice(BIG_BUF, tag_data + offset, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } + + PrintAndLogEx(INFO, "BB start index :: %u", startindex); + PrintAndLogEx(INFO, "BB :: %s", sprint_hex(tag_data + (5*8), 32)); - size_t gotBytes = blocks_read * 8 + blockno * 8; + offset += (blocks_read * 8); // try AA2 Kc, Credit if (have_credit_key) { @@ -1424,46 +1490,44 @@ static int CmdHFiClassDump(const char *Cmd) { return PM3_ESOFT; } - // do we still need to read more block? (aa2 enabled?) - if (maxBlk > blockno + numblks + 1) { + payload.start_blockno = app_limit1; + payload.numblks = app_limit2 - app_limit1 - 5; - payload.start_blockno = blockno + blocks_read; - payload.numblks = maxBlk - (blockno + blocks_read); + clearCommandBuffer(); + SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); - - if (!WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) { - PrintAndLogEx(WARNING, "command execute timeout 2"); - return PM3_ETIMEOUT; - } - - if (resp.status != PM3_SUCCESS) { - PrintAndLogEx(ERR, "failed to communicate with card"); - return resp.status; - } - - packet = (struct p_resp *)resp.data.asBytes; - if (packet->isOK == false) { - PrintAndLogEx(WARNING, "read block failed using credit key"); - return PM3_ESOFT; - } - - blocks_read = packet->block_cnt; - startindex = packet->bb_offset; - - if (blocks_read * 8 > sizeof(tag_data) - gotBytes) { - PrintAndLogEx(FAILED, "data exceeded buffer size!"); - blocks_read = (sizeof(tag_data) - gotBytes) / 8; - } - // get dumped data from bigbuf - if (!GetFromDevice(BIG_BUF, tag_data + gotBytes, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { - PrintAndLogEx(WARNING, "command execution time out"); - return PM3_ETIMEOUT; - } - - gotBytes += blocks_read * 8; + if (!WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) { + PrintAndLogEx(WARNING, "command execute timeout 2"); + return PM3_ETIMEOUT; } + + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to communicate with card"); + return resp.status; + } + + packet = (struct p_resp *)resp.data.asBytes; + if (packet->isOK == false) { + PrintAndLogEx(WARNING, "read block failed using credit key"); + return PM3_ESOFT; + } + + // + blocks_read = packet->block_cnt; + startindex = packet->bb_offset; + + if (blocks_read * 8 > sizeof(tag_data) - offset) { + PrintAndLogEx(FAILED, "data exceeded buffer size!"); + blocks_read = (sizeof(tag_data) - offset) / 8; + } + + // get dumped data from bigbuf + if (!GetFromDevice(BIG_BUF, tag_data + offset, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "command execution time out"); + return PM3_ETIMEOUT; + } + + offset += blocks_read * 8; } DropField(); @@ -1480,7 +1544,7 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "------+--+-------------------------+----------"); PrintAndLogEx(INFO, " CSN |00| " _GREEN_("%s") "|", sprint_hex(tag_data, 8)); - printIclassDumpContents(tag_data, 1, (gotBytes / 8), gotBytes); + printIclassDumpContents(tag_data, 1, (offset / 8), offset); if (filename[0] == 0) { //Use the first block (CSN) for filename @@ -1489,10 +1553,10 @@ static int CmdHFiClassDump(const char *Cmd) { } // save the dump to .bin file - PrintAndLogEx(SUCCESS, "saving dump file - %zu blocks read", gotBytes / 8); - saveFile(filename, ".bin", tag_data, gotBytes); - saveFileEML(filename, tag_data, gotBytes, 8); - saveFileJSON(filename, jsfIclass, tag_data, gotBytes, NULL); + PrintAndLogEx(SUCCESS, "saving dump file - %zu blocks read", offset / 8); + saveFile(filename, ".bin", tag_data, offset); + saveFileEML(filename, tag_data, offset, 8); + saveFileJSON(filename, jsfIclass, tag_data, offset, NULL); return PM3_SUCCESS; } @@ -1825,25 +1889,22 @@ static int CmdHFiClassCloneTag(const char *Cmd) { static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth) { - // return data. - struct p { - bool isOK; - uint8_t blockdata[8]; - } PACKED; - struct p *result = NULL; - // block 0,1 should always be able to read, and block 5 on some cards. if (auth || blockno >= 2) { uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (select_and_auth(KEY, MAC, div_key, (keyType == 0x18), elite, rawkey, verbose) == false) { + if (verbose) PrintAndLogEx(FAILED, "select/auth failed"); + DropField(); return PM3_ESOFT; } } else { uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (select_only(CSN, CCNR, (keyType == 0x18), verbose) == false) { - return PM3_ESOFT; + if (verbose) PrintAndLogEx(FAILED, "select only failed"); + DropField(); + return PM3_ESOFT; } } @@ -1851,22 +1912,29 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_READBL, (uint8_t *)&blockno, sizeof(uint8_t)); - if (WaitForResponseTimeout(CMD_HF_ICLASS_READBL, &resp, 2000) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_READBL, &resp, 2000) == false) { if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); DropField(); return PM3_ETIMEOUT; } + DropField(); + if (resp.status != PM3_SUCCESS) { if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); return PM3_EWRONGANSWER; } - result = (struct p *)resp.data.asBytes; - if (result->isOK == false) - return PM3_ESOFT; + // return data. + struct p { + bool isOK; + uint8_t blockdata[8]; + } PACKED; - DropField(); + struct p *result = (struct p *)resp.data.asBytes; + if (result->isOK == false) { + return PM3_ESOFT; + } PrintAndLogEx(SUCCESS, " block %02X : " _GREEN_("%s"), blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); @@ -1943,6 +2011,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { bool auth = false; bool verbose = false; uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': @@ -2000,10 +2069,10 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { if (got_blockno == false) errors = true; - if (errors || cmdp < 4) return usage_hf_iclass_readblock(); + if (errors) return usage_hf_iclass_readblock(); - if (!auth) - PrintAndLogEx(FAILED, "warning: no authentication used with read, only a few specific blocks can be read accurately without authentication."); + if (auth == false) + PrintAndLogEx(WARNING, "warning: no authentication used with read, only a few specific blocks can be read accurately without authentication."); return iclass_read_block(KEY, blockno, keyType, elite, rawkey, verbose, auth); } @@ -2993,6 +3062,20 @@ int CmdHFiClass(const char *Cmd) { return CmdsParse(CommandTable, Cmd); } + +//static void test_credential_type(void) { + // need AA1 key + // Block 5 -> tells if its a legacy or SIO, also tells which key to use. + + // tech | blocks used | desc | num of payloads + // -------+-----------------------+-----------------------------------+------ + // legacy | 6,7,8,9 | AA!, Access control payload | 1 + // SE | 6,7,8,9,10,11,12 | AA1, Secure identity object (SIO) | 1 + // SR | 6,7,8,9, | AA1, Access control payload | 2 + // | 10,11,12,13,14,15,16 | AA1, Secure identity object (SIO) | + // SEOS | | | +//} + int readIclass(bool loop, bool verbose) { bool tagFound = false; @@ -3079,6 +3162,10 @@ int readIclass(bool loop, bool verbose) { } } + uint8_t cardtype = get_mem_config(hdr); + PrintAndLogEx(SUCCESS, "%s", card_types[cardtype]); + + if (tagFound && !loop) { PrintAndLogEx(NORMAL, ""); DropField(); diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index 19b994d0c..53880d647 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -27,19 +27,6 @@ typedef struct iclass_prekey { uint8_t key[8]; } iclass_prekey_t; -typedef struct { - uint8_t key[8]; - bool use_raw; - bool use_elite; - bool use_credit_key; -} PACKED iclass_auth_req_t; - -typedef struct { - bool isOK; - uint8_t div_key[8]; - uint8_t mac[4]; -} PACKED iclass_auth_resp_t; - int CmdHFiClass(const char *Cmd); int readIclass(bool loop, bool verbose); diff --git a/common/cardhelper.c b/common/cardhelper.c index fbdaf2002..e34780896 100644 --- a/common/cardhelper.c +++ b/common/cardhelper.c @@ -19,6 +19,7 @@ #define CARD_INS_ENCRYPT 0x02 #define CARD_INS_DECODE 0x06 #define CARD_INS_NUMBLOCKS 0x07 +#define CARD_INS_PINSIZE 0x08 static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // look for CryptoHelper @@ -91,3 +92,13 @@ uint8_t GetNumberBlocksForUserId(uint8_t *src) { ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); return resp[8]; } + +// Call with block6 +uint8_t GetPinSize(uint8_t *src) { + int resp_len = 0; + uint8_t resp[254] = {0}; + uint8_t c[] = {0x96, CARD_INS_PINSIZE, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + memcpy(c + 5, src, 8); + ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); + return resp[8]; +} diff --git a/common/cardhelper.h b/common/cardhelper.h index eaf7ff38f..d55ae6701 100644 --- a/common/cardhelper.h +++ b/common/cardhelper.h @@ -19,4 +19,5 @@ bool Encrypt(uint8_t *src, uint8_t *dest); bool Decrypt(uint8_t *src, uint8_t *dest); void DecodeBlock6(uint8_t *src); uint8_t GetNumberBlocksForUserId(uint8_t *src); +uint8_t GetPinSize(uint8_t *src); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 3568bd50a..766e78c54 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -289,6 +289,23 @@ typedef struct { const char *value; } PACKED ecdsa_publickey_t; + +// iCLASS auth request data structure +typedef struct { + uint8_t key[8]; + bool use_raw; + bool use_elite; + bool use_credit_key; +} PACKED iclass_auth_req_t; + +// iCLASS auth response data structure +typedef struct { + bool isOK; + uint8_t div_key[8]; + uint8_t mac[4]; +} PACKED iclass_auth_resp_t; + + // For the bootloader #define CMD_DEVICE_INFO 0x0000 //#define CMD_SETUP_WRITE 0x0001 From 53174faaf6b0b21b74f38ca051ed28bed4570b3c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 19 Jul 2020 23:08:53 +0200 Subject: [PATCH 086/139] adapt return value --- common/cardhelper.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/cardhelper.c b/common/cardhelper.c index e34780896..3a5def846 100644 --- a/common/cardhelper.c +++ b/common/cardhelper.c @@ -100,5 +100,9 @@ uint8_t GetPinSize(uint8_t *src) { uint8_t c[] = {0x96, CARD_INS_PINSIZE, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(c + 5, src, 8); ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); - return resp[8]; + + if ( resp[resp_len - 2] == 0x90 && resp[resp_len - 1] == 0x00) { + return resp[8]; + } + return 0; } From 20ad16bfca7f8179bff241de1e0c606152e896cf Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 19 Jul 2020 23:09:21 +0200 Subject: [PATCH 087/139] fix iclass dump.. --- client/src/cmdhficlass.c | 53 +++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index d063f1607..614555cb0 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1096,14 +1096,18 @@ static int CmdHFiClassDecrypt(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Block 9 decoder"); - uint8_t pinsize = 10; + uint8_t pinsize = 0; if (use_sc) { pinsize = GetPinSize(decrypted + (8 * 6)); + + if (pinsize > 0) { + + uint64_t pin = bytes_to_num(decrypted + (8 * 9), 5); + char tmp[17] = {0}; + sprintf(tmp, "%."PRIu64, BCD2DEC(pin)); + PrintAndLogEx(INFO, "PIN........................ " _GREEN_("%.*s"), pinsize, tmp); + } } - uint64_t pin = bytes_to_num(decrypted + (8 * 9), 5); - char tmp[17] = {0}; - sprintf(tmp, "%."PRIu64, BCD2DEC(pin)); - PrintAndLogEx(INFO, "PIN........................ " _GREEN_("%.*s"), pinsize, tmp); } } @@ -1280,7 +1284,7 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t CreditKEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t keyNbr = 0; uint8_t dataLen = 0; - uint8_t app_limit1, app_limit2 = 0; + uint8_t app_limit1 = 0, app_limit2 = 0; uint8_t fileNameLen = 0; char filename[FILE_PATH_SIZE] = {0}; char tempStr[50] = {0}; @@ -1370,7 +1374,7 @@ static int CmdHFiClassDump(const char *Cmd) { // if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work) if (!have_debit_key && have_credit_key) use_credit_key = true; - uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); + uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE | FLAG_ICLASS_READER_AIA); //get config and first 3 blocks PacketResponseNG resp; @@ -1395,8 +1399,8 @@ static int CmdHFiClassDump(const char *Cmd) { return PM3_ESOFT; } - if (readStatus & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC)) { - memcpy(tag_data, data, 8 * 3); + if (readStatus & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC | FLAG_ICLASS_AIA)) { + memcpy(tag_data, data, 8 * 6); uint8_t type = get_mem_config(hdr); app_limit1 = hdr->conf.app_limit; @@ -1418,7 +1422,7 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t start_blockno; uint8_t numblks; } PACKED payload; - payload.start_blockno = 5; + payload.start_blockno = 6; payload.numblks = app_limit1 - 5; clearCommandBuffer(); @@ -1443,7 +1447,7 @@ static int CmdHFiClassDump(const char *Cmd) { return resp.status; } - // dump cmd switch off at device when finised. + // dump cmd switch off at device when finished. struct p_resp { bool isOK; @@ -1452,30 +1456,26 @@ static int CmdHFiClassDump(const char *Cmd) { } PACKED; struct p_resp *packet = (struct p_resp *)resp.data.asBytes; - uint32_t blocks_read = packet->block_cnt; - if (packet->isOK == false) { PrintAndLogEx(WARNING, "read block failed"); return PM3_ESOFT; } - uint16_t offset = (5 * 8); - uint32_t startindex = packet->bb_offset; - - if (blocks_read * 8 > sizeof(tag_data) - offset) { - PrintAndLogEx(FAILED, "data exceeded buffer size!"); - blocks_read = (sizeof(tag_data) / 8) - 5; + uint32_t blocks_read = packet->block_cnt; + if (blocks_read == app_limit1 - 5) { + PrintAndLogEx(INFO, "ICE: got all AA1"); } + uint16_t offset = (6 * 8); + uint32_t startindex = packet->bb_offset; + // response ok - now get bigbuf content of the dump if (!GetFromDevice(BIG_BUF, tag_data + offset, blocks_read * 8, startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } - - PrintAndLogEx(INFO, "BB start index :: %u", startindex); - PrintAndLogEx(INFO, "BB :: %s", sprint_hex(tag_data + (5*8), 32)); + PrintAndLogEx(INFO, "ICE: blocks_read (13) == %u (0x%02x)", blocks_read, blocks_read); offset += (blocks_read * 8); // try AA2 Kc, Credit @@ -1491,12 +1491,12 @@ static int CmdHFiClassDump(const char *Cmd) { } payload.start_blockno = app_limit1; - payload.numblks = app_limit2 - app_limit1 - 5; + payload.numblks = app_limit2 - app_limit1; clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t*)&payload, sizeof(payload)); - if (!WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000) == false) { PrintAndLogEx(WARNING, "command execute timeout 2"); return PM3_ETIMEOUT; } @@ -1511,10 +1511,13 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(WARNING, "read block failed using credit key"); return PM3_ESOFT; } - // blocks_read = packet->block_cnt; startindex = packet->bb_offset; + + if (blocks_read == app_limit2 - app_limit1) { + PrintAndLogEx(INFO, "ICE: got all AA2"); + } if (blocks_read * 8 > sizeof(tag_data) - offset) { PrintAndLogEx(FAILED, "data exceeded buffer size!"); From 9eb479fc7f0bbd37f23be73bafd4b9630827c555 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 20 Jul 2020 00:16:16 +0200 Subject: [PATCH 088/139] iceclass calc diversified key if not present --- armsrc/Standalone/hf_iceclass.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 19aa9626d..d8df74773 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -70,6 +70,7 @@ uint8_t card_app2_limit[] = { }; static uint8_t aa2_key[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + static uint8_t legacy_aa1_key[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78}; static uint8_t csns[8 * NUM_CSNS] = { @@ -145,15 +146,22 @@ static int fullsim_mode(void) { Dbprintf("loaded '" _YELLOW_(HF_ICLASS_FULLSIM_ORIG_BIN) "' (%u bytes) to emulator memory", fsize); } - // create diversified key if not in dump. + // create diversified key AA1/KD if not in dump. if ( memcmp(emul + (3 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 0) { uint8_t ccnr[12] = {0}; memcpy(ccnr, emul + (2 * 8), 8); bool use_elite = false; - iclass_calc_div_key(emul, legacy_aa1_key, emul + (3 * 8), use_elite); } + // create diversified key AA2/KC if not in dump. + if ( memcmp(emul + (4 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 0) { + uint8_t ccnr[12] = {0}; + memcpy(ccnr, emul + (2 * 8), 8); + bool use_elite = false; + iclass_calc_div_key(emul, aa2_key, emul + (4 * 8), use_elite); + } + iclass_simulate(ICLASS_SIM_MODE_FULL, 0 , false, NULL, NULL, NULL); LED_B_ON(); @@ -298,23 +306,21 @@ static int reader_dump_mode(void) { static int config_sim_mode(void) { uint8_t *emul = BigBuf_get_EM_addr(); - + for (uint8_t i = 0; i < 2; i++) { SpinOff(0); - uint32_t fsize = size_in_spiffs(cc_files[i]); - + rdv40_spiffs_lazy_mount(); + uint32_t fsize = size_in_spiffs(cc_files[i]); int res = rdv40_spiffs_read_as_filetype(cc_files[i], emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); rdv40_spiffs_lazy_unmount(); if (res == SPIFFS_OK) { Dbprintf("loaded '" _YELLOW_("%s") "' (%u bytes) to emulator memory", cc_files[i], fsize); + iclass_simulate(ICLASS_SIM_MODE_FULL, 0 , false, NULL, NULL, NULL); } - - iclass_simulate(ICLASS_SIM_MODE_FULL, 0 , false, NULL, NULL, NULL); } - rdv40_spiffs_lazy_unmount(); return PM3_SUCCESS; } @@ -330,7 +336,7 @@ void RunMod(void) { StandAloneMode(); Dbprintf(_YELLOW_("HF iCLASS mode a.k.a iceCLASS started")); - uint8_t mode = ICE_STATE_ATTACK; + uint8_t mode = ICE_STATE_FULLSIM; for (;;) { From 2d368ba2d8264db7e7e9335b1fdb8f8d3a701efe Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 20 Jul 2020 00:52:46 +0200 Subject: [PATCH 089/139] fix sim reply --- client/src/cmdhficlass.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 614555cb0..29c5eee98 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -649,9 +649,9 @@ static int CmdHFiClassSim(const char *Cmd) { PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, NUM_CSNS, 0, csns, 8 * NUM_CSNS); + SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, NUM_CSNS, 1, csns, 8 * NUM_CSNS); - while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + while (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { tries++; if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\naborted via keyboard."); @@ -698,9 +698,9 @@ static int CmdHFiClassSim(const char *Cmd) { PrintAndLogEx(INFO, "press Enter to cancel"); PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, NUM_CSNS, 0, csns, 8 * NUM_CSNS); + SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, NUM_CSNS, 1, csns, 8 * NUM_CSNS); - while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + while (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { tries++; if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\naborted via keyboard."); @@ -1457,10 +1457,11 @@ static int CmdHFiClassDump(const char *Cmd) { struct p_resp *packet = (struct p_resp *)resp.data.asBytes; if (packet->isOK == false) { - PrintAndLogEx(WARNING, "read block failed"); + PrintAndLogEx(WARNING, "read AA1 blocks failed"); return PM3_ESOFT; } + // 13 uint32_t blocks_read = packet->block_cnt; if (blocks_read == app_limit1 - 5) { PrintAndLogEx(INFO, "ICE: got all AA1"); From 0f5e58a81c07554fb74375450b1333e882b4671e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 20 Jul 2020 17:42:10 +0200 Subject: [PATCH 090/139] fix iclass sof tracelog --- client/src/cmdtrace.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index f2b20ab68..750bc9953 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -275,13 +275,12 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr if (data_len == 0) { if (protocol == ICLASS && duration == 2048) { - sprintf(line[0], " "); + sprintf(line[0], ""); } else if (protocol == ISO_15693 && duration == 512) { - sprintf(line[0], " "); + sprintf(line[0], ""); } else { sprintf(line[0], ""); } - return tracepos; } for (int j = 0; j < data_len && j / 18 < 18; j++) { From e94cbd8da58a9e2d41fb609e06282c72277a0d54 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 21 Jul 2020 10:48:29 +0200 Subject: [PATCH 091/139] list 15693 --- client/src/cmdhflist.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index 8ade2f7dc..202e5b41d 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -507,8 +507,10 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { break; } - if (cmd[1] >= 0x2D && cmd[1] <= 0x9F) snprintf(exp, size, "Optional RFU"); - else if (cmd[1] >= 0xA0 && cmd[1] <= 0xDF) snprintf(exp, size, "Cust IC MFG dependent"); + if (cmd[1] > ISO15693_STAYQUIET && cmd[1] < ISO15693_READBLOCK) snprintf(exp, size, "Mandatory RFU"); + else if (cmd[1] > ISO15693_READ_MULTI_SECSTATUS && cmd[1] <= 0x9F) snprintf(exp, size, "Optional RFU"); +// else if (cmd[1] >= 0xA0 && cmd[1] <= 0xDF) snprintf(exp, size, "Cust IC MFG dependent"); + else if (cmd[1] > ISO15693_READ_SIGNATURE && cmd[1] <= 0xDF) snprintf(exp, size, "Cust IC MFG dependent"); else if (cmd[1] >= 0xE0) snprintf(exp, size, "Proprietary IC MFG dependent"); else snprintf(exp, size, "?"); From df404a652a4a1294249400fc4b9410d555810907 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 21 Jul 2020 10:49:29 +0200 Subject: [PATCH 092/139] duration isnt 15bits, its 16. length is 15bits. --- armsrc/BigBuf.c | 17 +++++++++++++---- armsrc/BigBuf.h | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 338206d6e..608c38040 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -221,17 +221,17 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ duration = (UINT32_MAX - timestamp_start) + timestamp_end; } - if (duration > 0x7FFF) { + if (duration > 0xFFFF) { /* if (DBGLEVEL >= DBG_DEBUG) { - Dbprintf("Error in LogTrace: duration too long for 15 bits encoding: 0x%08x start: 0x%08x end: 0x%08x", duration, timestamp_start, timestamp_end); + Dbprintf("Error in LogTrace: duration too long for 16 bits encoding: 0x%08x start: 0x%08x end: 0x%08x", duration, timestamp_start, timestamp_end); } */ - duration /= 32; + duration = 0; } hdr->timestamp = timestamp_start; - hdr->duration = duration & 0x7FFF; + hdr->duration = duration & 0xFFFF; hdr->data_len = iLen; hdr->isResponse = !readerToTag; trace_len += TRACELOG_HDR_LEN; @@ -254,6 +254,15 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ return true; } +// specific LogTrace function for ISO15693: the duration needs to be scaled because otherwise it won't fit into a uint16_t +bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag) { + uint32_t duration = ts_end - ts_start; + duration /= 32; + ts_end = ts_start + duration; + return LogTrace(bytes, len, ts_start, ts_end, parity, reader2tag); +} + + // Emulator memory uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length) { uint8_t *mem = BigBuf_get_EM_addr(); diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 2f381f36b..8b570cb8c 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -42,7 +42,11 @@ void clear_trace(void); void set_tracing(bool enable); void set_tracelen(uint32_t value); bool get_tracing(void); + bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); +bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag); + + uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length); From 42f21e8d658bf60077e260d60c0fe09c9eb63ec9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 21 Jul 2020 10:50:23 +0200 Subject: [PATCH 093/139] adapt iclass sim --- armsrc/iclass.c | 65 ++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index fa161b813..16988f74e 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -393,7 +393,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { int trace_data_size = 0; // Respond SOF -- takes 1 bytes - uint8_t *resp_sof = BigBuf_malloc(1); + uint8_t *resp_sof = BigBuf_malloc(2); int resp_sof_len; // Anticollision CSN (rotated CSN) @@ -524,6 +524,32 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { } goto send; + } else if (cmd == ICLASS_CMD_SELECT && len == 9) { + // Reader selects anticollision CSN. + // Tag sends the corresponding real CSN + if (chip_state == ACTIVATED || chip_state == SELECTED) { + if (!memcmp(receivedCmd + 1, anticoll_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } else { + chip_state = IDLE; + } + } else if (chip_state == HALTED) { + // RESELECT with CSN + if (!memcmp(receivedCmd + 1, csn_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } + } + goto send; + + } else if (cmd == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // 0x0C if (chip_state != SELECTED) { @@ -580,38 +606,14 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = data_generic_trace; trace_data_size = 10; CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(modulated_response, ts->buf, ts->max); + memcpy(data_response, ts->buf, ts->max); + modulated_response = data_response; modulated_response_size = ts->max; } goto send; } } // swith - } else if (cmd == ICLASS_CMD_SELECT && len == 9) { // 0x81 - // Reader selects anticollission CSN. - // Tag sends the corresponding real CSN - if (chip_state == ACTIVATED || chip_state == SELECTED) { - if (!memcmp(receivedCmd + 1, anticoll_data, 8)) { - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - chip_state = SELECTED; - } else { - chip_state = IDLE; - } - } else if (chip_state == HALTED) { - // RESELECT with CSN - if (!memcmp(receivedCmd + 1, csn_data, 8)) { - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - chip_state = SELECTED; - } - } - goto send; - } else if (cmd == ICLASS_CMD_READCHECK) { // 0x88 // Read e-purse KD (88 02) KC (18 02) if (chip_state != SELECTED) { @@ -701,11 +703,12 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = data_generic_trace; trace_data_size = 34; CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(modulated_response, ts->buf, ts->max); + memcpy(data_response, ts->buf, ts->max); + modulated_response = data_response; modulated_response_size = ts->max; goto send; - } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { + } else if (cmd == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { // We're expected to respond with the data+crc, exactly what's already in the receivedCmd // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b @@ -810,7 +813,7 @@ send: if (modulated_response_size > 0) { uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM; TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); - LogTrace(trace_data, trace_data_size, response_time * 32, (response_time * 32) + (modulated_response_size * 32 * 64), NULL, false); + LogTrace_ISO15693(trace_data, trace_data_size, response_time * 32, (response_time * 32) + (modulated_response_size * 32 * 64), NULL, false); } } @@ -829,7 +832,7 @@ static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, start_time); *end_time = *start_time + (32 * ((8 * ts->max) - 4)); // substract the 4 padding bits after EOF - LogTrace(frame, len, (*start_time * 4), (*end_time * 4), NULL, true); + LogTrace_ISO15693(frame, len, (*start_time * 4), (*end_time * 4), NULL, true); } static bool iclass_send_cmd_with_retries(uint8_t* cmd, size_t cmdsize, uint8_t* resp, size_t max_resp_size, From c51565fd7cae3dd96d3db06cc29f847361275753 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 21 Jul 2020 10:51:48 +0200 Subject: [PATCH 094/139] iso15 sim, make decoders dynamic bigbuff malloc --- armsrc/iso15693.c | 797 ++++++++++++++++++++++++++-------------------- armsrc/iso15693.h | 2 +- 2 files changed, 444 insertions(+), 355 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index df576d3b3..379d094af 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -106,14 +106,22 @@ static void BuildIdentifyRequest(uint8_t *cmd); -// --------------------------- +// --------------------------- + // Signal Processing // --------------------------- // prepare data using "1 out of 4" code for later transmission // resulting data rate is 26.48 kbit/s (fc/512) // cmd ... data -// n ... length of data +// n ... length of data +static uint8_t encode15_lut[] = { + 0x40, // 01000000 + 0x10, // 00010000 + 0x04, // 00000100 + 0x01 // 00000001 +}; + void CodeIso15693AsReader(uint8_t *cmd, int n) { tosend_reset(); @@ -124,23 +132,18 @@ void CodeIso15693AsReader(uint8_t *cmd, int n) { // data for (int i = 0; i < n; i++) { - for (int j = 0; j < 8; j += 2) { - uint8_t these = (cmd[i] >> j) & 0x03; - switch(these) { - case 0: - ts->buf[++ts->max] = 0x40; //01000000 - break; - case 1: - ts->buf[++ts->max] = 0x10; //00010000 - break; - case 2: - ts->buf[++ts->max] = 0x04; //00000100 - break; - case 3: - ts->buf[++ts->max] = 0x01; //00000001 - break; - } - } + + volatile uint8_t b = (cmd[i] >> 0) & 0x03; + ts->buf[++ts->max] = encode15_lut[b]; + + b = (cmd[i] >> 2) & 0x03; + ts->buf[++ts->max] = encode15_lut[b]; + + b = (cmd[i] >> 4) & 0x03; + ts->buf[++ts->max] = encode15_lut[b]; + + b = (cmd[i] >> 6) & 0x03; + ts->buf[++ts->max] = encode15_lut[b]; } // EOF @@ -234,7 +237,6 @@ void CodeIso15693AsTag(uint8_t *cmd, size_t len) { // EOF ts->buf[++ts->max] = 0xB8; // 10111000 - ts->max++; } @@ -348,7 +350,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, #define NOISE_THRESHOLD 80 // don't try to correlate noise #define MAX_PREVIOUS_AMPLITUDE (-1 - NOISE_THRESHOLD) -typedef struct DecodeTag { +typedef struct { enum { STATE_TAG_SOF_LOW, STATE_TAG_SOF_RISING_EDGE, @@ -380,222 +382,211 @@ typedef struct DecodeTag { //----------------------------------------------------------------------------- // DEMODULATE tag answer //----------------------------------------------------------------------------- -static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { - switch (DecodeTag->state) { +static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *tag) { + + switch (tag->state) { case STATE_TAG_SOF_LOW: { // waiting for a rising edge - if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) { - if (DecodeTag->posCount > 10) { - DecodeTag->threshold_sof = amplitude - DecodeTag->previous_amplitude; // to be divided by 2 - DecodeTag->threshold_half = 0; - DecodeTag->state = STATE_TAG_SOF_RISING_EDGE; + if (amplitude > NOISE_THRESHOLD + tag->previous_amplitude) { + if (tag->posCount > 10) { + tag->threshold_sof = amplitude - tag->previous_amplitude; // to be divided by 2 + tag->threshold_half = 0; + tag->state = STATE_TAG_SOF_RISING_EDGE; } else { - DecodeTag->posCount = 0; + tag->posCount = 0; } } else { - DecodeTag->posCount++; - DecodeTag->previous_amplitude = amplitude; + tag->posCount++; + tag->previous_amplitude = amplitude; } break; } case STATE_TAG_SOF_RISING_EDGE: { - if (amplitude > DecodeTag->threshold_sof + DecodeTag->previous_amplitude) { // edge still rising - if (amplitude > DecodeTag->threshold_sof + DecodeTag->threshold_sof) { // steeper edge, take this as time reference - DecodeTag->posCount = 1; + if (amplitude > tag->threshold_sof + tag->previous_amplitude) { // edge still rising + if (amplitude > tag->threshold_sof + tag->threshold_sof) { // steeper edge, take this as time reference + tag->posCount = 1; } else { - DecodeTag->posCount = 2; + tag->posCount = 2; } - DecodeTag->threshold_sof = (amplitude - DecodeTag->previous_amplitude) / 2; + tag->threshold_sof = (amplitude - tag->previous_amplitude) / 2; } else { - DecodeTag->posCount = 2; - DecodeTag->threshold_sof = DecodeTag->threshold_sof / 2; + tag->posCount = 2; + tag->threshold_sof = tag->threshold_sof / 2; } - // DecodeTag->posCount = 2; - DecodeTag->state = STATE_TAG_SOF_HIGH; + tag->state = STATE_TAG_SOF_HIGH; break; } case STATE_TAG_SOF_HIGH: { // waiting for 10 times high. Take average over the last 8 - if (amplitude > DecodeTag->threshold_sof) { - DecodeTag->posCount++; - if (DecodeTag->posCount > 2) { - DecodeTag->threshold_half += amplitude; // keep track of average high value + if (amplitude > tag->threshold_sof) { + tag->posCount++; + if (tag->posCount > 2) { + tag->threshold_half += amplitude; // keep track of average high value } - if (DecodeTag->posCount == 10) { - DecodeTag->threshold_half >>= 2; // (4 times 1/2 average) - DecodeTag->state = STATE_TAG_SOF_HIGH_END; + if (tag->posCount == 10) { + tag->threshold_half >>= 2; // (4 times 1/2 average) + tag->state = STATE_TAG_SOF_HIGH_END; } } else { // high phase was too short - DecodeTag->posCount = 1; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; + tag->posCount = 1; + tag->previous_amplitude = amplitude; + tag->state = STATE_TAG_SOF_LOW; } break; } case STATE_TAG_SOF_HIGH_END: { // check for falling edge - if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) { - DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) - DecodeTag->shiftReg = 0; - DecodeTag->bitCount = 0; - DecodeTag->len = 0; - DecodeTag->sum1 = amplitude; - DecodeTag->sum2 = 0; - DecodeTag->posCount = 2; - DecodeTag->state = STATE_TAG_RECEIVING_DATA; - // FpgaDisableTracing(); // DEBUGGING - // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", - // amplitude, - // DecodeTag->threshold_sof, - // DecodeTag->threshold_half/4, - // DecodeTag->previous_amplitude); // DEBUGGING + if (tag->posCount == 13 && amplitude < tag->threshold_sof) { + tag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) + tag->shiftReg = 0; + tag->bitCount = 0; + tag->len = 0; + tag->sum1 = amplitude; + tag->sum2 = 0; + tag->posCount = 2; + tag->state = STATE_TAG_RECEIVING_DATA; LED_C_ON(); } else { - DecodeTag->posCount++; - if (DecodeTag->posCount > 13) { // high phase too long - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; + tag->posCount++; + if (tag->posCount > 13) { // high phase too long + tag->posCount = 0; + tag->previous_amplitude = amplitude; + tag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } } break; } case STATE_TAG_RECEIVING_DATA: { - // FpgaDisableTracing(); // DEBUGGING - // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", - // amplitude, - // DecodeTag->threshold_sof, - // DecodeTag->threshold_half/4, - // DecodeTag->previous_amplitude); // DEBUGGING - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; + if (tag->posCount == 1) { + tag->sum1 = 0; + tag->sum2 = 0; } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; + if (tag->posCount <= 4) { + tag->sum1 += amplitude; } else { - DecodeTag->sum2 += amplitude; + tag->sum2 += amplitude; } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in both halves - if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF - DecodeTag->state = STATE_TAG_EOF; + if (tag->posCount == 8) { + if (tag->sum1 > tag->threshold_half && tag->sum2 > tag->threshold_half) { // modulation in both halves + if (tag->lastBit == LOGIC0) { // this was already part of EOF + tag->state = STATE_TAG_EOF; } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; + tag->posCount = 0; + tag->previous_amplitude = amplitude; + tag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } - } else if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in second half + } else if (tag->sum1 < tag->threshold_half && tag->sum2 > tag->threshold_half) { // modulation in second half // logic 1 - if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF - DecodeTag->lastBit = SOF_PART2; // SOF completed + if (tag->lastBit == SOF_PART1) { // still part of SOF + tag->lastBit = SOF_PART2; // SOF completed } else { - DecodeTag->lastBit = LOGIC1; - DecodeTag->shiftReg >>= 1; - DecodeTag->shiftReg |= 0x80; - DecodeTag->bitCount++; - if (DecodeTag->bitCount == 8) { - DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; - DecodeTag->len++; - // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING - if (DecodeTag->len > DecodeTag->max_len) { + tag->lastBit = LOGIC1; + tag->shiftReg >>= 1; + tag->shiftReg |= 0x80; + tag->bitCount++; + if (tag->bitCount == 8) { + tag->output[tag->len] = tag->shiftReg; + tag->len++; + + if (tag->len > tag->max_len) { // buffer overflow, give up LED_C_OFF(); return true; } - DecodeTag->bitCount = 0; - DecodeTag->shiftReg = 0; + tag->bitCount = 0; + tag->shiftReg = 0; } } - } else if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half + } else if (tag->sum1 > tag->threshold_half && tag->sum2 < tag->threshold_half) { // modulation in first half // logic 0 - if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; + if (tag->lastBit == SOF_PART1) { // incomplete SOF + tag->posCount = 0; + tag->previous_amplitude = amplitude; + tag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } else { - DecodeTag->lastBit = LOGIC0; - DecodeTag->shiftReg >>= 1; - DecodeTag->bitCount++; - if (DecodeTag->bitCount == 8) { - DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; - DecodeTag->len++; - // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING - if (DecodeTag->len > DecodeTag->max_len) { + tag->lastBit = LOGIC0; + tag->shiftReg >>= 1; + tag->bitCount++; + + if (tag->bitCount == 8) { + tag->output[tag->len] = tag->shiftReg; + tag->len++; + + if (tag->len > tag->max_len) { // buffer overflow, give up - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; + tag->posCount = 0; + tag->previous_amplitude = amplitude; + tag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } - DecodeTag->bitCount = 0; - DecodeTag->shiftReg = 0; + tag->bitCount = 0; + tag->shiftReg = 0; } } } else { // no modulation - if (DecodeTag->lastBit == SOF_PART2) { // only SOF (this is OK for iClass) + if (tag->lastBit == SOF_PART2) { // only SOF (this is OK for iClass) LED_C_OFF(); return true; } else { - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; + tag->posCount = 0; + tag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } } - DecodeTag->posCount = 0; + tag->posCount = 0; } - DecodeTag->posCount++; + tag->posCount++; break; } case STATE_TAG_EOF: { - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; + if (tag->posCount == 1) { + tag->sum1 = 0; + tag->sum2 = 0; } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; + if (tag->posCount <= 4) { + tag->sum1 += amplitude; } else { - DecodeTag->sum2 += amplitude; + tag->sum2 += amplitude; } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_EOF_TAIL; + if (tag->posCount == 8) { + if (tag->sum1 > tag->threshold_half && tag->sum2 < tag->threshold_half) { // modulation in first half + tag->posCount = 0; + tag->state = STATE_TAG_EOF_TAIL; } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; + tag->posCount = 0; + tag->previous_amplitude = amplitude; + tag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } } - DecodeTag->posCount++; + tag->posCount++; break; } case STATE_TAG_EOF_TAIL: { - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; + if (tag->posCount == 1) { + tag->sum1 = 0; + tag->sum2 = 0; } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; + if (tag->posCount <= 4) { + tag->sum1 += amplitude; } else { - DecodeTag->sum2 += amplitude; + tag->sum2 += amplitude; } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // no modulation in both halves + if (tag->posCount == 8) { + if (tag->sum1 < tag->threshold_half && tag->sum2 < tag->threshold_half) { // no modulation in both halves LED_C_OFF(); return true; } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; + tag->posCount = 0; + tag->previous_amplitude = amplitude; + tag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } } - DecodeTag->posCount++; + tag->posCount++; break; } } @@ -603,21 +594,18 @@ static RAMFUNC int Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *De return false; } -static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) { - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; - DecodeTag->output = data; - DecodeTag->max_len = max_len; +static void DecodeTagReset(DecodeTag_t *tag) { + tag->posCount = 0; + tag->state = STATE_TAG_SOF_LOW; + tag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; } -static void DecodeTagReset(DecodeTag_t *DecodeTag) { - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; +static void DecodeTagInit(DecodeTag_t *tag, uint8_t *data, uint16_t max_len) { + tag->output = data; + tag->max_len = max_len; + DecodeTagReset(tag); } - /* * Receive and decode the tag response, also log to tracebuffer */ @@ -641,14 +629,18 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo // The DMA buffer, used to stream samples from the FPGA dmabuf16_t *dma = get_dma16(); - FpgaSetupSscDma((uint8_t*) dma->buf, DMA_BUFFER_SIZE); + // Setup and start DMA. + if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) { + if (DBGLEVEL > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting"); + return -4; + } uint32_t dma_start_time = 0; uint16_t *upTo = dma->buf; for(;;) { - uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); + volatile uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); if (behindBy == 0) continue; @@ -693,7 +685,6 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo FpgaDisableSscDma(); - uint32_t sof_time = *eof_time - (DecodeTag.len * 8 * 8 * 16) // time for byte transfers - (32 * 16) // time for SOF transfer @@ -713,11 +704,11 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo Dbprintf("timing: sof_time = %d, eof_time = %d", (sof_time * 4), (*eof_time * 4)); } - if (ret == -1) { + if (ret < 0) { return ret; } - - LogTrace(DecodeTag.output, DecodeTag.len, (sof_time * 4), (*eof_time * 4), NULL, false); + + LogTrace_ISO15693(DecodeTag.output, DecodeTag.len, (sof_time * 4), (*eof_time * 4), NULL, false); return DecodeTag.len; } @@ -735,7 +726,7 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo // false if we are still waiting for some more //============================================================================= -typedef struct DecodeReader { +typedef struct { enum { STATE_READER_UNSYNCD, STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF, @@ -762,50 +753,50 @@ typedef struct DecodeReader { uint8_t *jam_search_string; } DecodeReader_t; -static void DecodeReaderInit(DecodeReader_t* DecodeReader, uint8_t *data, uint16_t max_len, uint8_t jam_search_len, uint8_t *jam_search_string) { - DecodeReader->output = data; - DecodeReader->byteCountMax = max_len; - DecodeReader->state = STATE_READER_UNSYNCD; - DecodeReader->byteCount = 0; - DecodeReader->bitCount = 0; - DecodeReader->posCount = 1; - DecodeReader->shiftReg = 0; - DecodeReader->jam_search_len = jam_search_len; - DecodeReader->jam_search_string = jam_search_string; +static void DecodeReaderInit(DecodeReader_t* reader, uint8_t *data, uint16_t max_len, uint8_t jam_search_len, uint8_t *jam_search_string) { + reader->output = data; + reader->byteCountMax = max_len; + reader->state = STATE_READER_UNSYNCD; + reader->byteCount = 0; + reader->bitCount = 0; + reader->posCount = 1; + reader->shiftReg = 0; + reader->jam_search_len = jam_search_len; + reader->jam_search_string = jam_search_string; } -static void DecodeReaderReset(DecodeReader_t* DecodeReader) { - DecodeReader->state = STATE_READER_UNSYNCD; +static void DecodeReaderReset(DecodeReader_t* reader) { + reader->state = STATE_READER_UNSYNCD; } -static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeReader) { - switch (DecodeReader->state) { +static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *reader) { + switch (reader->state) { case STATE_READER_UNSYNCD: // wait for unmodulated carrier if (bit) { - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } break; case STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF: if (!bit) { // we went low, so this could be the beginning of a SOF - DecodeReader->posCount = 1; - DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; + reader->posCount = 1; + reader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; } break; case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF: - DecodeReader->posCount++; + reader->posCount++; if (bit) { // detected rising edge - if (DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + if (reader->posCount < 4) { // rising edge too early (nominally expected at 5) + reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { // SOF - DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; + reader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; } } else { - if (DecodeReader->posCount > 5) { // stayed low for too long - DecodeReaderReset(DecodeReader); + if (reader->posCount > 5) { // stayed low for too long + DecodeReaderReset(reader); } else { // do nothing, keep waiting } @@ -813,22 +804,26 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR break; case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF: - DecodeReader->posCount++; - if (!bit) { // detected a falling edge - if (DecodeReader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) - DecodeReaderReset(DecodeReader); - } else if (DecodeReader->posCount < 23) { // SOF for 1 out of 4 coding - DecodeReader->Coding = CODING_1_OUT_OF_4; - DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; - } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) - DecodeReaderReset(DecodeReader); + + reader->posCount++; + + if (bit == false) { // detected a falling edge + + if (reader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) + DecodeReaderReset(reader); + } else if (reader->posCount < 23) { // SOF for 1 out of 4 coding + reader->Coding = CODING_1_OUT_OF_4; + reader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + } else if (reader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) + DecodeReaderReset(reader); } else { // SOF for 1 out of 256 coding - DecodeReader->Coding = CODING_1_OUT_OF_256; - DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + reader->Coding = CODING_1_OUT_OF_256; + reader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; } + } else { - if (DecodeReader->posCount > 29) { // stayed high for too long - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + if (reader->posCount > 29) { // stayed high for too long + reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { // do nothing, keep waiting } @@ -836,37 +831,39 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR break; case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF: - DecodeReader->posCount++; + + reader->posCount++; + if (bit) { // detected rising edge - if (DecodeReader->Coding == CODING_1_OUT_OF_256) { - if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + if (reader->Coding == CODING_1_OUT_OF_256) { + if (reader->posCount < 32) { // rising edge too early (nominally expected at 33) + reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { - DecodeReader->posCount = 1; - DecodeReader->bitCount = 0; - DecodeReader->byteCount = 0; - DecodeReader->sum1 = 1; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; + reader->posCount = 1; + reader->bitCount = 0; + reader->byteCount = 0; + reader->sum1 = 1; + reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; LED_B_ON(); } } else { // CODING_1_OUT_OF_4 - if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + if (reader->posCount < 24) { // rising edge too early (nominally expected at 25) + reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { - DecodeReader->posCount = 1; - DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; + reader->posCount = 1; + reader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; } } } else { - if (DecodeReader->Coding == CODING_1_OUT_OF_256) { - if (DecodeReader->posCount > 34) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); + if (reader->Coding == CODING_1_OUT_OF_256) { + if (reader->posCount > 34) { // signal stayed low for too long + DecodeReaderReset(reader); } else { // do nothing, keep waiting } } else { // CODING_1_OUT_OF_4 - if (DecodeReader->posCount > 26) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); + if (reader->posCount > 26) { // signal stayed low for too long + DecodeReaderReset(reader); } else { // do nothing, keep waiting } @@ -875,136 +872,162 @@ static RAMFUNC int Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeR break; case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: - DecodeReader->posCount++; + + reader->posCount++; + if (bit) { - if (DecodeReader->posCount == 9) { - DecodeReader->posCount = 1; - DecodeReader->bitCount = 0; - DecodeReader->byteCount = 0; - DecodeReader->sum1 = 1; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; + if (reader->posCount == 9) { + reader->posCount = 1; + reader->bitCount = 0; + reader->byteCount = 0; + reader->sum1 = 1; + reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; LED_B_ON(); } else { // do nothing, keep waiting } } else { // unexpected falling edge - DecodeReaderReset(DecodeReader); + DecodeReaderReset(reader); } break; case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: - DecodeReader->posCount++; - if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit ? 1 : 0; - } else if (DecodeReader->posCount <= 4) { - if (bit) DecodeReader->sum1++; - } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit ? 1 : 0; + + reader->posCount++; + + if (reader->posCount == 1) { + + reader->sum1 = bit ? 1 : 0; + + } else if (reader->posCount <= 4) { + + if (bit) + reader->sum1++; + + } else if (reader->posCount == 5) { + + reader->sum2 = bit ? 1 : 0; + } else { - if (bit) DecodeReader->sum2++; + if (bit) + reader->sum2++; } - if (DecodeReader->posCount == 8) { - DecodeReader->posCount = 0; - if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF + + if (reader->posCount == 8) { + reader->posCount = 0; + if (reader->sum1 <= 1 && reader->sum2 >= 3) { // EOF LED_B_OFF(); // Finished receiving - DecodeReaderReset(DecodeReader); - if (DecodeReader->byteCount != 0) { + DecodeReaderReset(reader); + if (reader->byteCount != 0) { return true; } - } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected a 2bit position - DecodeReader->shiftReg >>= 2; - DecodeReader->shiftReg |= (DecodeReader->bitCount << 6); + + } else if (reader->sum1 >= 3 && reader->sum2 <= 1) { // detected a 2bit position + reader->shiftReg >>= 2; + reader->shiftReg |= (reader->bitCount << 6); } - if (DecodeReader->bitCount == 15) { // we have a full byte - DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; - if (DecodeReader->byteCount > DecodeReader->byteCountMax) { + + if (reader->bitCount == 15) { // we have a full byte + + reader->output[reader->byteCount++] = reader->shiftReg; + if (reader->byteCount > reader->byteCountMax) { // buffer overflow, give up LED_B_OFF(); - DecodeReaderReset(DecodeReader); + DecodeReaderReset(reader); } - DecodeReader->bitCount = 0; - DecodeReader->shiftReg = 0; - if (DecodeReader->byteCount == DecodeReader->jam_search_len) { - if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { + + reader->bitCount = 0; + reader->shiftReg = 0; + if (reader->byteCount == reader->jam_search_len) { + if (!memcmp(reader->output, reader->jam_search_string, reader->jam_search_len)) { LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); - DecodeReader->state = STATE_READER_RECEIVE_JAMMING; + reader->state = STATE_READER_RECEIVE_JAMMING; } } + } else { - DecodeReader->bitCount++; + reader->bitCount++; } } break; case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: - DecodeReader->posCount++; - if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit ? 1 : 0; - } else if (DecodeReader->posCount <= 4) { - if (bit) DecodeReader->sum1++; - } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit ? 1 : 0; + + reader->posCount++; + + if (reader->posCount == 1) { + reader->sum1 = bit ? 1 : 0; + } else if (reader->posCount <= 4) { + if (bit) reader->sum1++; + } else if (reader->posCount == 5) { + reader->sum2 = bit ? 1 : 0; } else if (bit) { - DecodeReader->sum2++; + reader->sum2++; } - if (DecodeReader->posCount == 8) { - DecodeReader->posCount = 0; - if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF + + if (reader->posCount == 8) { + reader->posCount = 0; + if (reader->sum1 <= 1 && reader->sum2 >= 3) { // EOF LED_B_OFF(); // Finished receiving - DecodeReaderReset(DecodeReader); - if (DecodeReader->byteCount != 0) { + DecodeReaderReset(reader); + if (reader->byteCount != 0) { return true; } - } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected the bit position - DecodeReader->shiftReg = DecodeReader->bitCount; + + } else if (reader->sum1 >= 3 && reader->sum2 <= 1) { // detected the bit position + reader->shiftReg = reader->bitCount; } - if (DecodeReader->bitCount == 255) { // we have a full byte - DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; - if (DecodeReader->byteCount > DecodeReader->byteCountMax) { + + if (reader->bitCount == 255) { // we have a full byte + reader->output[reader->byteCount++] = reader->shiftReg; + if (reader->byteCount > reader->byteCountMax) { // buffer overflow, give up LED_B_OFF(); - DecodeReaderReset(DecodeReader); + DecodeReaderReset(reader); } - if (DecodeReader->byteCount == DecodeReader->jam_search_len) { - if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { + + if (reader->byteCount == reader->jam_search_len) { + if (!memcmp(reader->output, reader->jam_search_string, reader->jam_search_len)) { LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); - DecodeReader->state = STATE_READER_RECEIVE_JAMMING; + reader->state = STATE_READER_RECEIVE_JAMMING; } } } - DecodeReader->bitCount++; + reader->bitCount++; } break; case STATE_READER_RECEIVE_JAMMING: - DecodeReader->posCount++; - if (DecodeReader->Coding == CODING_1_OUT_OF_4) { - if (DecodeReader->posCount == 7 * 16) { // 7 bits jammed + + reader->posCount++; + + if (reader->Coding == CODING_1_OUT_OF_4) { + if (reader->posCount == 7 * 16) { // 7 bits jammed FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming // FpgaDisableTracing(); LED_D_OFF(); - } else if (DecodeReader->posCount == 8 * 16) { - DecodeReader->posCount = 0; - DecodeReader->output[DecodeReader->byteCount++] = 0x00; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; + } else if (reader->posCount == 8 * 16) { + reader->posCount = 0; + reader->output[reader->byteCount++] = 0x00; + reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; } } else { - if (DecodeReader->posCount == 7 * 256) { // 7 bits jammend + if (reader->posCount == 7 * 256) { // 7 bits jammend FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); // stop jamming LED_D_OFF(); - } else if (DecodeReader->posCount == 8 * 256) { - DecodeReader->posCount = 0; - DecodeReader->output[DecodeReader->byteCount++] = 0x00; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; + } else if (reader->posCount == 8 * 256) { + reader->posCount = 0; + reader->output[reader->byteCount++] = 0x00; + reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; } } break; default: LED_B_OFF(); - DecodeReaderReset(DecodeReader); + DecodeReaderReset(reader); break; } @@ -1040,17 +1063,25 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo (void) temp; while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; - uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8; - // Setup and start DMA. dmabuf8_t *dma = get_dma8(); - FpgaSetupSscDma(dma->buf, DMA_BUFFER_SIZE); + if (FpgaSetupSscDma(dma->buf, DMA_BUFFER_SIZE) == false) { + if (DBGLEVEL > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting"); + return -4; + } uint8_t *upTo = dma->buf; - for (;;) { - uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); +// uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8; + uint32_t dma_start_time; + for (;;) { + volatile uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); if (behindBy == 0) continue; + + if (samples == 0) { + // DMA has transferred the very first data + dma_start_time = GetCountSspClk() & 0xfffffff0; + } volatile uint8_t b = *upTo++; if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. @@ -1074,16 +1105,16 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo samples++; } + if (gotFrame) { + break; + } + if (BUTTON_PRESS()) { DecodeReader.byteCount = -1; break; } WDT_HIT(); - - if (gotFrame) { - break; - } } FpgaDisableSscDma(); @@ -1094,12 +1125,12 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo DecodeReader.bitCount, DecodeReader.posCount); } - if (DecodeReader.byteCount > 0) { + if (DecodeReader.byteCount >= 0) { uint32_t sof_time = *eof_time - DecodeReader.byteCount * (DecodeReader.Coding == CODING_1_OUT_OF_4 ? 128 : 2048) // time for byte transfers - 32 // time for SOF transfer - 16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, (sof_time * 32), (*eof_time * 32), NULL, true); + LogTrace_ISO15693(DecodeReader.output, DecodeReader.byteCount, (sof_time * 32), (*eof_time * 32), NULL, true); } return DecodeReader.byteCount; @@ -1155,19 +1186,26 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + BigBuf_free(); clear_trace(); set_tracing(true); // Count of samples received so far, so that we can include timing int samples = 0; - DecodeTag_t DecodeTag = {0}; - uint8_t response[ISO15693_MAX_RESPONSE_LENGTH] = {0}; - DecodeTagInit(&DecodeTag, response, sizeof(response)); +// DecodeTag_t dtag = {0}; +// uint8_t response[ISO15693_MAX_RESPONSE_LENGTH] = {0}; +// DecodeTagInit(&dtag, response, sizeof(response)); + DecodeTag_t *dtag = (DecodeTag_t *)BigBuf_malloc(sizeof(DecodeTag_t)); + uint8_t *response = BigBuf_malloc(ISO15693_MAX_RESPONSE_LENGTH); + DecodeTagInit(dtag, response, ISO15693_MAX_RESPONSE_LENGTH); - DecodeReader_t DecodeReader = {0}; - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH] = {0}; - DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd), jam_search_len, jam_search_string); +// DecodeReader_t dreader = {0}; +// uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH] = {0}; +// DecodeReaderInit(&dreader, cmd, sizeof(cmd), jam_search_len, jam_search_string); + DecodeReader_t *dreader = (DecodeReader_t *)BigBuf_malloc(sizeof(DecodeReader_t)); + uint8_t *cmd = BigBuf_malloc(ISO15693_MAX_COMMAND_LENGTH); + DecodeReaderInit(dreader, cmd, ISO15693_MAX_COMMAND_LENGTH, jam_search_len, jam_search_string); // Print some debug information about the buffer sizes if (DBGLEVEL >= DBG_EXTENDED) { @@ -1178,7 +1216,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE * sizeof(uint16_t)); } - Dbprintf("Sniff started. Press PM3 Button to stop."); + Dbprintf("Starting to sniff. Press PM3 Button to stop."); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE); LED_D_OFF(); @@ -1189,38 +1227,79 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { // The DMA buffer, used to stream samples from the FPGA dmabuf16_t *dma = get_dma16(); - FpgaSetupSscDma((uint8_t*)dma->buf, DMA_BUFFER_SIZE); uint16_t *upTo = dma->buf; + // Setup and start DMA. + if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) { + if (DBGLEVEL > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting"); + switch_off(); + return; + } + bool tag_is_active = false; bool reader_is_active = false; bool expect_tag_answer = false; - uint32_t dma_start_time = 0; - uint16_t max_behindBy = 0; + int dma_start_time = 0; + +// int max_data_len = 0, data_len; // And now we loop, receiving samples. for(;;) { - uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); - if (behindBy > max_behindBy) { - max_behindBy = behindBy; - } - - if (behindBy == 0) continue; samples++; if (samples == 1) { // DMA has transferred the very first data dma_start_time = GetCountSspClk() & 0xfffffff0; } - uint16_t sniffdata = *upTo++; + /* if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + + upTo = dma->buf; + + int register read_bufdata_p = upTo - dma->buf; + int register dma_buf_data_p = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; + if (read_bufdata_p <= dma_buf_data_p) + data_len = dma_buf_data_p - read_bufdata_p; + else + data_len = DMA_BUFFER_SIZE - read_bufdata_p + dma_buf_data_p; + + // test for length of buffer + if (data_len > max_data_len) { + max_data_len = data_len; + if (data_len > (9 * DMA_BUFFER_SIZE / 10)) { + Dbprintf("[!] blew circular buffer! | datalen %u", data_len); + break; + } + } + + // primary buffer was stopped( <-- we lost data! + if (AT91C_BASE_PDC_SSC->PDC_RCR == false) { + AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) dma->buf; + AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE; + } + // secondary buffer sets as primary, secondary buffer was stopped + if (AT91C_BASE_PDC_SSC->PDC_RNCR == false) { + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + } + + + } +*/ + + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); + if (behindBy == 0) continue; + + if (upTo >= dma->buf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dma->buf; // start reading the circular buffer from the beginning if (behindBy > (9 * DMA_BUFFER_SIZE / 10)) { Dbprintf("About to blow circular buffer - aborted! behindBy=%d, samples=%d", behindBy, samples); break; } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; // refresh the DMA Next Buffer and AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers @@ -1232,87 +1311,97 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { } } +/* + WDT_HIT(); + if (BUTTON_PRESS()) { + DbpString("Sniff stopped."); + break; + } +*/ // no need to try decoding reader data if the tag is sending if (tag_is_active == false) { - if (Handle15693SampleFromReader(sniffdata & 0x02, &DecodeReader)) { + if (Handle15693SampleFromReader(sniffdata & 0x02, dreader)) { uint32_t eof_time = dma_start_time + (samples * 16) + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF - if (DecodeReader.byteCount > 0) { + if (dreader->byteCount > 0) { uint32_t sof_time = eof_time - - DecodeReader.byteCount * (DecodeReader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers + - dreader->byteCount * (dreader->Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers - 32 * 16 // time for SOF transfer - 16 * 16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); + LogTrace_ISO15693(dreader->output, dreader->byteCount, (sof_time * 4), (eof_time * 4), NULL, true); } // And ready to receive another command. - DecodeReaderReset(&DecodeReader); + DecodeReaderReset(dreader); // And also reset the demod code, which might have been // false-triggered by the commands from the reader. - DecodeTagReset(&DecodeTag); + DecodeTagReset(dtag); reader_is_active = false; expect_tag_answer = true; - } else if (Handle15693SampleFromReader(sniffdata & 0x01, &DecodeReader)) { + } else if (Handle15693SampleFromReader(sniffdata & 0x01, dreader)) { uint32_t eof_time = dma_start_time + (samples * 16) + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF - if (DecodeReader.byteCount > 0) { + if (dreader->byteCount > 0) { uint32_t sof_time = eof_time - - DecodeReader.byteCount * (DecodeReader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers + - dreader->byteCount * (dreader->Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers - 32 * 16 // time for SOF transfer - 16 * 16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); + LogTrace_ISO15693(dreader->output, dreader->byteCount, (sof_time * 4), (eof_time * 4), NULL, true); } // And ready to receive another command - DecodeReaderReset(&DecodeReader); + DecodeReaderReset(dreader); // And also reset the demod code, which might have been // false-triggered by the commands from the reader. - DecodeTagReset(&DecodeTag); + DecodeTagReset(dtag); reader_is_active = false; expect_tag_answer = true; } else { - reader_is_active = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); + reader_is_active = (dreader->state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); } } - if (!reader_is_active && expect_tag_answer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet - if (Handle15693SamplesFromTag(sniffdata >> 2, &DecodeTag)) { + if (reader_is_active == false && expect_tag_answer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + + if (Handle15693SamplesFromTag(sniffdata >> 2, dtag)) { uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF - if (DecodeTag.lastBit == SOF_PART2) { + if (dtag->lastBit == SOF_PART2) { eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) } uint32_t sof_time = eof_time - - DecodeTag.len * 8 * 8 * 16 // time for byte transfers + - dtag->len * 8 * 8 * 16 // time for byte transfers - (32 * 16) // time for SOF transfer - - (DecodeTag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer + - (dtag->lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer - LogTrace(DecodeTag.output, DecodeTag.len, (sof_time * 4), (eof_time * 4), NULL, false); + LogTrace_ISO15693(dtag->output, dtag->len, (sof_time * 4), (eof_time * 4), NULL, false); // And ready to receive another response. - DecodeTagReset(&DecodeTag); - DecodeReaderReset(&DecodeReader); + DecodeTagReset(dtag); + DecodeReaderReset(dreader); expect_tag_answer = false; tag_is_active = false; } else { - tag_is_active = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); + tag_is_active = (dtag->state >= STATE_TAG_RECEIVING_DATA); } } } + FpgaDisableTracing(); + switch_off(); DbpString("Sniff statistics:"); Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", expect_tag_answer, tag_is_active, reader_is_active); - Dbprintf(" DecodeTag State: %d", DecodeTag.state); - Dbprintf(" DecodeTag byteCnt: %d", DecodeTag.len); - Dbprintf(" DecodeTag posCount: %d", DecodeTag.posCount); - Dbprintf(" DecodeReader State: %d", DecodeReader.state); - Dbprintf(" DecodeReader byteCnt: %d", DecodeReader.byteCount); - Dbprintf(" DecodeReader posCount: %d", DecodeReader.posCount); + Dbprintf(" DecodeTag State: %d", dtag->state); + Dbprintf(" DecodeTag byteCnt: %d", dtag->len); + Dbprintf(" DecodeTag posCount: %d", dtag->posCount); + Dbprintf(" DecodeReader State: %d", dreader->state); + Dbprintf(" DecodeReader byteCnt: %d", dreader->byteCount); + Dbprintf(" DecodeReader posCount: %d", dreader->posCount); Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); - Dbprintf(" Max behindBy: %d", max_behindBy); +// Dbprintf(" Max behindBy: %d", max_behindBy); } // Initialize Proxmark3 as ISO15693 reader @@ -1386,7 +1475,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, &start_time); uint32_t end_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF - LogTrace(send, sendlen, (start_time * 4), (end_time * 4), NULL, true); + LogTrace_ISO15693(send, sendlen, (start_time * 4), (end_time * 4), NULL, true); int res = 0; if (recv != NULL) { @@ -1401,7 +1490,7 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, &start_time); uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // substract the 4 padding bits after EOF - LogTrace(NULL, 0, (start_time * 4), (end_time * 4), NULL, true); + LogTrace_ISO15693(NULL, 0, (start_time * 4), (end_time * 4), NULL, true); int res = 0; if (recv != NULL) { @@ -1639,7 +1728,7 @@ void SimTagIso15693(uint8_t *uid) { bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); - LogTrace(resp_inv, CMD_INV_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); + LogTrace_ISO15693(resp_inv, CMD_INV_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); chip_state = SELECTED; } diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index fcca9491c..d650ab0ef 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -27,7 +27,7 @@ void Iso15693InitReader(void); void Iso15693InitTag(void); void CodeIso15693AsReader(uint8_t *cmd, int n); void CodeIso15693AsTag(uint8_t *cmd, size_t len); - + void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow); int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time); From ca14b92dd560e53b208b0f483595457ee006d7d5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 21 Jul 2020 10:53:19 +0200 Subject: [PATCH 095/139] iclass info - some cards configured to take all available mem. ie no AA2 area. --- client/src/cmdhficlass.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 29c5eee98..14a796743 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -512,7 +512,10 @@ static void mem_app_config(const picopass_hdr *hdr) { PrintAndLogEx(INFO, "------ " _CYAN_("Memory") " ------"); PrintAndLogEx(INFO, " %u KBits/%u App Areas (%u bytes)", kb, app_areas, app2_limit * 8); PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit , app1_limit + 5, app1_limit + 5); - PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit); + if (app1_limit <= app2_limit) + PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit); + else + PrintAndLogEx(INFO, " AA1 is configured to take all available space"); PrintAndLogEx(INFO, "------ " _CYAN_("KeyAccess") " ------"); PrintAndLogEx(INFO, " Kd = Debit key (AA1), Kc = Credit key (AA2)"); From 1f2c03ce8a76a9ef12f93f6a07829a77766b57d7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 21 Jul 2020 13:00:52 +0200 Subject: [PATCH 096/139] iclass rdbl textual --- client/src/cmdhficlass.c | 62 +++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 14a796743..916ddd303 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -377,6 +377,14 @@ static inline uint32_t leadingzeros(uint64_t a) { #else return 0; #endif +} +static inline uint32_t countones(uint64_t a) { +#if defined __GNUC__ + return __builtin_popcountll(a); +#else + return 0; +#endif + } // iclass card descriptors @@ -1943,8 +1951,10 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo return PM3_ESOFT; } + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, " block %02X : " _GREEN_("%s"), blockno, sprint_hex(result->blockdata, sizeof(result->blockdata))); - + PrintAndLogEx(NORMAL, ""); + if (memcmp(result->blockdata, empty, 8) == 0) return PM3_SUCCESS; @@ -1962,14 +1972,19 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo break; } case 7: { - PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + PrintAndLogEx(INFO, "----------------------------- " _CYAN_("cardhelper") " -----------------------------"); uint8_t dec_data[8]; + uint64_t a = bytes_to_num(result->blockdata, 8); - if (leadingzeros(a) < 12) { - PrintAndLogEx(INFO, "data looks encrypted, false positive is possible"); + bool starts = (leadingzeros(a) < 12); + bool ones = (countones(a) > 16 && countones(a) < 48); + + if (starts && ones) { + PrintAndLogEx(INFO, "data looks encrypted, False Positives " _YELLOW_("ARE") " possible"); Decrypt(result->blockdata, dec_data); PrintAndLogEx(SUCCESS, "decrypted : " _GREEN_("%s"), sprint_hex(dec_data, sizeof(dec_data))); } else { + memcpy(dec_data, result->blockdata, sizeof(dec_data)); PrintAndLogEx(INFO, "data looks unencrypted, trying to decode"); } @@ -1990,14 +2005,14 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo i &= 0x3C; PrintAndLogEx(SUCCESS, " bin : %s", binstr + i); - PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, "------------------------------ " _CYAN_("wiegand") " -------------------------------"); wiegand_message_t packed = initialize_message_object(top, mid, bot); HIDTryUnpack(&packed, true); } else { PrintAndLogEx(INFO, "no credential found"); } - - PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + PrintAndLogEx(INFO, "----------------------------------------------------------------------"); break; } } @@ -2008,8 +2023,8 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { uint8_t blockno = 0; uint8_t keyType = 0x88; //debit key uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t keyNbr = 0; - uint8_t dataLen = 0; + uint8_t key_idx = 0; + uint8_t key_len = 0; char tempStr[50] = {0}; bool got_blockno = false; bool elite = false; @@ -2029,7 +2044,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { cmdp += 2; break; case 'c': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("CREDIT")); + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("KC credit")); keyType = 0x18; cmdp++; break; @@ -2040,20 +2055,19 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { break; case 'k': auth = true; - dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { - errors = param_gethex(tempStr, 0, KEY, dataLen); - } else if (dataLen == 1) { - keyNbr = param_get8(Cmd, cmdp + 1); - if (keyNbr < ICLASS_KEYS_MAX) { - PrintAndLogEx(SUCCESS, "Using key[%d] %s", keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8)); - memcpy(KEY, iClass_Key_Table[keyNbr], 8); + key_len = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); + if (key_len == 16) { + errors = param_gethex(tempStr, 0, KEY, key_len); + } else if (key_len == 1) { + key_idx = param_get8(Cmd, cmdp + 1); + if (key_idx < ICLASS_KEYS_MAX) { + memcpy(KEY, iClass_Key_Table[key_idx], 8); } else { - PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); + PrintAndLogEx(WARNING, "\nERROR: key index is invalid\n"); errors = true; } } else { - PrintAndLogEx(WARNING, "\nERROR: Credit Key is incorrect length\n"); + PrintAndLogEx(WARNING, "\nERROR: incorrect key length\n"); errors = true; } cmdp += 2; @@ -2078,6 +2092,14 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { if (errors) return usage_hf_iclass_readblock(); + if (verbose) { + if (key_len == 1) + PrintAndLogEx(SUCCESS, "Using key[%d] %s", key_idx, sprint_hex(KEY, 8)); + else + PrintAndLogEx(SUCCESS, "Using key %s", sprint_hex(KEY, 8)); + } + + if (auth == false) PrintAndLogEx(WARNING, "warning: no authentication used with read, only a few specific blocks can be read accurately without authentication."); From a85fd925b71169b657d3cfbc8df09e58a374c56d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 21 Jul 2020 13:01:19 +0200 Subject: [PATCH 097/139] colors to wiegand decode --- client/src/wiegand_formats.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/wiegand_formats.c b/client/src/wiegand_formats.c index 7c25cd7ff..e04fc29f0 100644 --- a/client/src/wiegand_formats.c +++ b/client/src/wiegand_formats.c @@ -671,21 +671,21 @@ static void HIDDisplayUnpackedCard(wiegand_card_t *card, const cardformat_t form PrintAndLogEx(SUCCESS, " Parity: %s",card->ParityValid ? "Valid" : "Invalid"); */ - char s[80] = {0}; + char s[110] = {0}; if (format.Fields.hasFacilityCode) - snprintf(s, sizeof(s), "FC: %u", card->FacilityCode); + snprintf(s, sizeof(s), "FC: " _GREEN_("%u"), card->FacilityCode); if (format.Fields.hasCardNumber) - snprintf(s + strlen(s), sizeof(s) - strlen(s), " CN: %" PRIu64, card->CardNumber); + snprintf(s + strlen(s), sizeof(s) - strlen(s), " CN: " _GREEN_("%"PRIu64), card->CardNumber); if (format.Fields.hasIssueLevel) - snprintf(s + strlen(s), sizeof(s) - strlen(s), " Issue %u", card->IssueLevel); + snprintf(s + strlen(s), sizeof(s) - strlen(s), " Issue " _GREEN_("%u"), card->IssueLevel); if (format.Fields.hasOEMCode) - snprintf(s + strlen(s), sizeof(s) - strlen(s), " OEM: %u", card->OEM); + snprintf(s + strlen(s), sizeof(s) - strlen(s), " OEM: " _GREEN_("%u"), card->OEM); if (format.Fields.hasParity) - snprintf(s + strlen(s), sizeof(s) - strlen(s), " parity: %s", card->ParityValid ? "valid" : "invalid"); + snprintf(s + strlen(s), sizeof(s) - strlen(s), " parity: %s", card->ParityValid ? _GREEN_("valid") : _RED_("invalid")); PrintAndLogEx(SUCCESS, "[%s] - %s; %s", format.Name, format.Descrp, s); } From 06c02d3b404f9a6bd46968b997ed16bf1d045338 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 21 Jul 2020 14:09:05 +0200 Subject: [PATCH 098/139] added iclass esave, textual --- client/src/cmdhficlass.c | 199 +++++++++++++++++++++++++++++++-------- 1 file changed, 159 insertions(+), 40 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 916ddd303..6a99c0db7 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -51,8 +51,8 @@ static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { }; static int usage_hf_iclass_sim(void) { - PrintAndLogEx(NORMAL, "Simulate a iclass legacy/standard tag\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass sim [h]