]> cvs.zerfleddert.de Git - proxmark3-svn/commitdiff
Merge branch 'master' of https://github.com/Proxmark/proxmark3
authoriceman1001 <iceman@iuse.se>
Thu, 18 Jun 2015 07:51:30 +0000 (09:51 +0200)
committericeman1001 <iceman@iuse.se>
Thu, 18 Jun 2015 07:51:30 +0000 (09:51 +0200)
Conflicts:
armsrc/iso14443a.c
armsrc/mifarecmd.c
armsrc/mifareutil.c
armsrc/mifareutil.h
client/Makefile
client/cmddata.c
client/cmdhfmf.c
client/cmdhfmfu.c
client/lualibs/utils.lua
client/scripting.c
client/scripts/didump.lua
client/util.c
client/util.h
common/crc16.c
common/lfdemod.c
common/sha1.c

114 files changed:
README.txt
armsrc/BigBuf.c
armsrc/LCD.c
armsrc/Makefile
armsrc/appmain.c
armsrc/apps.h
armsrc/crapto1.c
armsrc/des.c
armsrc/des.h
armsrc/desfire_crypto.c [new file with mode: 0644]
armsrc/desfire_crypto.h [new file with mode: 0644]
armsrc/desfire_key.c [new file with mode: 0644]
armsrc/desfire_key.h [new file with mode: 0644]
armsrc/epa.c
armsrc/fpgaloader.c
armsrc/hitag2.c
armsrc/iclass.c
armsrc/iso14443.c [deleted file]
armsrc/iso14443a.c
armsrc/iso14443a.h
armsrc/iso14443b.c [new file with mode: 0644]
armsrc/legicrf.c
armsrc/lfops.c
armsrc/mifarecmd.c
armsrc/mifarecmd.h
armsrc/mifaredesfire.c [new file with mode: 0644]
armsrc/mifaredesfire.h [new file with mode: 0644]
armsrc/mifaresniff.h
armsrc/mifareutil.c
armsrc/mifareutil.h
bootrom/bootrom.c
client/Makefile
client/cmdcrc.c [new file with mode: 0644]
client/cmdcrc.h [new file with mode: 0644]
client/cmddata.c
client/cmdhf.c
client/cmdhf.h
client/cmdhf14a.c
client/cmdhf14a.h
client/cmdhf14b.c
client/cmdhf14b.h
client/cmdhf15.c
client/cmdhfdes.c [new file with mode: 0644]
client/cmdhfdes.h [new file with mode: 0644]
client/cmdhfepa.c
client/cmdhficlass.c
client/cmdhfmf.c
client/cmdhfmf.h
client/cmdhfmfdes.c [new file with mode: 0644]
client/cmdhfmfdes.h [new file with mode: 0644]
client/cmdhfmfdesfire.c [new file with mode: 0644]
client/cmdhfmfdesfire.h [new file with mode: 0644]
client/cmdhfmfu.c
client/cmdhftopaz.c [new file with mode: 0644]
client/cmdhftopaz.h [new file with mode: 0644]
client/cmdlf.c
client/cmdlfawid26.c [new file with mode: 0644]
client/cmdlfawid26.h [new file with mode: 0644]
client/cmdlfem4x.c
client/cmdlft55xx.c
client/cmdmain.c
client/cmdmain.h
client/flasher.c
client/loclass/cipher.c
client/loclass/fileutils.h
client/loclass/hash1_brute.c [new file with mode: 0644]
client/loclass/hash1_brute.h [new file with mode: 0644]
client/lualibs/commands.lua
client/lualibs/html_dumplib.lua
client/lualibs/utils.lua
client/mifarehost.c
client/nonce2key/crapto1.c
client/nonce2key/nonce2key.c
client/nonce2key/nonce2key.h
client/obj/reveng/.gitignore [new file with mode: 0644]
client/platforms/.gitignore [new file with mode: 0644]
client/proxmark3.c
client/proxmark3.h
client/reveng/bmpbit.c [new file with mode: 0644]
client/reveng/cli.c [new file with mode: 0644]
client/reveng/config.h [new file with mode: 0644]
client/reveng/getopt.c [new file with mode: 0644]
client/reveng/getopt.h [new file with mode: 0644]
client/reveng/model.c [new file with mode: 0644]
client/reveng/poly.c [new file with mode: 0644]
client/reveng/reveng.c [new file with mode: 0644]
client/reveng/reveng.h [new file with mode: 0644]
client/scripting.c
client/scripts/didump.lua
client/scripts/e.lua [new file with mode: 0644]
client/scripts/test.lua [deleted file]
client/scripts/test_t55x7_ask.lua
client/ui.c
client/ui.h
client/util.c
client/util.h
common/Makefile.common
common/crc16.c
common/desfire.h [new file with mode: 0644]
common/iso14443crc.c
common/iso14443crc.h
common/iso15693tools.c
common/legic_prng.c
common/lfdemod.c
common/protocols.h
common/sha1.c
cp2tau [new file with mode: 0644]
fpga/fpga_hf.bit
fpga/hi_read_rx_xcorr.v
iceman.txt [new file with mode: 0644]
include/mifare.h
include/usb_cmd.h
tools/mfkey/mfkey32.c
tools/mkversion.pl

index 1a4ddb6d0e693b3192f7270a5b8326d75b4fd86a..e510e792059a09ba4d15325e23f1aa6f86f6a6ab 100644 (file)
@@ -1,87 +1,70 @@
+The iceman fork.
+
 NOTICE:
-(2014-03-26)
-This is now the official Proxmark repository!
 
-INTRODUCTION:
+The official Proxmark repository is found here: https://github.com/Proxmark/proxmark3
 
-The proxmark3 is a powerful general purpose RFID tool, the size of a deck
-of cards, designed to snoop, listen and emulate everything from
-Low Frequency (125kHz) to High Frequency (13.56MHz) tags.
 
-This repository contains enough software, logic (for the FPGA), and design
-documentation for the hardware that you could, at least in theory,
-do something useful with a proxmark3.
+NEWS:      
 
-RESOURCES:
+Whats in this fork?  I have scraped the web for different enhancements to the PM3 source code and not all of them ever found their way to the master branch. 
+Among the stuff is
 
-   * This repository!
-      https://github.com/Proxmark/proxmark3
-      
-   * The Wiki
-      https://github.com/Proxmark/proxmark3/wiki
-      
-   * The GitHub page
-      http://proxmark.github.io/proxmark3/
-      
-   * The Forum
-      http://www.proxmark.org/forum
-      
-   * The IRC chanel
-       irc.freenode.org #proxmark3
-       -or-
-       http://webchat.freenode.net/?channels=#proxmark3
-   
-DEVELOPMENT:
+       * Jonor's hf 14a raw timing patch
+       * Piwi's updates. (usually gets into the master)
+       * Holiman's iclass, (usually gets into the master)
+       * Marshmellow's LF fixes
+       * Midnitesnake's Ultralight,  Ultralight-c enhancements
+       * Izsh's lf peak modification / iir-filtering
+       * Aspers's tips and tricks from inside the PM3-gui-tool, settings.xml and other stuff.
+       * My own desfire, Ultralight extras, LF T55xx enhancements, bugs fixes (filelength, hf mf commands ), TNP3xxx lua scripts,  Awid26,  skidata scripts (will come)
+       * other obscure patches like for the sammy-mode,  (offline you know), tagidentifications, defaultkeys. 
+       
+Give me a hint, and I'll see if I can't merge in the stuff you have. 
 
-The tools required to build  or run the project will vary depending on
-your operating system. Please refer to the Wiki for details.
+I don't actually know how to make small pull-request to github :( and that is the number one reason for me not pushing a lot of things back to the PM3 master.
+       
+PM3 GUI:
 
-   * https://github.com/Proxmark/proxmark3/wiki
+I do tend to rename and move stuff around, the official PM3-GUI from Gaucho will not work so well. *sorry*     
+
+         
+DEVELOPMENT:
 
-OBTAINING HARDWARE:
+This fork is adjusted to compile on windows/mingw environment with Qt5.3.1 & GCC 4.8
+For people with linux you will need to patch some source code and some small change to one makefile.  If you are lazy, you google the forum and find asper's or holimans makefile or you find your solution below.
+
+Common errors linux/macOS finds
+Error:
+       * loclass/fileutils.c:15:2: warning: implicit declaration of function \91_stat\92 [-Wimplicit-function-declaration]
+Solution:
+       * Remove the "unscore" sign.   In linux you use without underscore, in windows you need a underscore. 
+       
+Error:  
+       * \client\makefile  the parameter -lgdi32 
+Solution:
+       * Remove parameter.
+       
+Error:  
+       * Using older Qt4.6 gives compilation errors.  
+Solution
+       * Upgrade to Qt5.3.1 
+       OR 
+       * Change these two line in  \client\makefile
+               CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -I$(QTDIR)/include/QtWidgets  -I/mingw/include
+               QTLDLIBS = -L$(QTDIR)/lib  -lQt5Core -lQt5Gui -lQt5Widgets 
+               
+               TO
+               
+               CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
+               QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
+       
+
+An old Qt4 version makefile is found here: http://www.icesql.se/proxmark3/code/linuxmakefile.txt  but this one doesn't have all new files in it. So I don't recommend it.
 
 The Proxmark 3 is available for purchase (assembled and tested) from the
 following locations:
 
-   * http://proxmark3.com/
-   * http://www.xfpga.com/
-
-Most of the ultra-low-volume contract assemblers could put
-something like this together with a reasonable yield. A run of around
-a dozen units is probably cost-effective. The BOM includes (possibly-
-outdated) component pricing, and everything is available from Digikey
-and the usual distributors.
-
-If you've never assembled a modern circuit board by hand, then this is
-not a good place to start. Some of the components (e.g. the crystals)
-must not be assembled with a soldering iron, and require hot air.
-
-The schematics are included; the component values given are not
-necessarily correct for all situations, but it should be possible to do
-nearly anything you would want with appropriate population options.
-
-The printed circuit board artwork is also available, as Gerbers and an
-Excellon drill file.
-
-
-LICENSING:
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-
-Jonathan Westhues
-user jwesthues, at host cq.cx
 
-May 2007, Cambridge MA
+January 2015, Sweden
+iceman at host iuse.se
\ No newline at end of file
index 703ade658da348db04f80b2824269a32c738cb55..51fafdebc22b3b872a8a6b1cba3a9f34bfc2567e 100644 (file)
@@ -171,18 +171,19 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_
        traceLen += iLen;
 
        // parity bytes
-       if (parity != NULL && iLen != 0) {
-               memcpy(trace + traceLen, parity, num_paritybytes);
+       if (iLen != 0) {
+               if (parity != NULL) {
+                       memcpy(trace + traceLen, parity, num_paritybytes);
+               } else {
+                       memset(trace + traceLen, 0x00, num_paritybytes);
+               }
        }
        traceLen += num_paritybytes;
 
-       if(traceLen +4 < max_traceLen)
-       {       //If it hadn't been cleared, for whatever reason..
-               memset(trace+traceLen,0x44, 4);
-       }
-
        return TRUE;
 }
+
+
 int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int readerToTag)
 {
        /**
@@ -224,6 +225,8 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP
 
        return TRUE;
 }
+
+
 // Emulator memory
 uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length){
        uint8_t* mem = BigBuf_get_EM_addr();
index 65d64ac90ed9d87c831a568020669d824d98e98f..87be5e3aec468e64d33de09cad26bada7fb83e29 100644 (file)
@@ -6,7 +6,7 @@
 // LCD code
 //-----------------------------------------------------------------------------
 
-#include "proxmark3.h"
+#include "../include/proxmark3.h"
 #include "apps.h"
 #include "LCD.h"
 #include "fonts.h"
index 899b03075af35d1d51a0d61f318d1028959ae09f..83a4ab9494c7f34497c6f154bf0b156510f66a84 100644 (file)
@@ -17,8 +17,8 @@ APP_CFLAGS    = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_
 SRC_LF = lfops.c hitag2.c lfsampling.c
 SRC_ISO15693 = iso15693.c iso15693tools.c
 SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
-SRC_ISO14443b = iso14443.c
-SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c 
+SRC_ISO14443b = iso14443b.c
+SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c desfire_key.c desfire_crypto.c mifaredesfire.c
 SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c 
 
 THUMBSRC = start.c \
index c226c726398dd822b85f287aadb8d47be421e7e3..6eedcdd619e569e7b7dbaa2ab69ec813d5c2e7f8 100644 (file)
 #include "util.h"
 #include "printf.h"
 #include "string.h"
-
 #include <stdarg.h>
-
 #include "legicrf.h"
 #include <hitag2.h>
 #include "lfsampling.h"
 #include "BigBuf.h"
+
 #ifdef WITH_LCD
  #include "LCD.h"
 #endif
@@ -180,7 +179,7 @@ void MeasureAntennaTuning(void)
        int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0 
        int vLf125 = 0, vLf134 = 0, vHf = 0;    // in mV
 
-       LED_B_ON();
+  LED_B_ON();
 
 /*
  * Sweeps the useful LF range of the proxmark from
@@ -212,7 +211,7 @@ void MeasureAntennaTuning(void)
 
        for (i=18; i >= 0; i--) LF_Results[i] = 0;
        
-       LED_A_ON();
+  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);
@@ -221,9 +220,9 @@ void MeasureAntennaTuning(void)
 
        cmd_send(CMD_MEASURED_ANTENNA_TUNING, vLf125 | (vLf134<<16), vHf, peakf | (peakv<<16), LF_Results, 256);
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       LED_A_OFF();
-       LED_B_OFF();
-       return;
+  LED_A_OFF();
+  LED_B_OFF();
+  return;
 }
 
 void MeasureAntennaTuningHf(void)
@@ -370,7 +369,7 @@ void SamyRun()
        for (;;)
        {
                usb_poll();
-    WDT_HIT();
+               WDT_HIT();
 
                // Was our button held down or pressed?
                int button_pressed = BUTTON_HELD(1000);
@@ -640,7 +639,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
 {
        UsbCommand *c = (UsbCommand *)packet;
 
-//  Dbprintf("received %d bytes, with command: 0x%04x and args: %d %d %d",len,c->cmd,c->arg[0],c->arg[1],c->arg[2]);
+  //Dbprintf("received %d bytes, with command: 0x%04x and args: %d %d %d",len,c->cmd,c->arg[0],c->arg[1],c->arg[2]);
   
        switch(c->cmd) {
 #ifdef WITH_LF
@@ -804,7 +803,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
 
 #ifdef WITH_ISO14443a
                case CMD_SNOOP_ISO_14443a:
-                       SnoopIso14443a(c->arg[0]);
+                       SniffIso14443a(c->arg[0]);
                        break;
                case CMD_READER_ISO_14443a:
                        ReaderIso14443a(c);
@@ -817,8 +816,12 @@ void UsbPacketReceived(uint8_t *packet, int len)
                        EPA_PACE_Collect_Nonce(c);
                        break;
                        
+               // case CMD_EPA_:
+               //      EpaFoo(c);
+               // break;
+                       
                case CMD_READER_MIFARE:
-                       ReaderMifare(c->arg[0]);
+            ReaderMifare(c->arg[0]);
                        break;
                case CMD_MIFARE_READBL:
                        MifareReadBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
@@ -890,6 +893,28 @@ void UsbPacketReceived(uint8_t *packet, int len)
                        SniffMifare(c->arg[0]);
                        break;
 
+               //mifare desfire
+               case CMD_MIFARE_DESFIRE_READBL: break;
+               case CMD_MIFARE_DESFIRE_WRITEBL: break;
+               case CMD_MIFARE_DESFIRE_AUTH1:
+                       MifareDES_Auth1(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
+                       break;
+               case CMD_MIFARE_DESFIRE_AUTH2:
+                       //MifareDES_Auth2(c->arg[0],c->d.asBytes);
+                       break;
+               case CMD_MIFARE_DES_READER:
+                       //readermifaredes(c->arg[0], c->arg[1], c->d.asBytes);
+                       break;
+               case CMD_MIFARE_DESFIRE_INFO:
+                       MifareDesfireGetInformation();
+                       break;
+               case CMD_MIFARE_DESFIRE:
+                       MifareSendCommand(c->arg[0], c->arg[1], c->d.asBytes);
+                       break;
+
+               case CMD_MIFARE_COLLECT_NONCES:
+                       MifareCollectNonces(c->arg[0], c->arg[1]);
+                       break;
 #endif
 
 #ifdef WITH_ICLASS
@@ -904,7 +929,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
                        ReaderIClass(c->arg[0]);
                        break;
                case CMD_READER_ICLASS_REPLAY:
-                   ReaderIClass_Replay(c->arg[0], c->d.asBytes);
+                       ReaderIClass_Replay(c->arg[0], c->d.asBytes);
                        break;
        case CMD_ICLASS_EML_MEMSET:
                        emlSet(c->d.asBytes,c->arg[0], c->arg[1]);
@@ -1037,7 +1062,7 @@ void  __attribute__((noreturn)) AppMain(void)
        LED_A_OFF();
 
        // Init USB device
-  usb_enable();
+       usb_enable();
 
        // The FPGA gets its clock from us from PCK0 output, so set that up.
        AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0;
@@ -1067,12 +1092,12 @@ void  __attribute__((noreturn)) AppMain(void)
        size_t rx_len;
   
        for(;;) {
-    if (usb_poll()) {
-      rx_len = usb_read(rx,sizeof(UsbCommand));
-      if (rx_len) {
-        UsbPacketReceived(rx,rx_len);
-      }
-    }
+               if (usb_poll()) {
+                       rx_len = usb_read(rx,sizeof(UsbCommand));
+                       if (rx_len) {
+                               UsbPacketReceived(rx,rx_len);
+                       }
+               }
                WDT_HIT();
 
 #ifdef WITH_LF
index 6360b664b82f49528570d2ec00b1f88a93cbd258..9068202feb514899ae4301fce64feef64f23cf7b 100644 (file)
 
 #include <stdint.h>
 #include <stddef.h>
-#include "common.h"
-#include "hitag2.h"
-#include "mifare.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <strings.h>
 #include "../common/crc32.h"
+#include "../common/lfdemod.h"
 #include "BigBuf.h"
+#include "../include/hitag2.h"
+#include "../include/mifare.h"
+//#include "des.h"
+//#include "aes.h"
+#include "desfire.h"
+
 
 extern const uint8_t OddByteParity[256];
 extern int rsamples;   // = 0;
@@ -133,6 +141,7 @@ void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int
 void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMode);
 void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode );
 void T55xxReadTrace(void);
+void TurnReadLFOn();
 int DemodPCF7931(uint8_t **outBlocks);
 int IsBlock0PCF7931(uint8_t *Block);
 int IsBlock1PCF7931(uint8_t *Block);
@@ -148,7 +157,7 @@ void RAMFUNC SnoopIso14443(void);
 void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
 
 /// iso14443a.h
-void RAMFUNC SnoopIso14443a(uint8_t param);
+void RAMFUNC SniffIso14443a(uint8_t param);
 void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data);
 void ReaderIso14443a(UsbCommand * c);
 // Also used in iclass.c
@@ -185,6 +194,8 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
 void MifareCIdent();  // is "magic chinese" card?
 void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
 
+void MifareCollectNonces(uint32_t arg0, uint32_t arg1);
+
 //desfire
 void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain);
 void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);                                    
@@ -202,6 +213,17 @@ void       OnError(uint8_t reason);
 
 
 
+// desfire_crypto.h
+void   *mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, off_t offset, int communication_settings);
+void    *mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbytes, int communication_settings);
+void    mifare_cypher_single_block (desfirekey_t  key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size);
+void    mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation);
+size_t  key_block_size (const desfirekey_t  key);
+size_t  padded_data_length (const size_t nbytes, const size_t block_size);
+size_t  maced_data_length (const desfirekey_t  key, const size_t nbytes);
+size_t  enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings);
+void    cmac_generate_subkeys (desfirekey_t key);
+void    cmac (const desfirekey_t  key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac);
 
 
 /// iso15693.h
index bcd3117114147a5287eb6c0d694f21abb239d501..2fdeb924241ee0ac30bd631027286c4711c25771 100644 (file)
@@ -1,21 +1,21 @@
 /*  crapto1.c\r
 \r
-       This program is free software; you can redistribute it and/or\r
-       modify it under the terms of the GNU General Public License\r
-       as published by the Free Software Foundation; either version 2\r
-       of the License, or (at your option) any later version.\r
-\r
-       This program is distributed in the hope that it will be useful,\r
-       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-       GNU General Public License for more details.\r
-\r
-       You should have received a copy of the GNU General Public License\r
-       along with this program; if not, write to the Free Software\r
-       Foundation, Inc., 51 Franklin Street, Fifth Floor,\r
-       Boston, MA  02110-1301, US$\r
-\r
-       Copyright (C) 2008-2008 bla <blapost@gmail.com>\r
+    This program is free software; you can redistribute it and/or\r
+    modify it under the terms of the GNU General Public License\r
+    as published by the Free Software Foundation; either version 2\r
+    of the License, or (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor,\r
+    Boston, MA  02110-1301, US$\r
+\r
+    Copyright (C) 2008-2008 bla <blapost@gmail.com>\r
 */\r
 #include "crapto1.h"\r
 #include <stdlib.h>\r
@@ -24,9 +24,9 @@
 static uint8_t filterlut[1 << 20];\r
 static void __attribute__((constructor)) fill_lut()\r
 {\r
-       uint32_t i;\r
-       for(i = 0; i < 1 << 20; ++i)\r
-               filterlut[i] = filter(i);\r
+        uint32_t i;\r
+        for(i = 0; i < 1 << 20; ++i)\r
+                filterlut[i] = filter(i);\r
 }\r
 #define filter(x) (filterlut[(x) & 0xfffff])\r
 #endif\r
@@ -152,12 +152,12 @@ recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks,
                eks >>= 1;\r
                in >>= 2;\r
                extend_table(o_head, &o_tail, oks & 1, LF_POLY_EVEN << 1 | 1,\r
-                                LF_POLY_ODD << 1, 0);\r
+                            LF_POLY_ODD << 1, 0);\r
                if(o_head > o_tail)\r
                        return sl;\r
 \r
                extend_table(e_head, &e_tail, eks & 1, LF_POLY_ODD,\r
-                                LF_POLY_EVEN << 1 | 1, in & 3);\r
+                            LF_POLY_EVEN << 1 | 1, in & 3);\r
                if(e_head > e_tail)\r
                        return sl;\r
        }\r
@@ -170,7 +170,7 @@ recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks,
                        o_tail = binsearch(o_head, o = o_tail);\r
                        e_tail = binsearch(e_head, e = e_tail);\r
                        sl = recover(o_tail--, o, oks,\r
-                                        e_tail--, e, eks, rem, sl, in);\r
+                                    e_tail--, e, eks, rem, sl, in);\r
                }\r
                else if(*o_tail > *e_tail)\r
                        o_tail = binsearch(o_head, o_tail) - 1;\r
@@ -424,7 +424,7 @@ uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd)
  */\r
 static struct Crypto1State*\r
 check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],\r
-               uint32_t odd, uint32_t even, struct Crypto1State* sl)\r
+               uint32_t odd, uint32_t even, struct Crypto1State* sl)\r
 {\r
        uint32_t ks1, nr, ks2, rr, ks3, c, good = 1;\r
 \r
@@ -464,12 +464,12 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8])
 \r
        odd = lfsr_prefix_ks(ks, 1);\r
        even = lfsr_prefix_ks(ks, 0);\r
-\r
+       \r
        s = statelist = malloc((sizeof *statelist) << 20);\r
        if(!s || !odd || !even) {\r
                free(statelist);\r
                statelist = 0;\r
-               goto out;\r
+                goto out;\r
        }\r
 \r
        for(o = odd; *o + 1; ++o)\r
index a81df9c8d4234c7bd2bd5432b0a503f9a1c6ba36..172b32358dbf38aa96f30a25dcd0e118105d1634 100644 (file)
@@ -378,59 +378,59 @@ void tdes_dec(void* out, void* in, const uint8_t* key){
        des_dec(out, out, (uint8_t*)key + 0);
 }
 
-void tdes_2key_enc(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]){
+ void tdes_2key_enc(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]){
 
        if( length % 8 ) return; 
-       
+
        uint8_t i;
        uint8_t* tin = (uint8_t*) in;
        uint8_t* tout = (uint8_t*) out;
        
        while( length > 0 )
        {
-               for ( i = 0; i < 8; i++ )
-                       tout[i] = (unsigned char)(tin[i] ^ iv[i]);
-
+               for( i = 0; i < 8; i++ )
+                               tout[i] = (unsigned char)( tin[i] ^ iv[i] );
+               
                des_enc(tout,  tin, (uint8_t*)key + 0);
                des_dec(tout, tout, (uint8_t*)key + 8);
                des_enc(tout, tout, (uint8_t*)key + 0);
                
-               memcpy(iv, tout, 8);
-
+               memcpy( iv, tout, 8 );
+               
                tin  += 8;
                tout += 8;
                length -= 8;
        }
-}
-
-void tdes_2key_dec(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]){
+ }
+ void tdes_2key_dec(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]){
        
        if( length % 8 ) return; 
 
        uint8_t i;
        unsigned char temp[8];
+
        uint8_t* tin = (uint8_t*) in;
        uint8_t* tout = (uint8_t*) out;
        
        while( length > 0 )
        {
-               memcpy(temp, tin, 8);
-
+               memcpy( temp, tin, 8 );
+               
                des_dec(tout,  tin, (uint8_t*)key + 0);
                des_enc(tout, tout, (uint8_t*)key + 8);
                des_dec(tout, tout, (uint8_t*)key + 0);          
 
-               for (i = 0; i < 8; i++)
-                       tout[i] = (unsigned char)(tout[i] ^ iv[i]);
+               for( i = 0; i < 8; i++ )
+                       tout[i] = (unsigned char)( tout[i] ^ iv[i] );
 
-               memcpy(iv, temp, 8);
+               memcpy( iv, temp, 8 );
                
                tin  += 8;
                tout += 8;
                length -= 8;
        }
-}
-
+ }
 
 /******************************************************************************/
 
index 90f742464ba6d4ed41988c81f2cf33b8c4dc77ec..3379463a612ce5fd3062a941fdced0d3df16a6ac 100644 (file)
@@ -96,6 +96,9 @@ void tdes_enc(void* out, const void* in, const void* key);
  * \param key pointer to the key (192 bit = 24 byte)
  */
  void tdes_dec(void* out, const void* in, const void* key);
+ void tdes_2key_enc(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]);
+ void tdes_2key_dec(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]);
 
  void tdes_2key_enc(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]);
  void tdes_2key_dec(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]);
diff --git a/armsrc/desfire_crypto.c b/armsrc/desfire_crypto.c
new file mode 100644 (file)
index 0000000..9ea0737
--- /dev/null
@@ -0,0 +1,642 @@
+/*-
+ * Copyright (C) 2010, Romain Tartiere.
+ * 
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser 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 Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ * 
+ * $Id$
+ */
+
+/*
+ * This implementation was written based on information provided by the
+ * following documents:
+ *
+ * NIST Special Publication 800-38B
+ * Recommendation for Block Cipher Modes of Operation: The CMAC Mode for Authentication
+ * May 2005
+ */
+#include "desfire_crypto.h"
+
+static void      xor (const uint8_t *ivect, uint8_t *data, const size_t len);
+
+static size_t    key_macing_length (desfirekey_t key);
+
+static void xor (const uint8_t *ivect, uint8_t *data, const size_t len) {
+    for (size_t i = 0; i < len; i++) {
+        data[i] ^= ivect[i];
+    }
+}
+
+void cmac_generate_subkeys ( desfirekey_t key) {
+    int kbs = key_block_size (key);
+    const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
+
+    uint8_t l[kbs];
+    memset (l, 0, kbs);
+
+    uint8_t ivect[kbs];
+    memset (ivect, 0, kbs);
+
+    mifare_cypher_blocks_chained (NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER);
+
+    bool xor = false;
+
+    // Used to compute CMAC on complete blocks
+    memcpy (key->cmac_sk1, l, kbs);
+    xor = l[0] & 0x80;
+    lsl (key->cmac_sk1, kbs);
+    if (xor)
+        key->cmac_sk1[kbs-1] ^= R;
+
+    // Used to compute CMAC on the last block if non-complete
+    memcpy (key->cmac_sk2, key->cmac_sk1, kbs);
+    xor = key->cmac_sk1[0] & 0x80;
+    lsl (key->cmac_sk2, kbs);
+    if (xor)
+        key->cmac_sk2[kbs-1] ^= R;
+}
+
+void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac) {
+    int kbs = key_block_size (key);
+    uint8_t *buffer = malloc (padded_data_length (len, kbs));
+
+    memcpy (buffer, data, len);
+
+    if ((!len) || (len % kbs)) {
+        buffer[len++] = 0x80;
+        while (len % kbs) {
+            buffer[len++] = 0x00;
+        }
+        xor (key->cmac_sk2, buffer + len - kbs, kbs);
+    } else {
+        xor (key->cmac_sk1, buffer + len - kbs, kbs);
+    }
+
+    mifare_cypher_blocks_chained (NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER);
+
+    memcpy (cmac, ivect, kbs);
+}
+
+size_t key_block_size (const desfirekey_t key) {
+    size_t block_size = 8;
+
+    switch (key->type) {
+               case T_DES:
+               case T_3DES:
+               case T_3K3DES:
+                       block_size = 8;
+                       break;
+               case T_AES:
+                       block_size = 16;
+                       break;
+    }
+
+    return block_size;
+}
+
+/*
+ * Size of MACing produced with the key.
+ */
+static size_t key_macing_length (const desfirekey_t key) {
+    size_t mac_length = MAC_LENGTH;
+
+    switch (key->type) {
+    case T_DES:
+    case T_3DES:
+        mac_length = MAC_LENGTH;
+        break;
+    case T_3K3DES:
+    case T_AES:
+        mac_length = CMAC_LENGTH;
+        break;
+    }
+
+    return mac_length;
+}
+
+/*
+ * Size required to store nbytes of data in a buffer of size n*block_size.
+ */
+size_t padded_data_length (const size_t nbytes, const size_t block_size) {
+    if ((!nbytes) || (nbytes % block_size))
+        return ((nbytes / block_size) + 1) * block_size;
+    else
+        return nbytes;
+}
+
+/*
+ * Buffer size required to MAC nbytes of data
+ */
+size_t maced_data_length (const desfirekey_t key, const size_t nbytes) {
+    return nbytes + key_macing_length (key);
+}
+/*
+ * Buffer size required to encipher nbytes of data and a two bytes CRC.
+ */
+size_t enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings) {
+    size_t crc_length = 0;
+    if (!(communication_settings & NO_CRC)) {
+        switch (DESFIRE(tag)->authentication_scheme) {
+        case AS_LEGACY:
+            crc_length = 2;
+            break;
+        case AS_NEW:
+            crc_length = 4;
+            break;
+        }
+    }
+
+    size_t block_size = DESFIRE(tag)->session_key ? key_block_size (DESFIRE(tag)->session_key) : 1;
+
+    return padded_data_length (nbytes + crc_length, block_size);
+}
+
+void* mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, off_t offset, int communication_settings) {
+    uint8_t *res = data;
+    uint8_t mac[4];
+    size_t edl;
+    bool append_mac = true;
+    desfirekey_t key = DESFIRE(tag)->session_key;
+
+    if (!key)
+        return data;
+
+    switch (communication_settings & MDCM_MASK) {
+    case MDCM_PLAIN:
+        if (AS_LEGACY == DESFIRE(tag)->authentication_scheme)
+            break;
+
+        /*
+         * When using new authentication methods, PLAIN data transmission from
+         * the PICC to the PCD are CMACed, so we have to maintain the
+         * cryptographic initialisation vector up-to-date to check data
+         * integrity later.
+         *
+         * The only difference with CMACed data transmission is that the CMAC
+         * is not apended to the data send by the PCD to the PICC.
+         */
+
+        append_mac = false;
+
+        /* pass through */
+    case MDCM_MACED:
+        switch (DESFIRE(tag)->authentication_scheme) {
+        case AS_LEGACY:
+            if (!(communication_settings & MAC_COMMAND))
+                break;
+
+            /* pass through */
+            edl = padded_data_length (*nbytes - offset, key_block_size (DESFIRE(tag)->session_key)) + offset;
+
+            // Fill in the crypto buffer with data ...
+            memcpy (res, data, *nbytes);
+            // ... and 0 padding
+            memset (res + *nbytes, 0, edl - *nbytes);
+
+            mifare_cypher_blocks_chained (tag, NULL, NULL, res + offset, edl - offset, MCD_SEND, MCO_ENCYPHER);
+
+            memcpy (mac, res + edl - 8, 4);
+
+            // Copy again provided data (was overwritten by mifare_cypher_blocks_chained)
+            memcpy (res, data, *nbytes);
+
+            if (!(communication_settings & MAC_COMMAND))
+                break;
+            // Append MAC
+            size_t bla = maced_data_length (DESFIRE(tag)->session_key, *nbytes - offset) + offset;
+                       bla++;
+
+            memcpy (res + *nbytes, mac, 4);
+
+            *nbytes += 4;
+            break;
+        case AS_NEW:
+            if (!(communication_settings & CMAC_COMMAND))
+                break;
+            cmac (key, DESFIRE (tag)->ivect, res, *nbytes, DESFIRE (tag)->cmac);
+
+            if (append_mac) {
+                maced_data_length (key, *nbytes);
+
+                memcpy (res, data, *nbytes);
+                memcpy (res + *nbytes, DESFIRE (tag)->cmac, CMAC_LENGTH);
+                *nbytes += CMAC_LENGTH;
+            }
+            break;
+        }
+
+        break;
+    case MDCM_ENCIPHERED:
+        /*  |<-------------- data -------------->|
+         *  |<--- offset -->|                    |
+         *  +---------------+--------------------+-----+---------+
+         *  | CMD + HEADERS | DATA TO BE SECURED | CRC | PADDING |
+         *  +---------------+--------------------+-----+---------+ ----------------
+         *  |               |<~~~~v~~~~~~~~~~~~~>|  ^  |         |   (DES / 3DES)
+         *  |               |     `---- crc16() ----'  |         |
+         *  |               |                    |  ^  |         | ----- *or* -----
+         *  |<~~~~~~~~~~~~~~~~~~~~v~~~~~~~~~~~~~>|  ^  |         |  (3K3DES / AES)
+         *                  |     `---- crc32() ----'  |         |
+         *                  |                                    | ---- *then* ----
+         *                  |<---------------------------------->|
+         *                            encypher()/decypher()
+         */
+
+            if (!(communication_settings & ENC_COMMAND))
+                break;
+            edl = enciphered_data_length (tag, *nbytes - offset, communication_settings) + offset;
+
+            // Fill in the crypto buffer with data ...
+            memcpy (res, data, *nbytes);
+            if (!(communication_settings & NO_CRC)) {
+                // ... CRC ...
+                switch (DESFIRE (tag)->authentication_scheme) {
+                case AS_LEGACY:
+                    AppendCrc14443a(res + offset, *nbytes - offset);
+                    *nbytes += 2;
+                    break;
+                case AS_NEW:
+                    crc32_append (res, *nbytes);
+                    *nbytes += 4;
+                    break;
+                }
+            }
+            // ... and padding
+            memset (res + *nbytes, 0, edl - *nbytes);
+
+            *nbytes = edl;
+
+            mifare_cypher_blocks_chained (tag, NULL, NULL, res + offset, *nbytes - offset, MCD_SEND, (AS_NEW == DESFIRE(tag)->authentication_scheme) ? MCO_ENCYPHER : MCO_DECYPHER);
+        break;
+    default:
+
+        *nbytes = -1;
+        res = NULL;
+        break;
+    }
+
+    return res;
+
+}
+
+void* mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbytes, int communication_settings)
+{
+    void *res = data;
+    size_t edl;
+    void *edata = NULL;
+    uint8_t first_cmac_byte = 0x00;
+
+    desfirekey_t key = DESFIRE(tag)->session_key;
+
+    if (!key)
+        return data;
+
+    // Return directly if we just have a status code.
+    if (1 == *nbytes)
+        return res;
+
+    switch (communication_settings & MDCM_MASK) {
+    case MDCM_PLAIN:
+
+        if (AS_LEGACY == DESFIRE(tag)->authentication_scheme)
+            break;
+
+        /* pass through */
+    case MDCM_MACED:
+        switch (DESFIRE (tag)->authentication_scheme) {
+        case AS_LEGACY:
+            if (communication_settings & MAC_VERIFY) {
+                *nbytes -= key_macing_length (key);
+                if (*nbytes <= 0) {
+                    *nbytes = -1;
+                    res = NULL;
+#ifdef WITH_DEBUG
+                    Dbprintf ("No room for MAC!");
+#endif
+                    break;
+                }
+
+                edl = enciphered_data_length (tag, *nbytes - 1, communication_settings);
+                edata = malloc (edl);
+
+                memcpy (edata, data, *nbytes - 1);
+                memset ((uint8_t *)edata + *nbytes - 1, 0, edl - *nbytes + 1);
+
+                mifare_cypher_blocks_chained (tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER);
+
+                if (0 != memcmp ((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) {
+#ifdef WITH_DEBUG
+                    Dbprintf ("MACing not verified");
+                    hexdump ((uint8_t *)data + *nbytes - 1, key_macing_length (key), "Expect ", 0);
+                    hexdump ((uint8_t *)edata + edl - 8, key_macing_length (key), "Actual ", 0);
+#endif
+                    DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
+                    *nbytes = -1;
+                    res = NULL;
+                }
+            }
+            break;
+        case AS_NEW:
+            if (!(communication_settings & CMAC_COMMAND))
+                break;
+            if (communication_settings & CMAC_VERIFY) {
+                if (*nbytes < 9) {
+                    *nbytes = -1;
+                    res = NULL;
+                    break;
+                }
+                first_cmac_byte = ((uint8_t *)data)[*nbytes - 9];
+                ((uint8_t *)data)[*nbytes - 9] = ((uint8_t *)data)[*nbytes-1];
+            }
+
+            int n = (communication_settings & CMAC_VERIFY) ? 8 : 0;
+            cmac (key, DESFIRE (tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE (tag)->cmac);
+
+            if (communication_settings & CMAC_VERIFY) {
+                ((uint8_t *)data)[*nbytes - 9] = first_cmac_byte;
+                if (0 != memcmp (DESFIRE (tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) {
+#ifdef WITH_DEBUG
+                    Dbprintf ("CMAC NOT verified :-(");
+                    hexdump ((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0);
+                    hexdump (DESFIRE (tag)->cmac, 8, "Actual ", 0);
+#endif
+                    DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
+                    *nbytes = -1;
+                    res = NULL;
+                } else {
+                    *nbytes -= 8;
+                }
+            }
+            break;
+        }
+
+        free (edata);
+
+        break;
+    case MDCM_ENCIPHERED:
+        (*nbytes)--;
+        bool verified = false;
+        int crc_pos = 0x00;
+        int end_crc_pos = 0x00;
+        uint8_t x;
+
+        /*
+         * AS_LEGACY:
+         * ,-----------------+-------------------------------+--------+
+         * \     BLOCK n-1   |              BLOCK n          | STATUS |
+         * /  PAYLOAD | CRC0 | CRC1 | 0x80? | 0x000000000000 | 0x9100 |
+         * `-----------------+-------------------------------+--------+
+         *
+         *         <------------ DATA ------------>
+         * FRAME = PAYLOAD + CRC(PAYLOAD) + PADDING
+         *
+         * AS_NEW:
+         * ,-------------------------------+-----------------------------------------------+--------+
+         * \                 BLOCK n-1     |                  BLOCK n                      | STATUS |
+         * /  PAYLOAD | CRC0 | CRC1 | CRC2 | CRC3 | 0x80? | 0x0000000000000000000000000000 | 0x9100 |
+         * `-------------------------------+-----------------------------------------------+--------+
+         * <----------------------------------- DATA ------------------------------------->|
+         *
+         *         <----------------- DATA ---------------->
+         * FRAME = PAYLOAD + CRC(PAYLOAD + STATUS) + PADDING + STATUS
+         *                                    `------------------'
+         */
+
+        mifare_cypher_blocks_chained (tag, NULL, NULL, res, *nbytes, MCD_RECEIVE, MCO_DECYPHER);
+
+        /*
+         * Look for the CRC and ensure it is followed by NULL padding.  We
+         * can't start by the end because the CRC is supposed to be 0 when
+         * verified, and accumulating 0's in it should not change it.
+         */
+        switch (DESFIRE (tag)->authentication_scheme) {
+        case AS_LEGACY:
+            crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks
+            if (crc_pos < 0) {
+                /* Single block */
+                crc_pos = 0;
+            }
+            break;
+        case AS_NEW:
+            /* Move status between payload and CRC */
+            res = DESFIRE (tag)->crypto_buffer;
+            memcpy (res, data, *nbytes);
+
+            crc_pos = (*nbytes) - 16 - 3;
+            if (crc_pos < 0) {
+                /* Single block */
+                crc_pos = 0;
+            }
+            memcpy ((uint8_t *)res + crc_pos + 1, (uint8_t *)res + crc_pos, *nbytes - crc_pos);
+            ((uint8_t *)res)[crc_pos] = 0x00;
+            crc_pos++;
+            *nbytes += 1;
+            break;
+        }
+
+        do {
+            uint16_t crc16 =0x00;
+            uint32_t crc;
+            switch (DESFIRE (tag)->authentication_scheme) {
+            case AS_LEGACY:
+                end_crc_pos = crc_pos + 2;
+                AppendCrc14443a (res, end_crc_pos);
+                               
+                               // 
+                               
+                               
+                crc = crc16;
+                break;
+            case AS_NEW:
+                end_crc_pos = crc_pos + 4;
+                crc32 (res, end_crc_pos, (uint8_t *)&crc);
+                break;
+            }
+            if (!crc) {
+                verified = true;
+                for (int n = end_crc_pos; n < *nbytes - 1; n++) {
+                    uint8_t byte = ((uint8_t *)res)[n];
+                    if (!( (0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos)) ))
+                        verified = false;
+                }
+            }
+            if (verified) {
+                *nbytes = crc_pos;
+                switch (DESFIRE (tag)->authentication_scheme) {
+                case AS_LEGACY:
+                    ((uint8_t *)data)[(*nbytes)++] = 0x00;
+                    break;
+                case AS_NEW:
+                    /* The status byte was already before the CRC */
+                    break;
+                }
+            } else {
+                switch (DESFIRE (tag)->authentication_scheme) {
+                case AS_LEGACY:
+                    break;
+                case AS_NEW:
+                    x = ((uint8_t *)res)[crc_pos - 1];
+                    ((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos];
+                    ((uint8_t *)res)[crc_pos] = x;
+                    break;
+                }
+                crc_pos++;
+            }
+        } while (!verified && (end_crc_pos < *nbytes));
+
+        if (!verified) {
+#ifdef WITH_DEBUG
+            /* FIXME In some configurations, the file is transmitted PLAIN */
+            Dbprintf("CRC not verified in decyphered stream");
+#endif
+            DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
+            *nbytes = -1;
+            res = NULL;
+        }
+
+        break;
+    default:
+        Dbprintf("Unknown communication settings");
+        *nbytes = -1;
+        res = NULL;
+        break;
+
+    }
+    return res;
+}
+
+
+void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size)
+{
+    uint8_t ovect[MAX_CRYPTO_BLOCK_SIZE];
+
+    if (direction == MCD_SEND) {
+        xor (ivect, data, block_size);
+    } else {
+        memcpy (ovect, data, block_size);
+    }
+
+    uint8_t edata[MAX_CRYPTO_BLOCK_SIZE];
+
+    switch (key->type) {
+    case T_DES:
+        switch (operation) {
+        case MCO_ENCYPHER:
+            //DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
+                       des_enc(edata, data, key->data);
+            break;
+        case MCO_DECYPHER:
+            //DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
+                       des_dec(edata, data, key->data);
+            break;
+        }
+        break;
+    case T_3DES:
+        switch (operation) {
+        case MCO_ENCYPHER:                     
+            // DES_ecb_encrypt ((DES_cblock *) data,  (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
+            // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data,  &(key->ks2), DES_DECRYPT);
+            // DES_ecb_encrypt ((DES_cblock *) data,  (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
+                       tdes_enc(edata,data, key->data);
+            break;
+        case MCO_DECYPHER:
+            // DES_ecb_encrypt ((DES_cblock *) data,  (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
+            // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data,  &(key->ks2), DES_ENCRYPT);
+            // DES_ecb_encrypt ((DES_cblock *) data,  (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
+                       tdes_dec(data, edata, key->data);
+            break;
+        }
+        break;
+    case T_3K3DES:
+        switch (operation) {
+        case MCO_ENCYPHER:
+                       tdes_enc(edata,data, key->data);
+            // DES_ecb_encrypt ((DES_cblock *) data,  (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
+            // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data,  &(key->ks2), DES_DECRYPT);
+            // DES_ecb_encrypt ((DES_cblock *) data,  (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT);
+            break;
+        case MCO_DECYPHER:
+                       tdes_dec(data, edata, key->data);        
+                       // DES_ecb_encrypt ((DES_cblock *) data,  (DES_cblock *) edata, &(key->ks3), DES_DECRYPT);
+            // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data,  &(key->ks2), DES_ENCRYPT);
+            // DES_ecb_encrypt ((DES_cblock *) data,  (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
+            break;
+        }
+        break;
+    case T_AES:
+        switch (operation) 
+               {
+                       case MCO_ENCYPHER:
+                       {
+                               AesCtx ctx;
+                               AesCtxIni(&ctx, ivect, key->data, KEY128,CBC); 
+                               AesEncrypt(&ctx, data, edata, sizeof(data) );
+                               break;
+                       }
+                       case MCO_DECYPHER:
+                       {
+                               AesCtx ctx;
+                               AesCtxIni(&ctx, ivect, key->data, KEY128,CBC); 
+                               AesDecrypt(&ctx, edata, data, sizeof(edata));
+                               break;
+                       }
+        }
+        break;
+    }
+
+    memcpy (data, edata, block_size);
+
+    if (direction == MCD_SEND) {
+        memcpy (ivect, data, block_size);
+    } else {
+        xor (ivect, data, block_size);
+        memcpy (ivect, ovect, block_size);
+    }
+}
+
+/*
+ * This function performs all CBC cyphering / deciphering.
+ *
+ * The tag argument may be NULL, in which case both key and ivect shall be set.
+ * When using the tag session_key and ivect for processing data, these
+ * arguments should be set to NULL.
+ *
+ * Because the tag may contain additional data, one may need to call this
+ * function with tag, key and ivect defined.
+ */
+void mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation) {
+    size_t block_size;
+
+    if (tag) {
+        if (!key)
+            key = DESFIRE (tag)->session_key;
+        if (!ivect)
+            ivect = DESFIRE (tag)->ivect;
+
+        switch (DESFIRE (tag)->authentication_scheme) {
+                       case AS_LEGACY:
+                               memset (ivect, 0, MAX_CRYPTO_BLOCK_SIZE);
+                               break;
+                       case AS_NEW:
+                               break;
+        }
+    }
+
+    block_size = key_block_size (key);
+
+    size_t offset = 0;
+    while (offset < data_size) {
+        mifare_cypher_single_block (key, data + offset, ivect, direction, operation, block_size);
+        offset += block_size;
+    }
+}
\ No newline at end of file
diff --git a/armsrc/desfire_crypto.h b/armsrc/desfire_crypto.h
new file mode 100644 (file)
index 0000000..698f11e
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __DESFIRE_CRYPTO_H
+#define __DESFIRE_CRYPTO_H
+
+#include <string.h>
+#include <strings.h>
+#include <stdarg.h>
+#include "printf.h"
+
+#include "iso14443a.h"
+#include "../common/desfire.h"
+#include "des.h"
+//#include "aes.h"
+
+#endif
diff --git a/armsrc/desfire_key.c b/armsrc/desfire_key.c
new file mode 100644 (file)
index 0000000..b3aa14e
--- /dev/null
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (C) 2010, Romain Tartiere.
+ * 
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser 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 Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ * 
+ * $Id$
+ */
+#include <stdlib.h>
+#include "desfire_key.h"
+
+static inline void update_key_schedules (desfirekey_t key);
+
+static inline void update_key_schedules (desfirekey_t key) {
+    // DES_set_key ((DES_cblock *)key->data, &(key->ks1));
+    // DES_set_key ((DES_cblock *)(key->data + 8), &(key->ks2));
+    // if (T_3K3DES == key->type) {
+        // DES_set_key ((DES_cblock *)(key->data + 16), &(key->ks3));
+    // }
+}
+
+void Desfire_des_key_new (const uint8_t value[8], desfirekey_t key) {
+    uint8_t data[8];
+    memcpy (data, value, 8);
+    for (int n=0; n < 8; n++)
+        data[n] &= 0xfe;
+    Desfire_des_key_new_with_version (data, key);
+}
+
+void Desfire_des_key_new_with_version (const uint8_t value[8], desfirekey_t key) {
+       if ( key != NULL) {
+               key->type = T_DES;
+               memcpy (key->data, value, 8);
+               memcpy (key->data+8, value, 8);
+               update_key_schedules (key);
+       }
+}
+
+void Desfire_3des_key_new (const uint8_t value[16], desfirekey_t key) {
+    uint8_t data[16];
+    memcpy (data, value, 16);
+    for (int n=0; n < 8; n++)
+        data[n] &= 0xfe;
+    for (int n=8; n < 16; n++)
+        data[n] |= 0x01;
+    Desfire_3des_key_new_with_version (data, key);
+}
+
+void Desfire_3des_key_new_with_version (const uint8_t value[16], desfirekey_t key) {
+    if ( key != NULL ){
+               key->type = T_3DES;
+               memcpy (key->data, value, 16);
+               update_key_schedules (key);
+       }
+}
+
+void Desfire_3k3des_key_new (const uint8_t value[24], desfirekey_t key) {
+    uint8_t data[24];
+    memcpy (data, value, 24);
+    for (int n=0; n < 8; n++)
+        data[n] &= 0xfe;
+    Desfire_3k3des_key_new_with_version (data, key);
+}
+
+void Desfire_3k3des_key_new_with_version (const uint8_t value[24], desfirekey_t key) {
+       if ( key != NULL){
+               key->type = T_3K3DES;
+               memcpy (key->data, value, 24);
+               update_key_schedules (key);
+       }
+}
+
+ void Desfire_aes_key_new (const uint8_t value[16], desfirekey_t key) {
+    Desfire_aes_key_new_with_version (value, 0, key);
+}
+
+ void Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version, desfirekey_t key) {
+
+       if (key != NULL) {
+               memcpy (key->data, value, 16);
+               key->type = T_AES;
+               key->aes_version = version;
+       }
+}
+
+uint8_t Desfire_key_get_version (desfirekey_t key) {
+    uint8_t version = 0;
+
+    for (int n = 0; n < 8; n++) {
+        version |= ((key->data[n] & 1) << (7 - n));
+    }
+    return version;
+}
+
+void Desfire_key_set_version (desfirekey_t key, uint8_t version)
+{
+    for (int n = 0; n < 8; n++) {
+        uint8_t version_bit = ((version & (1 << (7-n))) >> (7-n));
+        key->data[n] &= 0xfe;
+        key->data[n] |= version_bit;
+        if (key->type == T_DES) {
+            key->data[n+8] = key->data[n];
+        } else {
+            // Write ~version to avoid turning a 3DES key into a DES key
+            key->data[n+8] &= 0xfe;
+            key->data[n+8] |= ~version_bit;
+        }
+    }
+}
+
+void Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key) {
+
+    uint8_t buffer[24];
+
+    switch (authkey->type) {
+    case T_DES:
+        memcpy (buffer, rnda, 4);
+        memcpy (buffer+4, rndb, 4);
+        Desfire_des_key_new_with_version (buffer, key);
+        break;
+    case T_3DES:
+        memcpy (buffer, rnda, 4);
+        memcpy (buffer+4, rndb, 4);
+        memcpy (buffer+8, rnda+4, 4);
+        memcpy (buffer+12, rndb+4, 4);
+        Desfire_3des_key_new_with_version (buffer, key);
+        break;
+    case T_3K3DES:
+        memcpy (buffer, rnda, 4);
+        memcpy (buffer+4, rndb, 4);
+        memcpy (buffer+8, rnda+6, 4);
+        memcpy (buffer+12, rndb+6, 4);
+        memcpy (buffer+16, rnda+12, 4);
+        memcpy (buffer+20, rndb+12, 4);
+        Desfire_3k3des_key_new (buffer, key);
+        break;
+    case T_AES:
+        memcpy (buffer, rnda, 4);
+        memcpy (buffer+4, rndb, 4);
+        memcpy (buffer+8, rnda+12, 4);
+        memcpy (buffer+12, rndb+12, 4);
+        Desfire_aes_key_new (buffer, key);
+        break;
+    }
+}
\ No newline at end of file
diff --git a/armsrc/desfire_key.h b/armsrc/desfire_key.h
new file mode 100644 (file)
index 0000000..0d99903
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __DESFIRE_KEY_INCLUDED
+#define __DESFIRE_KEY_INCLUDED
+#include "iso14443a.h"
+// desfire_key.h
+void           Desfire_des_key_new (const uint8_t value[8], desfirekey_t key);
+void           Desfire_3des_key_new (const uint8_t value[16], desfirekey_t key);
+void           Desfire_des_key_new_with_version (const uint8_t value[8], desfirekey_t key);
+void           Desfire_3des_key_new_with_version (const uint8_t value[16], desfirekey_t key);
+void           Desfire_3k3des_key_new (const uint8_t value[24], desfirekey_t key);
+void           Desfire_3k3des_key_new_with_version (const uint8_t value[24], desfirekey_t key);
+void           Desfire_aes_key_new (const uint8_t value[16], desfirekey_t key);
+void           Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version,desfirekey_t key);
+uint8_t        Desfire_key_get_version (desfirekey_t key);
+void           Desfire_key_set_version (desfirekey_t key, uint8_t version);
+void           Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key);
+
+#endif
\ No newline at end of file
index 0006d59d01c03fd4944caefef829771b1b8068fc..9012bf11a8cb9713e0d5804eee142e86448fbb95 100644 (file)
@@ -13,7 +13,8 @@
 
 #include "iso14443a.h"
 #include "epa.h"
-#include "cmd.h"
+#include "../common/cmd.h"
+
 
 // Protocol and Parameter Selection Request
 // use regular (1x) speed in both directions
@@ -224,7 +225,7 @@ static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return)
        EPA_Finish();
        
        // send the USB packet
-  cmd_send(CMD_ACK,step,func_return,0,0,0);
+       cmd_send(CMD_ACK,step,func_return,0,0,0);
 }
 
 //-----------------------------------------------------------------------------
@@ -252,8 +253,9 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
        
        // set up communication
        func_return = EPA_Setup();
-       if (func_return != 0) {
+       if (func_return != 0) { 
                EPA_PACE_Collect_Nonce_Abort(1, func_return);
+               Dbprintf("epa: setup fucked up! %d", func_return);
                return;
        }
 
@@ -263,10 +265,13 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
        int card_access_length = EPA_Read_CardAccess(card_access, 256);
        // the response has to be at least this big to hold the OID
        if (card_access_length < 18) {
+               Dbprintf("epa: Too small!");
                EPA_PACE_Collect_Nonce_Abort(2, card_access_length);
                return;
        }
 
+       Dbprintf("epa: foo!");
+       
        // this will hold the PACE info of the card
        pace_version_info_t pace_version_info;
        // search for the PACE OID
@@ -278,6 +283,8 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
                return;
        }
        
+       Dbprintf("epa: bar!");
+       
        // initiate the PACE protocol
        // use the CAN for the password since that doesn't change
        func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2);
@@ -299,7 +306,7 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
        // save received information
 //     ack->arg[1] = func_return;
 //     memcpy(ack->d.asBytes, nonce, func_return);
-  cmd_send(CMD_ACK,0,func_return,0,nonce,func_return);
+       cmd_send(CMD_ACK,0,func_return,0,nonce,func_return);
 }
 
 //-----------------------------------------------------------------------------
@@ -422,7 +429,7 @@ int EPA_Setup()
 
        // power up the field
        iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
-
+       
        // select the card
        return_code = iso14443a_select_card(uid, &card_select_info, NULL);
        if (return_code != 1) {
index 077b378a918b438cb0dc625642d22a7543eaabbf..32e0500ed83f649fe6013ec86445c1fbb13e7298 100644 (file)
@@ -9,7 +9,8 @@
 // Routines to load the FPGA image, and then to configure the FPGA's major
 // mode once it is configured.
 //-----------------------------------------------------------------------------
-#include "proxmark3.h"
+
+#include "../include/proxmark3.h"
 #include "apps.h"
 #include "util.h"
 #include "string.h"
index 4b173d6f223845620eeb47e96e35c89ffb78f628..2d0645658c2dc2d2b68cf35f8f295308cf364925 100644 (file)
 // (c) 2012 Roel Verdult
 //-----------------------------------------------------------------------------
 
-#include "proxmark3.h"
+#include "../include/proxmark3.h"
 #include "apps.h"
 #include "util.h"
-#include "hitag2.h"
+#include "../include/hitag2.h"
 #include "string.h"
 #include "BigBuf.h"
 
@@ -973,7 +973,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
        AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1);
        AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
        
-  // Disable timer during configuration        
+    // Disable timer during configuration      
        AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
 
        // Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
index 9139d3bd9f5a0734f4b2e651ca4b503e4b0a6485..51a9011f100c058fe8d5c7cdb741ea3d255010af 100644 (file)
@@ -36,7 +36,7 @@
 //
 //-----------------------------------------------------------------------------
 
-#include "proxmark3.h"
+#include "../include/proxmark3.h"
 #include "apps.h"
 #include "util.h"
 #include "string.h"
@@ -45,8 +45,9 @@
 // Needed for CRC in emulation mode;
 // same construction as in ISO 14443;
 // different initial value (CRC_ICLASS)
-#include "iso14443crc.h"
-#include "iso15693tools.h"
+#include "../common/iso14443crc.h"
+#include "../common/iso15693tools.h"
+//#include "iso15693tools.h"
 #include "protocols.h"
 #include "optimized_cipher.h"
 
@@ -353,7 +354,7 @@ static struct {
                SUB_SECOND_HALF,
                SUB_BOTH
        }               sub;
-    uint8_t *output;
+    uint8_t   *output;
 } Demod;
 
 static RAMFUNC int ManchesterDecoding(int v)
@@ -632,8 +633,6 @@ static RAMFUNC int ManchesterDecoding(int v)
 //-----------------------------------------------------------------------------
 void RAMFUNC SnoopIClass(void)
 {
-
-
     // We won't start recording the frames that we acquire until we trigger;
     // a good trigger condition to get started is probably when we see a
     // response from the tag.
@@ -658,7 +657,7 @@ void RAMFUNC SnoopIClass(void)
        clear_trace();
     iso14a_set_trigger(FALSE);
 
-       int lastRxCounter;
+    int lastRxCounter;
     uint8_t *upTo;
     int smpl;
     int maxBehindBy = 0;
@@ -774,7 +773,7 @@ void RAMFUNC SnoopIClass(void)
                if(ManchesterDecoding(smpl & 0x0F)) {
                        time_stop = (GetCountSspClk()-time_0) << 4;
 
-                       rsamples = samples - Demod.samples;
+                   rsamples = samples - Demod.samples;
                    LED_B_ON();
 
                        if(tracing)     {
@@ -944,7 +943,7 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len)
                uint8_t b = cmd[i];
                ToSend[++ToSendMax] = encode4Bits(b & 0xF); //Least significant half
                ToSend[++ToSendMax] = encode4Bits((b >>4) & 0xF);//Most significant half
-       }
+                       }
 
        // Send EOF
        ToSend[++ToSendMax] = 0xB8;
@@ -1230,24 +1229,24 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
                                //exitLoop = true;
                        }else
                        {       //Not fullsim, we don't respond
-                               // We do not know what to answer, so lets keep quiet
+            // We do not know what to answer, so lets keep quiet
                                modulated_response = resp_sof; modulated_response_size = 0;
-                               trace_data = NULL;
-                               trace_data_size = 0;
+                       trace_data = NULL;
+                       trace_data_size = 0;
                                if (simulationMode == MODE_EXIT_AFTER_MAC){
-                                       // dbprintf:ing ...
-                                       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]);
-                                       if (reader_mac_buf != NULL)
-                                       {
-                                               memcpy(reader_mac_buf,receivedCmd+1,8);
-                                       }
-                                       exitLoop = true;
+                               // dbprintf:ing ...
+                               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]);
+                               if (reader_mac_buf != NULL)
+                               {
+                                       memcpy(reader_mac_buf,receivedCmd+1,8);
                                }
+                               exitLoop = true;
+                       }
                        }
 
                } else if(receivedCmd[0] == ICLASS_CMD_HALT && len == 1) {
@@ -1404,17 +1403,17 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int
    {
      if(*wait < 10) *wait = 10;
      
-     for(c = 0; c < *wait;) {
-       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
-         AT91C_BASE_SSC->SSC_THR = 0x00;               // For exact timing!
-         c++;
-       }
-       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-         volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
-         (void)r;
-       }
-       WDT_HIT();
-     }
+  for(c = 0; c < *wait;) {
+    if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+      AT91C_BASE_SSC->SSC_THR = 0x00;          // For exact timing!
+      c++;
+    }
+    if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+      volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
+      (void)r;
+    }
+    WDT_HIT();
+  }
 
    }
 
@@ -1497,18 +1496,18 @@ void CodeIClassCommand(const uint8_t * cmd, int len)
 
 void ReaderTransmitIClass(uint8_t* frame, int len)
 {
-       int wait = 0;
-       int samples = 0;
+  int wait = 0;
+  int samples = 0;
 
-       // This is tied to other size changes
-       CodeIClassCommand(frame,len);
+  // This is tied to other size changes
+  CodeIClassCommand(frame,len);
 
-       // Select the card
-       TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait);
-       if(trigger)
-               LED_A_ON();
+  // Select the card
+  TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait);
+  if(trigger)
+       LED_A_ON();
 
-       // Store reader command in buffer
+  // Store reader command in buffer
        if (tracing) {
                uint8_t par[MAX_PARITY_SIZE];
                GetParity(frame, len, par);
@@ -1544,7 +1543,7 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples,
        for(;;) {
                WDT_HIT();
 
-               if(BUTTON_PRESS()) return FALSE;
+           if(BUTTON_PRESS()) return FALSE;
 
                if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
                        AT91C_BASE_SSC->SSC_THR = 0x00;  // To make use of exact timing of next command from reader!!
@@ -1677,7 +1676,7 @@ void ReaderIClass(uint8_t arg0) {
 
        uint8_t card_data[6 * 8]={0};
        memset(card_data, 0xFF, sizeof(card_data));
-       uint8_t last_csn[8]={0};
+    uint8_t last_csn[8]={0};
        
        //Read conf block CRC(0x01) => 0xfa 0x22
        uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY,0x01, 0xfa, 0x22};
@@ -1685,16 +1684,16 @@ void ReaderIClass(uint8_t arg0) {
        uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY,0x05, 0xde, 0x64};
 
 
-       int read_status= 0;
+    int read_status= 0;
        uint8_t result_status = 0;
-       bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE;
+    bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE;
        bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY;
        set_tracing(TRUE);
-       setupIclassReader();
+    setupIclassReader();
 
        uint16_t tryCnt=0;
-       while(!BUTTON_PRESS())
-       {
+    while(!BUTTON_PRESS())
+    {
                if (try_once && tryCnt > 5) break; 
                tryCnt++;
                if(!tracing) {
@@ -1745,9 +1744,9 @@ void ReaderIClass(uint8_t arg0) {
                //Then we can 'ship' back the 8 * 5 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
-               if(memcmp(last_csn, card_data, 8) != 0)
+                    LED_B_ON();
+                    //Send back to client, but don't bother if we already sent this
+                    if(memcmp(last_csn, card_data, 8) != 0)
                {
                        // If caller requires that we get CC, continue until we got it
                        if( (arg0 & read_status & FLAG_ICLASS_READER_CC) || !(arg0 & FLAG_ICLASS_READER_CC))
@@ -1757,13 +1756,13 @@ void ReaderIClass(uint8_t arg0) {
                                        LED_A_OFF();
                                        return;
                                }
-                               //Save that we already sent this....
-                               memcpy(last_csn, card_data, 8);
+                    //Save that we already sent this....
+                        memcpy(last_csn, card_data, 8);
                        }
 
                }
                LED_B_OFF();
-       }
+    }
     cmd_send(CMD_ACK,0,0,0,card_data, 0);
     LED_A_OFF();
 }
@@ -1813,20 +1812,20 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
                uint8_t read_status = handshakeIclassTag(card_data);
                if(read_status < 2) continue;
 
-               //for now replay captured auth (as cc not updated)
-               memcpy(check+5,MAC,4);
+                               //for now replay captured auth (as cc not updated)
+                               memcpy(check+5,MAC,4);
 
                if(sendCmdGetResponseWithRetries(check, sizeof(check),resp, 4, 5))
                {
-                       Dbprintf("Error: Authentication Fail!");
+                                 Dbprintf("Error: Authentication Fail!");
                        continue;
-               }
+                               }
 
                //first get configuration block (block 1)
                crc = block_crc_LUT[1];
-               read[1]=1;
-               read[2] = crc >> 8;
-               read[3] = crc & 0xff;
+                               read[1]=1;
+                               read[2] = crc >> 8;
+                               read[3] = crc & 0xff;
 
                if(sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10))
                {
@@ -1834,12 +1833,12 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
                        continue;
                }
 
-               mem=resp[5];
-               memory.k16= (mem & 0x80);
-               memory.book= (mem & 0x20);
-               memory.k2= (mem & 0x8);
-               memory.lockauth= (mem & 0x2);
-               memory.keyaccess= (mem & 0x1);
+                                        mem=resp[5];
+                                        memory.k16= (mem & 0x80);
+                                        memory.book= (mem & 0x20);
+                                        memory.k2= (mem & 0x8);
+                                        memory.lockauth= (mem & 0x2);
+                                        memory.keyaccess= (mem & 0x1);
 
                cardsize = memory.k16 ? 255 : 32;
                WDT_HIT();
@@ -1847,20 +1846,20 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
                memset(card_data,0x0,USB_CMD_DATA_SIZE);
                uint8_t failedRead =0;
                uint32_t stored_data_length =0;
-               //then loop around remaining blocks
+                               //then loop around remaining blocks
                for(int block=0; block < cardsize; block++){
 
                        read[1]= block;
                        crc = block_crc_LUT[block];
-                       read[2] = crc >> 8;
-                       read[3] = crc & 0xff;
+                                   read[2] = crc >> 8;
+                                   read[3] = crc & 0xff;
 
                        if(!sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10))
                        {
-                               Dbprintf("     %02x: %02x %02x %02x %02x %02x %02x %02x %02x",
+                                        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]);
+                                         resp[3], resp[4], resp[5],
+                                         resp[6], resp[7]);
 
                                //Fill up the buffer
                                memcpy(card_data+stored_data_length,resp,8);
@@ -1924,7 +1923,7 @@ void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, uint8_
        uint8_t* resp = (((uint8_t *)BigBuf) + 3560);
 
        // Reset trace buffer
-    memset(trace, 0x44, RECV_CMD_OFFSET);
+       memset(trace, 0x44, RECV_CMD_OFFSET);
        traceLen = 0;
 
        // Setup SSC
diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c
deleted file mode 100644 (file)
index c202e31..0000000
+++ /dev/null
@@ -1,1245 +0,0 @@
-//-----------------------------------------------------------------------------
-// Jonathan Westhues, split Nov 2006
-//
-// This code is licensed to you under the terms of the GNU GPL, version 2 or,
-// at your option, any later version. See the LICENSE.txt file for the text of
-// the license.
-//-----------------------------------------------------------------------------
-// Routines to support ISO 14443. This includes both the reader software and
-// the `fake tag' modes. At the moment only the Type B modulation is
-// supported.
-//-----------------------------------------------------------------------------
-
-#include "proxmark3.h"
-#include "apps.h"
-#include "util.h"
-#include "string.h"
-
-#include "iso14443crc.h"
-
-//static void GetSamplesFor14443(int weTx, int n);
-
-/*#define DEMOD_TRACE_SIZE 4096
-#define READER_TAG_BUFFER_SIZE 2048
-#define TAG_READER_BUFFER_SIZE 2048
-#define DEMOD_DMA_BUFFER_SIZE 1024
-*/
-
-#define RECEIVE_SAMPLES_TIMEOUT 2000
-
-//=============================================================================
-// An ISO 14443 Type B tag. We listen for commands from the reader, using
-// a UART kind of thing that's implemented in software. When we get a
-// frame (i.e., a group of bytes between SOF and EOF), we check the CRC.
-// If it's good, then we can do something appropriate with it, and send
-// a response.
-//=============================================================================
-
-//-----------------------------------------------------------------------------
-// Code up a string of octets at layer 2 (including CRC, we don't generate
-// that here) so that they can be transmitted to the reader. Doesn't transmit
-// them yet, just leaves them ready to send in ToSend[].
-//-----------------------------------------------------------------------------
-static void CodeIso14443bAsTag(const uint8_t *cmd, int len)
-{
-       int i;
-
-       ToSendReset();
-
-       // Transmit a burst of ones, as the initial thing that lets the
-       // reader get phase sync. This (TR1) must be > 80/fs, per spec,
-       // but tag that I've tried (a Paypass) exceeds that by a fair bit,
-       // so I will too.
-       for(i = 0; i < 20; i++) {
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-       }
-
-       // Send SOF.
-       for(i = 0; i < 10; i++) {
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-       }
-       for(i = 0; i < 2; i++) {
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-       }
-
-       for(i = 0; i < len; i++) {
-               int j;
-               uint8_t b = cmd[i];
-
-               // Start bit
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-
-               // Data bits
-               for(j = 0; j < 8; j++) {
-                       if(b & 1) {
-                               ToSendStuffBit(1);
-                               ToSendStuffBit(1);
-                               ToSendStuffBit(1);
-                               ToSendStuffBit(1);
-                       } else {
-                               ToSendStuffBit(0);
-                               ToSendStuffBit(0);
-                               ToSendStuffBit(0);
-                               ToSendStuffBit(0);
-                       }
-                       b >>= 1;
-               }
-
-               // Stop bit
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-       }
-
-       // Send SOF.
-       for(i = 0; i < 10; i++) {
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-               ToSendStuffBit(0);
-       }
-       for(i = 0; i < 10; i++) {
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-       }
-
-       // Convert from last byte pos to length
-       ToSendMax++;
-
-       // Add a few more for slop
-       ToSendMax += 2;
-}
-
-//-----------------------------------------------------------------------------
-// The software UART that receives commands from the reader, and its state
-// variables.
-//-----------------------------------------------------------------------------
-static struct {
-       enum {
-               STATE_UNSYNCD,
-               STATE_GOT_FALLING_EDGE_OF_SOF,
-               STATE_AWAITING_START_BIT,
-               STATE_RECEIVING_DATA,
-               STATE_ERROR_WAIT
-       }       state;
-       uint16_t    shiftReg;
-       int     bitCnt;
-       int     byteCnt;
-       int     byteCntMax;
-       int     posCnt;
-       uint8_t   *output;
-} Uart;
-
-/* Receive & handle a bit coming from the reader.
- *
- * LED handling:
- * LED A -> ON once we have received the SOF and are expecting the rest.
- * LED A -> OFF once we have received EOF or are in error state or unsynced
- *
- * Returns: true if we received a EOF
- *          false if we are still waiting for some more
- */
-static int Handle14443UartBit(int bit)
-{
-       switch(Uart.state) {
-               case STATE_UNSYNCD:
-                       LED_A_OFF();
-                       if(!bit) {
-                               // we went low, so this could be the beginning
-                               // of an SOF
-                               Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;
-                               Uart.posCnt = 0;
-                               Uart.bitCnt = 0;
-                       }
-                       break;
-
-               case STATE_GOT_FALLING_EDGE_OF_SOF:
-                       Uart.posCnt++;
-                       if(Uart.posCnt == 2) {
-                               if(bit) {
-                                       if(Uart.bitCnt >= 10) {
-                                               // we've seen enough consecutive
-                                               // zeros that it's a valid SOF
-                                               Uart.posCnt = 0;
-                                               Uart.byteCnt = 0;
-                                               Uart.state = STATE_AWAITING_START_BIT;
-                                               LED_A_ON(); // Indicate we got a valid SOF
-                                       } else {
-                                               // didn't stay down long enough
-                                               // before going high, error
-                                               Uart.state = STATE_ERROR_WAIT;
-                                       }
-                               } else {
-                                       // do nothing, keep waiting
-                               }
-                               Uart.bitCnt++;
-                       }
-                       if(Uart.posCnt >= 4) Uart.posCnt = 0;
-                       if(Uart.bitCnt > 14) {
-                               // Give up if we see too many zeros without
-                               // a one, too.
-                               Uart.state = STATE_ERROR_WAIT;
-                       }
-                       break;
-
-               case STATE_AWAITING_START_BIT:
-                       Uart.posCnt++;
-                       if(bit) {
-                               if(Uart.posCnt > 25) {
-                                       // stayed high for too long between
-                                       // characters, error
-                                       Uart.state = STATE_ERROR_WAIT;
-                               }
-                       } else {
-                               // falling edge, this starts the data byte
-                               Uart.posCnt = 0;
-                               Uart.bitCnt = 0;
-                               Uart.shiftReg = 0;
-                               Uart.state = STATE_RECEIVING_DATA;
-                               LED_A_ON(); // Indicate we're receiving
-                       }
-                       break;
-
-               case STATE_RECEIVING_DATA:
-                       Uart.posCnt++;
-                       if(Uart.posCnt == 2) {
-                               // time to sample a bit
-                               Uart.shiftReg >>= 1;
-                               if(bit) {
-                                       Uart.shiftReg |= 0x200;
-                               }
-                               Uart.bitCnt++;
-                       }
-                       if(Uart.posCnt >= 4) {
-                               Uart.posCnt = 0;
-                       }
-                       if(Uart.bitCnt == 10) {
-                               if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))
-                               {
-                                       // this is a data byte, with correct
-                                       // start and stop bits
-                                       Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;
-                                       Uart.byteCnt++;
-
-                                       if(Uart.byteCnt >= Uart.byteCntMax) {
-                                               // Buffer overflowed, give up
-                                               Uart.posCnt = 0;
-                                               Uart.state = STATE_ERROR_WAIT;
-                                       } else {
-                                               // so get the next byte now
-                                               Uart.posCnt = 0;
-                                               Uart.state = STATE_AWAITING_START_BIT;
-                                       }
-                               } else if(Uart.shiftReg == 0x000) {
-                                       // this is an EOF byte
-                                       LED_A_OFF(); // Finished receiving
-                                       return TRUE;
-                               } else {
-                                       // this is an error
-                                       Uart.posCnt = 0;
-                                       Uart.state = STATE_ERROR_WAIT;
-                               }
-                       }
-                       break;
-
-               case STATE_ERROR_WAIT:
-                       // We're all screwed up, so wait a little while
-                       // for whatever went wrong to finish, and then
-                       // start over.
-                       Uart.posCnt++;
-                       if(Uart.posCnt > 10) {
-                               Uart.state = STATE_UNSYNCD;
-                       }
-                       break;
-
-               default:
-                       Uart.state = STATE_UNSYNCD;
-                       break;
-       }
-
-       // This row make the error blew circular buffer in hf 14b snoop
-       //if (Uart.state == STATE_ERROR_WAIT) LED_A_OFF(); // Error
-
-       return FALSE;
-}
-
-//-----------------------------------------------------------------------------
-// Receive a command (from the reader to us, where we are the simulated tag),
-// and store it in the given buffer, up to the given maximum length. Keeps
-// spinning, waiting for a well-framed command, until either we get one
-// (returns TRUE) or someone presses the pushbutton on the board (FALSE).
-//
-// Assume that we're called with the SSC (to the FPGA) and ADC path set
-// correctly.
-//-----------------------------------------------------------------------------
-static int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen)
-{
-       uint8_t mask;
-       int i, bit;
-
-       // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
-       // only, since we are receiving, not transmitting).
-       // Signal field is off with the appropriate LED
-       LED_D_OFF();
-       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION);
-
-
-       // Now run a `software UART' on the stream of incoming samples.
-       Uart.output = received;
-       Uart.byteCntMax = maxLen;
-       Uart.state = STATE_UNSYNCD;
-
-       for(;;) {
-               WDT_HIT();
-
-               if(BUTTON_PRESS()) return FALSE;
-
-               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
-                       AT91C_BASE_SSC->SSC_THR = 0x00;
-               }
-               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-                       uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
-
-                       mask = 0x80;
-                       for(i = 0; i < 8; i++, mask >>= 1) {
-                               bit = (b & mask);
-                               if(Handle14443UartBit(bit)) {
-                                       *len = Uart.byteCnt;
-                                       return TRUE;
-                               }
-                       }
-               }
-       }
-}
-
-//-----------------------------------------------------------------------------
-// Main loop of simulated tag: receive commands from reader, decide what
-// response to send, and send it.
-//-----------------------------------------------------------------------------
-void SimulateIso14443Tag(void)
-{
-       static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
-       static const uint8_t response1[] = {
-               0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,
-               0x00, 0x21, 0x85, 0x5e, 0xd7
-       };
-
-       uint8_t *resp;
-       int respLen;
-
-       uint8_t *resp1 = BigBuf_get_addr() + 800;
-       int resp1Len;
-
-       uint8_t *receivedCmd = BigBuf_get_addr();
-       int len;
-
-       int i;
-
-       int cmdsRecvd = 0;
-
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       memset(receivedCmd, 0x44, 400);
-
-       CodeIso14443bAsTag(response1, sizeof(response1));
-       memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;
-
-       // We need to listen to the high-frequency, peak-detected path.
-       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
-       FpgaSetupSsc();
-
-       cmdsRecvd = 0;
-
-       for(;;) {
-               uint8_t b1, b2;
-
-               if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) {
-               Dbprintf("button pressed, received %d commands", cmdsRecvd);
-               break;
-               }
-
-               // Good, look at the command now.
-
-               if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) {
-                       resp = resp1; respLen = resp1Len;
-               } else {
-                       Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd);
-                       // And print whether the CRC fails, just for good measure
-                       ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2);
-                       if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) {
-                               // Not so good, try again.
-                               DbpString("+++CRC fail");
-                       } else {
-                               DbpString("CRC passes");
-                       }
-                       break;
-               }
-
-               memset(receivedCmd, 0x44, 32);
-
-               cmdsRecvd++;
-
-               if(cmdsRecvd > 0x30) {
-                       DbpString("many commands later...");
-                       break;
-               }
-
-               if(respLen <= 0) continue;
-
-               // Modulate BPSK
-               // Signal field is off with the appropriate LED
-               LED_D_OFF();
-               FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);
-               AT91C_BASE_SSC->SSC_THR = 0xff;
-               FpgaSetupSsc();
-
-               // Transmit the response.
-               i = 0;
-               for(;;) {
-                       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
-                               uint8_t b = resp[i];
-
-                               AT91C_BASE_SSC->SSC_THR = b;
-
-                               i++;
-                               if(i > respLen) {
-                                       break;
-                               }
-                       }
-                       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-                               volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
-                               (void)b;
-                       }
-               }
-       }
-}
-
-//=============================================================================
-// An ISO 14443 Type B reader. We take layer two commands, code them
-// appropriately, and then send them to the tag. We then listen for the
-// tag's response, which we leave in the buffer to be demodulated on the
-// PC side.
-//=============================================================================
-
-static struct {
-       enum {
-               DEMOD_UNSYNCD,
-               DEMOD_PHASE_REF_TRAINING,
-               DEMOD_AWAITING_FALLING_EDGE_OF_SOF,
-               DEMOD_GOT_FALLING_EDGE_OF_SOF,
-               DEMOD_AWAITING_START_BIT,
-               DEMOD_RECEIVING_DATA,
-               DEMOD_ERROR_WAIT
-       }       state;
-       int     bitCount;
-       int     posCount;
-       int     thisBit;
-       int     metric;
-       int     metricN;
-       uint16_t    shiftReg;
-       uint8_t   *output;
-       int     len;
-       int     sumI;
-       int     sumQ;
-} Demod;
-
-/*
- * Handles reception of a bit from the tag
- *
- * LED handling:
- * LED C -> ON once we have received the SOF and are expecting the rest.
- * LED C -> OFF once we have received EOF or are unsynced
- *
- * Returns: true if we received a EOF
- *          false if we are still waiting for some more
- *
- */
-static RAMFUNC int Handle14443SamplesDemod(int ci, int cq)
-{
-       int v;
-
-       // The soft decision on the bit uses an estimate of just the
-       // quadrant of the reference angle, not the exact angle.
-#define MAKE_SOFT_DECISION() { \
-               if(Demod.sumI > 0) { \
-                       v = ci; \
-               } else { \
-                       v = -ci; \
-               } \
-               if(Demod.sumQ > 0) { \
-                       v += cq; \
-               } else { \
-                       v -= cq; \
-               } \
-       }
-
-       switch(Demod.state) {
-               case DEMOD_UNSYNCD:
-                       v = ci;
-                       if(v < 0) v = -v;
-                       if(cq > 0) {
-                               v += cq;
-                       } else {
-                               v -= cq;
-                       }
-                       if(v > 40) {
-                               Demod.posCount = 0;
-                               Demod.state = DEMOD_PHASE_REF_TRAINING;
-                               Demod.sumI = 0;
-                               Demod.sumQ = 0;
-                       }
-                       break;
-
-               case DEMOD_PHASE_REF_TRAINING:
-                       if(Demod.posCount < 8) {
-                               Demod.sumI += ci;
-                               Demod.sumQ += cq;
-                       } else if(Demod.posCount > 100) {
-                               // error, waited too long
-                               Demod.state = DEMOD_UNSYNCD;
-                       } else {
-                               MAKE_SOFT_DECISION();
-                               if(v < 0) {
-                                       Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
-                                       Demod.posCount = 0;
-                               }
-                       }
-                       Demod.posCount++;
-                       break;
-
-               case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:
-                       MAKE_SOFT_DECISION();
-                       if(v < 0) {
-                               Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
-                               Demod.posCount = 0;
-                       } else {
-                               if(Demod.posCount > 100) {
-                                       Demod.state = DEMOD_UNSYNCD;
-                               }
-                       }
-                       Demod.posCount++;
-                       break;
-
-               case DEMOD_GOT_FALLING_EDGE_OF_SOF:
-                       MAKE_SOFT_DECISION();
-                       if(v > 0) {
-                               if(Demod.posCount < 12) {
-                                       Demod.state = DEMOD_UNSYNCD;
-                               } else {
-                                       LED_C_ON(); // Got SOF
-                                       Demod.state = DEMOD_AWAITING_START_BIT;
-                                       Demod.posCount = 0;
-                                       Demod.len = 0;
-                                       Demod.metricN = 0;
-                                       Demod.metric = 0;
-                               }
-                       } else {
-                               if(Demod.posCount > 100) {
-                                       Demod.state = DEMOD_UNSYNCD;
-                               }
-                       }
-                       Demod.posCount++;
-                       break;
-
-               case DEMOD_AWAITING_START_BIT:
-                       MAKE_SOFT_DECISION();
-                       if(v > 0) {
-                               if(Demod.posCount > 10) {
-                                       Demod.state = DEMOD_UNSYNCD;
-                               }
-                       } else {
-                               Demod.bitCount = 0;
-                               Demod.posCount = 1;
-                               Demod.thisBit = v;
-                               Demod.shiftReg = 0;
-                               Demod.state = DEMOD_RECEIVING_DATA;
-                       }
-                       break;
-
-               case DEMOD_RECEIVING_DATA:
-                       MAKE_SOFT_DECISION();
-                       if(Demod.posCount == 0) {
-                               Demod.thisBit = v;
-                               Demod.posCount = 1;
-                       } else {
-                               Demod.thisBit += v;
-
-                               if(Demod.thisBit > 0) {
-                                       Demod.metric += Demod.thisBit;
-                               } else {
-                                       Demod.metric -= Demod.thisBit;
-                               }
-                               (Demod.metricN)++;
-
-                               Demod.shiftReg >>= 1;
-                               if(Demod.thisBit > 0) {
-                                       Demod.shiftReg |= 0x200;
-                               }
-
-                               Demod.bitCount++;
-                               if(Demod.bitCount == 10) {
-                                       uint16_t s = Demod.shiftReg;
-                                       if((s & 0x200) && !(s & 0x001)) {
-                                               uint8_t b = (s >> 1);
-                                               Demod.output[Demod.len] = b;
-                                               Demod.len++;
-                                               Demod.state = DEMOD_AWAITING_START_BIT;
-                                       } else if(s == 0x000) {
-                                               // This is EOF
-                                               LED_C_OFF();
-                                               Demod.state = DEMOD_UNSYNCD;
-                                               return TRUE;
-                                       } else {
-                                               Demod.state = DEMOD_UNSYNCD;
-                                       }
-                               }
-                               Demod.posCount = 0;
-                       }
-                       break;
-
-               default:
-                       Demod.state = DEMOD_UNSYNCD;
-                       break;
-       }
-
-       if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized...
-       return FALSE;
-}
-static void DemodReset()
-{
-       // Clear out the state of the "UART" that receives from the tag.
-       Demod.len = 0;
-       Demod.state = DEMOD_UNSYNCD;
-       memset(Demod.output, 0x00, MAX_FRAME_SIZE);
-}
-static void DemodInit(uint8_t *data)
-{
-       Demod.output = data;
-       DemodReset();
-}
-
-static void UartReset()
-{
-       Uart.byteCntMax = MAX_FRAME_SIZE;
-       Uart.state = STATE_UNSYNCD;
-       Uart.byteCnt = 0;
-       Uart.bitCnt = 0;
-}
-static void UartInit(uint8_t *data)
-{
-       Uart.output = data;
-       UartReset();
-}
-
-/*
- *  Demodulate the samples we received from the tag, also log to tracebuffer
- *  weTx: set to 'TRUE' if we behave like a reader
- *        set to 'FALSE' if we behave like a snooper
- *  quiet: set to 'TRUE' to disable debug output
- */
-static void GetSamplesFor14443Demod(int weTx, int n, int quiet)
-{
-       int max = 0;
-       int gotFrame = FALSE;
-       int lastRxCounter, ci, cq, samples = 0;
-
-       // Allocate memory from BigBuf for some buffers
-       // free all previous allocations first
-       BigBuf_free();
-       
-       // The response (tag -> reader) that we're receiving.
-       uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE);
-       
-       // The DMA buffer, used to stream samples from the FPGA
-       uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
-
-       // Set up the demodulator for tag -> reader responses.
-       DemodInit(receivedResponse);
-
-       // Setup and start DMA.
-       FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE);
-
-       uint8_t *upTo= dmaBuf;
-       lastRxCounter = DMA_BUFFER_SIZE;
-
-       // Signal field is ON with the appropriate LED:
-       if (weTx) LED_D_ON(); else LED_D_OFF();
-       // And put the FPGA in the appropriate mode
-       FpgaWriteConfWord(
-               FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
-               (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));
-
-       for(;;) {
-               int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;
-               if(behindBy > max) max = behindBy;
-
-               while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1))
-                                       > 2)
-               {
-                       ci = upTo[0];
-                       cq = upTo[1];
-                       upTo += 2;
-                       if(upTo >= dmaBuf + DMA_BUFFER_SIZE) {
-                               upTo = dmaBuf;
-                               AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
-                               AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
-                       }
-                       lastRxCounter -= 2;
-                       if(lastRxCounter <= 0) {
-                               lastRxCounter += DMA_BUFFER_SIZE;
-                       }
-
-                       samples += 2;
-
-                       if(Handle14443SamplesDemod(ci, cq)) {
-                               gotFrame = 1;
-                       }
-               }
-
-               if(samples > n) {
-                       break;
-               }
-       }
-       AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
-       if (!quiet) Dbprintf("%x %x %x", max, gotFrame, Demod.len);
-       //Tracing
-       if (tracing && Demod.len > 0) {
-               uint8_t parity[MAX_PARITY_SIZE];
-               GetParity(Demod.output, Demod.len, parity);
-               LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE);
-       }
-}
-
-//-----------------------------------------------------------------------------
-// Read the tag's response. We just receive a stream of slightly-processed
-// samples from the FPGA, which we will later do some signal processing on,
-// to get the bits.
-//-----------------------------------------------------------------------------
-/*static void GetSamplesFor14443(int weTx, int n)
-{
-       uint8_t *dest = (uint8_t *)BigBuf;
-       int c;
-
-       FpgaWriteConfWord(
-               FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
-               (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));
-
-       c = 0;
-       for(;;) {
-               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
-                       AT91C_BASE_SSC->SSC_THR = 0x43;
-               }
-               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-                       int8_t b;
-                       b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
-
-                       dest[c++] = (uint8_t)b;
-
-                       if(c >= n) {
-                               break;
-                       }
-               }
-       }
-}*/
-
-//-----------------------------------------------------------------------------
-// Transmit the command (to the tag) that was placed in ToSend[].
-//-----------------------------------------------------------------------------
-static void TransmitFor14443(void)
-{
-       int c;
-
-       FpgaSetupSsc();
-
-       while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
-               AT91C_BASE_SSC->SSC_THR = 0xff;
-       }
-
-       // Signal field is ON with the appropriate Red LED
-       LED_D_ON();
-       // Signal we are transmitting with the Green LED
-       LED_B_ON();
-       FpgaWriteConfWord(
-               FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
-
-       for(c = 0; c < 10;) {
-               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
-                       AT91C_BASE_SSC->SSC_THR = 0xff;
-                       c++;
-               }
-               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-                       volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
-                       (void)r;
-               }
-               WDT_HIT();
-       }
-
-       c = 0;
-       for(;;) {
-               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
-                       AT91C_BASE_SSC->SSC_THR = ToSend[c];
-                       c++;
-                       if(c >= ToSendMax) {
-                               break;
-                       }
-               }
-               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-                       volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
-                       (void)r;
-               }
-               WDT_HIT();
-       }
-       LED_B_OFF(); // Finished sending
-}
-
-//-----------------------------------------------------------------------------
-// Code a layer 2 command (string of octets, including CRC) into ToSend[],
-// so that it is ready to transmit to the tag using TransmitFor14443().
-//-----------------------------------------------------------------------------
-static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
-{
-       int i, j;
-       uint8_t b;
-
-       ToSendReset();
-
-       // Establish initial reference level
-       for(i = 0; i < 40; i++) {
-               ToSendStuffBit(1);
-       }
-       // Send SOF
-       for(i = 0; i < 10; i++) {
-               ToSendStuffBit(0);
-       }
-
-       for(i = 0; i < len; i++) {
-               // Stop bits/EGT
-               ToSendStuffBit(1);
-               ToSendStuffBit(1);
-               // Start bit
-               ToSendStuffBit(0);
-               // Data bits
-               b = cmd[i];
-               for(j = 0; j < 8; j++) {
-                       if(b & 1) {
-                               ToSendStuffBit(1);
-                       } else {
-                               ToSendStuffBit(0);
-                       }
-                       b >>= 1;
-               }
-       }
-       // Send EOF
-       ToSendStuffBit(1);
-       for(i = 0; i < 10; i++) {
-               ToSendStuffBit(0);
-       }
-       for(i = 0; i < 8; i++) {
-               ToSendStuffBit(1);
-       }
-
-       // And then a little more, to make sure that the last character makes
-       // it out before we switch to rx mode.
-       for(i = 0; i < 24; i++) {
-               ToSendStuffBit(1);
-       }
-
-       // Convert from last character reference to length
-       ToSendMax++;
-}
-
-//-----------------------------------------------------------------------------
-// Read an ISO 14443 tag. We send it some set of commands, and record the
-// responses.
-// The command name is misleading, it actually decodes the reponse in HEX
-// into the output buffer (read the result using hexsamples, not hisamples)
-//
-// obsolete function only for test
-//-----------------------------------------------------------------------------
-void AcquireRawAdcSamplesIso14443(uint32_t parameter)
-{
-       uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
-
-       SendRawCommand14443B(sizeof(cmd1),1,1,cmd1);
-}
-
-/**
-  Convenience function to encode, transmit and trace iso 14443b comms
-  **/
-static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len)
-{
-       CodeIso14443bAsReader(cmd, len);
-       TransmitFor14443();
-       if (tracing) {
-               uint8_t parity[MAX_PARITY_SIZE];
-               GetParity(cmd, len, parity);
-               LogTrace(cmd,len, 0, 0, parity, TRUE);
-       }
-}
-
-//-----------------------------------------------------------------------------
-// Read a SRI512 ISO 14443 tag.
-//
-// SRI512 tags are just simple memory tags, here we're looking at making a dump
-// of the contents of the memory. No anticollision algorithm is done, we assume
-// we have a single tag in the field.
-//
-// I tried to be systematic and check every answer of the tag, every CRC, etc...
-//-----------------------------------------------------------------------------
-void ReadSTMemoryIso14443(uint32_t dwLast)
-{
-       clear_trace();
-       set_tracing(TRUE);
-
-       uint8_t i = 0x00;
-
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       // Make sure that we start from off, since the tags are stateful;
-       // confusing things will happen if we don't reset them between reads.
-       LED_D_OFF();
-       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       SpinDelay(200);
-
-       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
-       FpgaSetupSsc();
-
-       // Now give it time to spin up.
-       // Signal field is on with the appropriate LED
-       LED_D_ON();
-       FpgaWriteConfWord(
-               FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
-       SpinDelay(200);
-
-       // First command: wake up the tag using the INITIATE command
-       uint8_t cmd1[] = { 0x06, 0x00, 0x97, 0x5b};
-
-       CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
-//    LED_A_ON();
-       GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
-//    LED_A_OFF();
-
-       if (Demod.len == 0) {
-       DbpString("No response from tag");
-       return;
-       } else {
-       Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x",
-               Demod.output[0], Demod.output[1],Demod.output[2]);
-       }
-       // There is a response, SELECT the uid
-       DbpString("Now SELECT tag:");
-       cmd1[0] = 0x0E; // 0x0E is SELECT
-       cmd1[1] = Demod.output[0];
-       ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
-       CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
-
-//    LED_A_ON();
-       GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
-//    LED_A_OFF();
-       if (Demod.len != 3) {
-       Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);
-       return;
-       }
-       // Check the CRC of the answer:
-       ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);
-       if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {
-       DbpString("CRC Error reading select response.");
-       return;
-       }
-       // Check response from the tag: should be the same UID as the command we just sent:
-       if (cmd1[1] != Demod.output[0]) {
-       Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]);
-       return;
-       }
-       // Tag is now selected,
-       // First get the tag's UID:
-       cmd1[0] = 0x0B;
-       ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]);
-       CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one
-
-//    LED_A_ON();
-       GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
-//    LED_A_OFF();
-       if (Demod.len != 10) {
-       Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);
-       return;
-       }
-       // The check the CRC of the answer (use cmd1 as temporary variable):
-       ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]);
-                  if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) {
-       Dbprintf("CRC Error reading block! - Below: expected, got %x %x",
-               (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]);
-       // Do not return;, let's go on... (we should retry, maybe ?)
-       }
-       Dbprintf("Tag UID (64 bits): %08x %08x",
-       (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4],
-       (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]);
-
-       // Now loop to read all 16 blocks, address from 0 to last block
-       Dbprintf("Tag memory dump, block 0 to %d",dwLast);
-       cmd1[0] = 0x08;
-       i = 0x00;
-       dwLast++;
-       for (;;) {
-                  if (i == dwLast) {
-                       DbpString("System area block (0xff):");
-                       i = 0xff;
-               }
-               cmd1[1] = i;
-               ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
-               CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
-
-//         LED_A_ON();
-               GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
-//         LED_A_OFF();
-               if (Demod.len != 6) { // Check if we got an answer from the tag
-               DbpString("Expected 6 bytes from tag, got less...");
-               return;
-               }
-               // The check the CRC of the answer (use cmd1 as temporary variable):
-               ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]);
-                       if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) {
-               Dbprintf("CRC Error reading block! - Below: expected, got %x %x",
-                       (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]);
-               // Do not return;, let's go on... (we should retry, maybe ?)
-               }
-               // Now print out the memory location:
-               Dbprintf("Address=%x, Contents=%x, CRC=%x", i,
-               (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0],
-               (Demod.output[4]<<8)+Demod.output[5]);
-               if (i == 0xff) {
-               break;
-               }
-               i++;
-       }
-}
-
-
-//=============================================================================
-// Finally, the `sniffer' combines elements from both the reader and
-// simulated tag, to show both sides of the conversation.
-//=============================================================================
-
-//-----------------------------------------------------------------------------
-// Record the sequence of commands sent by the reader to the tag, with
-// triggering so that we start recording at the point that the tag is moved
-// near the reader.
-//-----------------------------------------------------------------------------
-/*
- * Memory usage for this function, (within BigBuf)
- * 0-4095 : Demodulated samples receive (4096 bytes) - DEMOD_TRACE_SIZE
- * 4096-6143 : Last Received command, 2048 bytes (reader->tag) - READER_TAG_BUFFER_SIZE
- * 6144-8191 : Last Received command, 2048 bytes(tag->reader) - TAG_READER_BUFFER_SIZE
- * 8192-9215 : DMA Buffer, 1024 bytes (samples) - DEMOD_DMA_BUFFER_SIZE
- */
-void RAMFUNC SnoopIso14443(void)
-{
-       // We won't start recording the frames that we acquire until we trigger;
-       // a good trigger condition to get started is probably when we see a
-       // response from the tag.
-       int triggered = TRUE;
-
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       BigBuf_free();
-
-       clear_trace();
-       set_tracing(TRUE);
-
-       // The DMA buffer, used to stream samples from the FPGA
-       uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
-       int lastRxCounter;
-       uint8_t *upTo;
-       int ci, cq;
-       int maxBehindBy = 0;
-
-       // Count of samples received so far, so that we can include timing
-       // information in the trace buffer.
-       int samples = 0;
-
-       DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
-       UartInit(BigBuf_malloc(MAX_FRAME_SIZE));
-
-       // Print some debug information about the buffer sizes
-       Dbprintf("Snooping buffers initialized:");
-       Dbprintf("  Trace: %i bytes", BigBuf_max_traceLen());
-       Dbprintf("  Reader -> tag: %i bytes", MAX_FRAME_SIZE);
-       Dbprintf("  tag -> Reader: %i bytes", MAX_FRAME_SIZE);
-       Dbprintf("  DMA: %i bytes", DMA_BUFFER_SIZE);
-
-       // Signal field is off with the appropriate LED
-       LED_D_OFF();
-
-       // And put the FPGA in the appropriate mode
-       FpgaWriteConfWord(
-               FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
-               FPGA_HF_READER_RX_XCORR_SNOOP);
-       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
-
-       // Setup for the DMA.
-       FpgaSetupSsc();
-       upTo = dmaBuf;
-       lastRxCounter = DMA_BUFFER_SIZE;
-       FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE);
-       uint8_t parity[MAX_PARITY_SIZE];
-       LED_A_ON();
-               
-       // And now we loop, receiving samples.
-       for(;;) {
-               int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &
-                                                               (DMA_BUFFER_SIZE-1);
-               if(behindBy > maxBehindBy) {
-                       maxBehindBy = behindBy;
-                       if(behindBy > (9*DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not?
-                               Dbprintf("blew circular buffer! behindBy=0x%x", behindBy);
-                               break;
-                       }
-               }
-               if(behindBy < 2) continue;
-
-               ci = upTo[0];
-               cq = upTo[1];
-               upTo += 2;
-               lastRxCounter -= 2;
-               if(upTo >= dmaBuf + DMA_BUFFER_SIZE) {
-                       upTo = dmaBuf;
-                       lastRxCounter += DMA_BUFFER_SIZE;
-                       AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf;
-                       AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
-               }
-
-               samples += 2;
-
-               if(Handle14443UartBit(ci & 1)) {
-                       if(triggered && tracing) {
-                               GetParity(Uart.output, Uart.byteCnt, parity);
-                               LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE);
-                       }
-                       if(Uart.byteCnt==0) Dbprintf("[1] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt);
-
-                       /* And ready to receive another command. */
-                       UartReset();
-                       /* And also reset the demod code, which might have been */
-                       /* false-triggered by the commands from the reader. */
-                       DemodReset();
-               }
-               if(Handle14443UartBit(cq & 1)) {
-                       if(triggered && tracing) {
-                               GetParity(Uart.output, Uart.byteCnt, parity);
-                               LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE);
-                       }
-                       if(Uart.byteCnt==0) Dbprintf("[2] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt);
-
-                       /* And ready to receive another command. */
-                       UartReset();
-                       /* And also reset the demod code, which might have been */
-                       /* false-triggered by the commands from the reader. */
-                       DemodReset();
-               }
-
-               if(Handle14443SamplesDemod(ci, cq)) {
-
-                       //Use samples as a time measurement
-                       if(tracing)
-                       {
-                               uint8_t parity[MAX_PARITY_SIZE];
-                               GetParity(Demod.output, Demod.len, parity);
-                               LogTrace(Demod.output,Demod.len,samples, samples,parity,FALSE);
-                       }
-                       triggered = TRUE;
-                       LED_A_OFF();
-                       LED_B_ON();
-
-                       // And ready to receive another response.
-                       DemodReset();
-               }
-               WDT_HIT();
-
-               if(!tracing) {
-                       DbpString("Reached trace limit");
-                       break;
-               }
-
-               if(BUTTON_PRESS()) {
-                       DbpString("cancelled");
-                       break;
-               }
-       }
-       FpgaDisableSscDma();
-       LED_A_OFF();
-       LED_B_OFF();
-       LED_C_OFF();
-       AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
-       DbpString("Snoop statistics:");
-       Dbprintf("  Max behind by: %i", maxBehindBy);
-       Dbprintf("  Uart State: %x", Uart.state);
-       Dbprintf("  Uart ByteCnt: %i", Uart.byteCnt);
-       Dbprintf("  Uart ByteCntMax: %i", Uart.byteCntMax);
-       Dbprintf("  Trace length: %i", BigBuf_get_traceLen());
-}
-
-/*
- * Send raw command to tag ISO14443B
- * @Input
- * datalen     len of buffer data
- * recv        bool when true wait for data from tag and send to client
- * powerfield  bool leave the field on when true
- * data        buffer with byte to send
- *
- * @Output
- * none
- *
- */
-
-void SendRawCommand14443B(uint32_t datalen, uint32_t recv,uint8_t powerfield, uint8_t data[])
-{
-       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
-       if(!powerfield)
-       {
-               // Make sure that we start from off, since the tags are stateful;
-               // confusing things will happen if we don't reset them between reads.
-               FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-               LED_D_OFF();
-               SpinDelay(200);
-       }
-
-       if(!GETBIT(GPIO_LED_D))
-       {
-               SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
-               FpgaSetupSsc();
-
-               // Now give it time to spin up.
-               // Signal field is on with the appropriate LED
-               LED_D_ON();
-               FpgaWriteConfWord(
-                       FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
-               SpinDelay(200);
-       }
-
-       CodeAndTransmit14443bAsReader(data, datalen);
-
-       if(recv)
-       {
-               GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
-               uint16_t iLen = MIN(Demod.len,USB_CMD_DATA_SIZE);
-               cmd_send(CMD_ACK,iLen,0,0,Demod.output,iLen);
-       }
-       if(!powerfield)
-       {
-               FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-               LED_D_OFF();
-       }
-}
-
index cf64da2fbcdb3b8c3f6790cabac7429eef89d74f..e1ec477c454ebb1f9f92f5aeb301edf454940d0b 100644 (file)
@@ -15,7 +15,6 @@
 #include "util.h"
 #include "string.h"
 #include "cmd.h"
-
 #include "iso14443crc.h"
 #include "iso14443a.h"
 #include "crapto1.h"
@@ -213,6 +212,12 @@ void AppendCrc14443a(uint8_t* data, int len)
        ComputeCrc14443(CRC_14443_A,data,len,data+len,data+len+1);
 }
 
+void AppendCrc14443b(uint8_t* data, int len)
+{
+       ComputeCrc14443(CRC_14443_B,data,len,data+len,data+len+1);
+}
+
+
 //=============================================================================
 // ISO 14443 Type A - Miller decoder
 //=============================================================================
@@ -232,13 +237,17 @@ void AppendCrc14443a(uint8_t* data, int len)
 static tUart Uart;
 
 // Lookup-Table to decide if 4 raw bits are a modulation.
-// We accept two or three consecutive "0" in any position with the rest "1"
+// We accept the following:
+// 0001  -   a 3 tick wide pause
+// 0011  -   a 2 tick wide pause, or a three tick wide pause shifted left
+// 0111  -   a 2 tick wide pause shifted left
+// 1001  -   a 2 tick wide pause shifted right
 const bool Mod_Miller_LUT[] = {
-       TRUE,  TRUE,  FALSE, TRUE,  FALSE, FALSE, FALSE, FALSE,
-       TRUE,  TRUE,  FALSE, FALSE, TRUE,  FALSE, FALSE, FALSE
+       FALSE,  TRUE, FALSE, TRUE,  FALSE, FALSE, FALSE, TRUE,
+       FALSE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
 };
-#define IsMillerModulationNibble1(b) (Mod_Miller_LUT[(b & 0x00F0) >> 4])
-#define IsMillerModulationNibble2(b) (Mod_Miller_LUT[(b & 0x000F)])
+#define IsMillerModulationNibble1(b) (Mod_Miller_LUT[(b & 0x000000F0) >> 4])
+#define IsMillerModulationNibble2(b) (Mod_Miller_LUT[(b & 0x0000000F)])
 
 void UartReset()
 {
@@ -248,16 +257,19 @@ void UartReset()
        Uart.parityLen = 0;                                     // number of decoded parity bytes
        Uart.shiftReg = 0;                                      // shiftreg to hold decoded data bits
        Uart.parityBits = 0;                            // holds 8 parity bits
-       Uart.twoBits = 0x0000;                          // buffer for 2 Bits
-       Uart.highCnt = 0;
        Uart.startTime = 0;
        Uart.endTime = 0;
+       
+       Uart.byteCntMax = 0;
+       Uart.posCnt = 0;
+       Uart.syncBit = 9999;
 }
 
 void UartInit(uint8_t *data, uint8_t *parity)
 {
        Uart.output = data;
        Uart.parity = parity;
+       Uart.fourBits = 0x00000000;                     // clear the buffer for 4 Bits
        UartReset();
 }
 
@@ -265,40 +277,44 @@ void UartInit(uint8_t *data, uint8_t *parity)
 static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time)
 {
 
-       Uart.twoBits = (Uart.twoBits << 8) | bit;
+       Uart.fourBits = (Uart.fourBits << 8) | bit;
        
        if (Uart.state == STATE_UNSYNCD) {                                                                                      // not yet synced
        
-               if (Uart.highCnt < 2) {                                                                                                 // wait for a stable unmodulated signal
-                       if (Uart.twoBits == 0xffff) {
-                               Uart.highCnt++;
-                       } else {
-                               Uart.highCnt = 0;
-                       }
-               } else {        
-                       Uart.syncBit = 0xFFFF;                                                                                          // not set
-                                                                                                                                                               // we look for a ...1111111100x11111xxxxxx pattern (the start bit)
-                       if              ((Uart.twoBits & 0xDF00) == 0x1F00) Uart.syncBit = 8;           // mask is   11x11111 xxxxxxxx, 
-                                                                                                                                                               // check for 00x11111 xxxxxxxx
-                       else if ((Uart.twoBits & 0xEF80) == 0x8F80) Uart.syncBit = 7;           // both masks shifted right one bit, left padded with '1'
-                       else if ((Uart.twoBits & 0xF7C0) == 0xC7C0) Uart.syncBit = 6;           // ...
-                       else if ((Uart.twoBits & 0xFBE0) == 0xE3E0) Uart.syncBit = 5;
-                       else if ((Uart.twoBits & 0xFDF0) == 0xF1F0) Uart.syncBit = 4;
-                       else if ((Uart.twoBits & 0xFEF8) == 0xF8F8) Uart.syncBit = 3;
-                       else if ((Uart.twoBits & 0xFF7C) == 0xFC7C) Uart.syncBit = 2;
-                       else if ((Uart.twoBits & 0xFFBE) == 0xFE3E) Uart.syncBit = 1;
-                       if (Uart.syncBit != 0xFFFF) {                                                                           // found a sync bit
+               Uart.syncBit = 9999;                                                                                                    // not set
+               
+               // 00x11111 2|3 ticks pause followed by 6|5 ticks unmodulated           Sequence Z (a "0" or "start of communication")
+               // 11111111 8 ticks unmodulation                                                                        Sequence Y (a "0" or "end of communication" or "no information")
+               // 111100x1 4 ticks unmodulated followed by 2|3 ticks pause                     Sequence X (a "1")
+
+               // The start bit is one ore more Sequence Y followed by a Sequence Z (... 11111111 00x11111). We need to distinguish from
+               // Sequence X followed by Sequence Y followed by Sequence Z     (111100x1 11111111 00x11111)
+               // we therefore look for a ...xx1111 11111111 00x11111xxxxxx... pattern 
+               // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's)
+               //
+#define ISO14443A_STARTBIT_MASK                0x07FFEF80              // mask is    00001111 11111111 1110 1111 10000000
+#define ISO14443A_STARTBIT_PATTERN     0x07FF8F80              // pattern is 00001111 11111111 1000 1111 10000000
+
+               if              ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 0)) == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7;
+               else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 1)) == ISO14443A_STARTBIT_PATTERN >> 1) Uart.syncBit = 6;
+               else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 2)) == ISO14443A_STARTBIT_PATTERN >> 2) Uart.syncBit = 5;
+               else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 3)) == ISO14443A_STARTBIT_PATTERN >> 3) Uart.syncBit = 4;
+               else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 4)) == ISO14443A_STARTBIT_PATTERN >> 4) Uart.syncBit = 3;
+               else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 5)) == ISO14443A_STARTBIT_PATTERN >> 5) Uart.syncBit = 2;
+               else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 6)) == ISO14443A_STARTBIT_PATTERN >> 6) Uart.syncBit = 1;
+               else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 7)) == ISO14443A_STARTBIT_PATTERN >> 7) Uart.syncBit = 0;
+
+               if (Uart.syncBit != 9999) {                                                                                             // found a sync bit
                                Uart.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8);
                                Uart.startTime -= Uart.syncBit;
                                Uart.endTime = Uart.startTime;
                                Uart.state = STATE_START_OF_COMMUNICATION;
                        }
-               }
 
        } else {
 
-               if (IsMillerModulationNibble1(Uart.twoBits >> Uart.syncBit)) {                  
-                       if (IsMillerModulationNibble2(Uart.twoBits >> Uart.syncBit)) {          // Modulation in both halves - error
+               if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) {                 
+                       if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) {         // Modulation in both halves - error
                                UartReset();
                        } else {                                                                                                                        // Modulation in first half = Sequence Z = logic "0"
                                if (Uart.state == STATE_MILLER_X) {                                                             // error - must not follow after X
@@ -322,7 +338,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time)
                                }
                        }
                } else {
-                       if (IsMillerModulationNibble2(Uart.twoBits >> Uart.syncBit)) {          // Modulation second half = Sequence X = logic "1"
+                       if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) {         // Modulation second half = Sequence X = logic "1"
                                Uart.bitCount++;
                                Uart.shiftReg = (Uart.shiftReg >> 1) | 0x100;                                   // add a 1 to the shiftreg
                                Uart.state = STATE_MILLER_X;
@@ -358,12 +374,10 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time)
                                                return TRUE;                                                                                    // we are finished with decoding the raw data sequence
                                        } else {
                                                UartReset();                                                                                    // Nothing received - start over
-                                               Uart.highCnt = 1;
                                        }
                                }
                                if (Uart.state == STATE_START_OF_COMMUNICATION) {                               // error - must not follow directly after SOC
                                        UartReset();
-                                       Uart.highCnt = 1;
                                } else {                                                                                                                // a logic "0"
                                        Uart.bitCount++;
                                        Uart.shiftReg = (Uart.shiftReg >> 1);                                           // add a 0 to the shiftreg
@@ -430,6 +444,11 @@ void DemodReset()
        Demod.highCnt = 0;
        Demod.startTime = 0;
        Demod.endTime = 0;
+       
+       //
+       Demod.bitCount = 0;
+       Demod.syncBit = 0xFFFF;
+       Demod.samples = 0;
 }
 
 void DemodInit(uint8_t *data, uint8_t *parity)
@@ -528,9 +547,7 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non
                                }
                        }
                }
-                       
        } 
-
     return FALSE;      // not finished yet, need more data
 }
 
@@ -544,7 +561,7 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non
 // triggering so that we start recording at the point that the tag is moved
 // near the reader.
 //-----------------------------------------------------------------------------
-void RAMFUNC SnoopIso14443a(uint8_t param) {
+void RAMFUNC SniffIso14443a(uint8_t param) {
        // param:
        // bit 0 - trigger from first card answer
        // bit 1 - trigger from first reader 7-bit request
@@ -656,6 +673,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
                                        }
                                        /* And ready to receive another command. */
                                        UartReset();
+                                       //UartInit(receivedCmd, receivedCmdPar);
                                        /* And also reset the demod code, which might have been */
                                        /* false-triggered by the commands from the reader. */
                                        DemodReset();
@@ -680,6 +698,9 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
 
                                        // And ready to receive another response.
                                        DemodReset();
+                                       // And reset the Miller decoder including itS (now outdated) input buffer
+                                       UartInit(receivedCmd, receivedCmdPar);
+
                                        LED_C_OFF();
                                } 
                                TagIsActive = (Demod.state != DEMOD_UNSYNCD);
@@ -892,7 +913,8 @@ bool prepare_tag_modulation(tag_response_info_t* response_info, size_t max_buffe
 // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) 
 // 28 * 8 data bits, 28 * 1 parity bits, 7 start bits, 7 stop bits, 7 correction bits
 // -> need 273 bytes buffer
-#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 273
+// 44 * 8 data bits, 44 * 1 parity bits, 9 start bits, 9 stop bits, 9 correction bits
+#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 370  //273
 
 bool prepare_allocated_tag_modulation(tag_response_info_t* response_info) {
   // Retrieve and store the current buffer index
@@ -915,10 +937,23 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info) {
 // Main loop of simulated tag: receive commands from reader, decide what
 // response to send, and send it.
 //-----------------------------------------------------------------------------
-void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
+void SimulateIso14443aTag(int tagType, int flags, int uid_2nd, byte_t* data)
 {
+
+       //Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2
+       // This can be used in a reader-only attack.
+       // (it can also be retrieved via 'hf 14a list', but hey...
+       uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0,0,0};
+       uint8_t ar_nr_collected = 0;
+       
        uint8_t sak;
 
+       uint8_t blockzeros[512];
+       memset(blockzeros, 0x00, sizeof(blockzeros));
+                                       
+       // PACK response to PWD AUTH for EV1/NTAG
+       uint8_t response8[4];
+       
        // The first response contains the ATQA (note: bytes are transmitted in reverse order).
        uint8_t response1[2];
        
@@ -931,7 +966,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
                } break;
                case 2: { // MIFARE Ultralight
                        // Says: I am a stupid memory tag, no crypto
-                       response1[0] = 0x04;
+                       response1[0] = 0x44;
                        response1[1] = 0x00;
                        sak = 0x00;
                } break;
@@ -952,6 +987,22 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
                        response1[0] = 0x01;
                        response1[1] = 0x0f;
                        sak = 0x01;
+               } break;
+               case 6: { // MIFARE Mini
+                       // Says: I am a Mifare Mini, 320b
+                       response1[0] = 0x44;
+                       response1[1] = 0x00;
+                       sak = 0x09;
+               } break;
+               case 7: { // NTAG?
+                       // Says: I am a NTAG, 
+                       response1[0] = 0x44;
+                       response1[1] = 0x00;
+                       sak = 0x00;
+                       // PACK
+                       response8[0] = 0x80;
+                       response8[1] = 0x80;
+                       ComputeCrc14443(CRC_14443_A, response8, 2, &response8[2], &response8[3]);
                } break;                
                default: {
                        Dbprintf("Error: unkown tagtype (%d)",tagType);
@@ -965,17 +1016,24 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
        // Check if the uid uses the (optional) part
        uint8_t response2a[5] = {0x00};
        
-       if (uid_2nd) {
+       if (flags & FLAG_7B_UID_IN_DATA) {
                response2[0] = 0x88;
-               num_to_bytes(uid_1st,3,response2+1);
-               num_to_bytes(uid_2nd,4,response2a);
+               response2[1] = data[0];
+               response2[2] = data[1];
+               response2[3] = data[2];
+
+               response2a[0] = data[3];
+               response2a[1] = data[4];
+               response2a[2] = data[5];
+               response2a[3] = data[6]; //??
                response2a[4] = response2a[0] ^ response2a[1] ^ response2a[2] ^ response2a[3];
 
                // Configure the ATQA and SAK accordingly
                response1[0] |= 0x40;
                sak |= 0x04;
        } else {
-               num_to_bytes(uid_1st,4,response2);
+               memcpy(response2, data, 4);
+               //num_to_bytes(uid_1st,4,response2);
                // Configure the ATQA and SAK accordingly
                response1[0] &= 0xBF;
                sak &= 0xFB;
@@ -994,7 +1052,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
        response3a[0] = sak & 0xFB;
        ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]);
 
-       uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce
+       uint8_t response5[] = { 0x01, 0x01, 0x01, 0x01 }; // Very random tag nonce
        uint8_t response6[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS: 
        // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, 
        // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
@@ -1002,7 +1060,11 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
        // TC(1) = 0x02: CID supported, NAD not supported
        ComputeCrc14443(CRC_14443_A, response6, 4, &response6[4], &response6[5]);
 
-       #define TAG_RESPONSE_COUNT 7
+       // Prepare GET_VERSION (different for EV-1 / NTAG)
+       //uint8_t response7_EV1[] = {0x00, 0x04, 0x03, 0x01, 0x01, 0x00, 0x0b, 0x03, 0xfd, 0xf7};  //EV1 48bytes VERSION.
+       uint8_t response7_NTAG[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x11, 0x03, 0x01, 0x9e}; //NTAG 215
+       
+       #define TAG_RESPONSE_COUNT 9
        tag_response_info_t responses[TAG_RESPONSE_COUNT] = {
                { .response = response1,  .response_n = sizeof(response1)  },  // Answer to request - respond with card type
                { .response = response2,  .response_n = sizeof(response2)  },  // Anticollision cascade1 - respond with uid
@@ -1011,6 +1073,8 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
                { .response = response3a, .response_n = sizeof(response3a) },  // Acknowledge select - cascade 2
                { .response = response5,  .response_n = sizeof(response5)  },  // Authentication answer (random nonce)
                { .response = response6,  .response_n = sizeof(response6)  },  // dummy ATS (pseudo-ATR), answer to RATS
+               { .response = response7_NTAG,  .response_n = sizeof(response7_NTAG)  },  // EV1/NTAG GET_VERSION response
+               { .response = response8,   .response_n = sizeof(response8) },  // EV1/NTAG PACK response
        };
 
        // Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
@@ -1086,10 +1150,57 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
                } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) {   // Received a SELECT (cascade 2)
                        p_response = &responses[4]; order = 30;
                } else if(receivedCmd[0] == 0x30) {     // Received a (plain) READ
-                       EmSendCmdEx(data+(4*receivedCmd[1]),16,false);
-                       // Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]);
-                       // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
-                       p_response = NULL;
+                       uint8_t block = receivedCmd[1];
+                       if ( tagType == 7 ) {
+                               
+                               if ( block < 4 ) {
+                                   //NTAG 215
+                                       uint8_t start = 4 * block;
+                                       
+                                       uint8_t blockdata[50] = {
+                                       data[0],data[1],data[2], 0x88 ^ data[0] ^ data[1] ^ data[2],
+                                       data[3],data[4],data[5],data[6],
+                                       data[3] ^ data[4] ^ data[5] ^ data[6],0x48,0x0f,0xe0,
+                                       0xe1,0x10,0x12,0x00,
+                                       0x03,0x00,0xfe,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};
+                                       ComputeCrc14443(CRC_14443_A, blockdata+start, 16, blockdata+start+17, blockdata+start+18);
+                                       EmSendCmdEx( blockdata+start, 18, false);
+                               } else {                                
+                                       ComputeCrc14443(CRC_14443_A, blockzeros,16, blockzeros+17,blockzeros+18);
+                                       EmSendCmdEx(blockzeros,18,false);
+                               }
+                               p_response = NULL;
+                               
+                       } else {                        
+                               EmSendCmdEx(data+(4*block),16,false);
+                               // Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]);
+                               // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
+                               p_response = NULL;
+                       }
+               } else if(receivedCmd[0] == 0x3A) {     // Received a FAST READ   -- just returns all zeros.
+                               uint8_t len = (receivedCmd[2]- receivedCmd[1] ) * 4;
+                               ComputeCrc14443(CRC_14443_A, blockzeros,len, blockzeros+len+1, blockzeros+len+2);
+                               EmSendCmdEx(blockzeros,len+2,false);                            
+                               p_response = NULL;                      
+               } else if(receivedCmd[0] == 0x3C && tagType == 7) {     // Received a READ SIGNATURE -- 
+                               // ECC data,  taken from a NTAG215 amiibo token. might work. LEN: 32, + 2 crc
+                               uint8_t data[] = {0x56,0x06,0xa6,0x4f,0x43,0x32,0x53,0x6f,
+                                                                 0x43,0xda,0x45,0xd6,0x61,0x38,0xaa,0x1e,
+                                                                 0xcf,0xd3,0x61,0x36,0xca,0x5f,0xbb,0x05,
+                                                                 0xce,0x21,0x24,0x5b,0xa6,0x7a,0x79,0x07,
+                                                                 0x00,0x00};
+                               ComputeCrc14443(CRC_14443_A, data, sizeof(data), data+33, data+34);
+                               EmSendCmdEx(data,sizeof(data),false);                           
+                               p_response = NULL;                                      
+               } else if(receivedCmd[0] == 0x39 && tagType == 7) {     // Received a READ COUNTER -- 
+                               uint8_t data[] =  {0x00,0x00,0x00,0x00,0x00};
+                               ComputeCrc14443(CRC_14443_A, data, sizeof(data), data+4, data+5);
+                               EmSendCmdEx(data,sizeof(data),false);                           
+                               p_response = NULL;                      
                } else if(receivedCmd[0] == 0x50) {     // Received a HALT
 
                        if (tracing) {
@@ -1097,7 +1208,12 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
                        }
                        p_response = NULL;
                } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) {   // Received an authentication request
-                       p_response = &responses[5]; order = 7;
+                                       
+                       if ( tagType == 7 ) {   // IF NTAG /EV1  0x60 == GET_VERSION, not a authentication request.
+                               p_response = &responses[7];
+                       } else {
+                               p_response = &responses[5]; order = 7;
+                       }
                } else if(receivedCmd[0] == 0xE0) {     // Received a RATS request
                        if (tagType == 1 || tagType == 2) {     // RATS not supported
                                EmSend4bit(CARD_NACK_NA);
@@ -1109,10 +1225,56 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
                        if (tracing) {
                                LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE);
                        }
+                       uint32_t nonce = bytes_to_num(response5,4);
                        uint32_t nr = bytes_to_num(receivedCmd,4);
                        uint32_t ar = bytes_to_num(receivedCmd+4,4);
-                       Dbprintf("Auth attempt {nr}{ar}: %08x %08x",nr,ar);
-               } else {
+                       //Dbprintf("Auth attempt {nonce}{nr}{ar}: %08x %08x %08x", nonce, nr, ar);
+
+                       if(flags & FLAG_NR_AR_ATTACK )
+                       {
+                               if(ar_nr_collected < 2){
+                                       // Avoid duplicates... probably not necessary, nr should vary. 
+                                       //if(ar_nr_responses[3] != nr){                                         
+                                               ar_nr_responses[ar_nr_collected*5]   = 0;
+                                               ar_nr_responses[ar_nr_collected*5+1] = 0;
+                                               ar_nr_responses[ar_nr_collected*5+2] = nonce;
+                                               ar_nr_responses[ar_nr_collected*5+3] = nr;
+                                               ar_nr_responses[ar_nr_collected*5+4] = ar;
+                                               ar_nr_collected++;
+                                       //}
+                               }                       
+
+                               if(ar_nr_collected > 1 ) {
+                               
+                                       if (MF_DBGLEVEL >= 2) {
+                                                       Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:");
+                                                       Dbprintf("../tools/mfkey/mfkey32 %07x%08x %08x %08x %08x %08x %08x",
+                                                               ar_nr_responses[0], // UID1
+                                                               ar_nr_responses[1], // UID2
+                                                               ar_nr_responses[2], // NT
+                                                               ar_nr_responses[3], // AR1
+                                                               ar_nr_responses[4], // NR1
+                                                               ar_nr_responses[8], // AR2
+                                                               ar_nr_responses[9]  // NR2
+                                                       );
+                                       }
+                                       uint8_t len = ar_nr_collected*5*4;
+                                       cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,len,0,&ar_nr_responses,len);
+                                       ar_nr_collected = 0;
+                                       memset(ar_nr_responses, 0x00, len);
+                               }
+                       }
+               } else if (receivedCmd[0] == 0x1a ) // ULC authentication
+               {
+                       
+               }
+               else if (receivedCmd[0] == 0x1b) // NTAG / EV-1 authentication
+               {
+                       if ( tagType == 7 ) {
+                               p_response =  &responses[8]; // PACK response
+                       }
+               }
+               else {
                        // Check for ISO 14443A-4 compliant commands, look at left nibble
                        switch (receivedCmd[0]) {
 
@@ -1215,6 +1377,8 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
                }
        }
 
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       
        Dbprintf("%x %x %x", happened, happened2, cmdsRecvd);
        LED_A_OFF();
        BigBuf_free_keep_EM();
@@ -1337,7 +1501,7 @@ void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8
                }
 
                // Only transmit parity bit if we transmitted a complete byte
-               if (j == 8) {
+               if (j == 8 && parity != NULL) {
                        // Get the parity bit
                        if (parity[i>>3] & (0x80 >> (i&0x0007))) {
                                // Sequence X
@@ -1601,7 +1765,7 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start
 //-----------------------------------------------------------------------------
 static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset)
 {
-       uint32_t c;
+       uint32_t c = 0x00;
        
        // Set FPGA mode to "reader listen mode", no modulation (listen
        // only, since we are receiving, not transmitting).
@@ -1615,7 +1779,6 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive
        // clear RXRDY:
     uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
 
-       c = 0;
        for(;;) {
                WDT_HIT();
 
@@ -1631,6 +1794,7 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive
        }
 }
 
+
 void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing)
 {
        CodeIso14443aBitsAsReaderPar(frame, bits, par);
@@ -1646,11 +1810,13 @@ void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t
        }
 }
 
+
 void ReaderTransmitPar(uint8_t* frame, uint16_t len, uint8_t *par, uint32_t *timing)
 {
   ReaderTransmitBitsPar(frame, len*8, par, timing);
 }
 
+
 void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing)
 {
   // Generate parity and redirect
@@ -1659,6 +1825,7 @@ void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing)
   ReaderTransmitBitsPar(frame, len, par, timing);
 }
 
+
 void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing)
 {
   // Generate parity and redirect
@@ -1719,6 +1886,11 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
                memset(uid_ptr,0,10);
        }
 
+       // check for proprietary anticollision:
+       if ((resp[0] & 0x1F) == 0) {
+               return 3;
+       }
+       
        // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in
        // which case we need to make a cascade 2 request and select - this is a long UID
        // While the UID is not complete, the 3nd bit (from the right) is set in the SAK.
@@ -1851,7 +2023,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
        DemodReset();
        UartReset();
        NextTransferTime = 2*DELAY_ARM2AIR_AS_READER;
-       iso14a_set_timeout(1050); // 10ms default
+       iso14a_set_timeout(10*106); // 10ms default
 }
 
 int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
@@ -1927,15 +2099,38 @@ void ReaderIso14443a(UsbCommand *c)
 
        if(param & ISO14A_RAW) {
                if(param & ISO14A_APPEND_CRC) {
-                       AppendCrc14443a(cmd,len);
+                       if(param & ISO14A_TOPAZMODE) {
+                               AppendCrc14443b(cmd,len);
+                       } else {
+                               AppendCrc14443a(cmd,len);
+                       }
                        len += 2;
                        if (lenbits) lenbits += 16;
                }
-               if(lenbits>0) {
+               if(lenbits>0) {                         // want to send a specific number of bits (e.g. short commands)
+                       if(param & ISO14A_TOPAZMODE) {
+                               int bits_to_send = lenbits;
+                               uint16_t i = 0;
+                               ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 7), NULL, NULL);             // first byte is always short (7bits) and no parity
+                               bits_to_send -= 7;
+                               while (bits_to_send > 0) {
+                                       ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 8), NULL, NULL);     // following bytes are 8 bit and no parity
+                                       bits_to_send -= 8;
+                               }
+                       } else {
                        GetParity(cmd, lenbits/8, par);
-                       ReaderTransmitBitsPar(cmd, lenbits, par, NULL);
+                               ReaderTransmitBitsPar(cmd, lenbits, par, NULL);                                                 // bytes are 8 bit with odd parity
+                       }
+               } else {                                        // want to send complete bytes only
+                       if(param & ISO14A_TOPAZMODE) {
+                               uint16_t i = 0;
+                               ReaderTransmitBitsPar(&cmd[i++], 7, NULL, NULL);                                                // first byte: 7 bits, no paritiy
+                               while (i < len) {
+                                       ReaderTransmitBitsPar(&cmd[i++], 8, NULL, NULL);                                        // following bytes: 8 bits, no paritiy
+                               }
                } else {
-                       ReaderTransmit(cmd,len, NULL);
+                               ReaderTransmit(cmd,len, NULL);                                                                                  // 8 bits, odd parity
+                       }
                }
                arg0 = ReaderReceive(buf, par);
                cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf));
@@ -1959,13 +2154,11 @@ void ReaderIso14443a(UsbCommand *c)
 // Therefore try in alternating directions.
 int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
 
-       uint16_t i;
-       uint32_t nttmp1, nttmp2;
-
        if (nt1 == nt2) return 0;
 
-       nttmp1 = nt1;
-       nttmp2 = nt2;
+       uint16_t i;
+       uint32_t nttmp1 = nt1;
+       uint32_t nttmp2 = nt2;
        
        for (i = 1; i < 32768; i++) {
                nttmp1 = prng_successor(nttmp1, 1);
@@ -1984,28 +2177,27 @@ int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
 // Cloning MiFare Classic Rail and Building Passes, Anywhere, Anytime"
 // (article by Nicolas T. Courtois, 2009)
 //-----------------------------------------------------------------------------
-void ReaderMifare(bool first_try)
-{
-       // Mifare AUTH
-       uint8_t mf_auth[]    = { 0x60,0x00,0xf5,0x7b };
-       uint8_t mf_nr_ar[]   = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
-       static uint8_t mf_nr_ar3;
-
-       uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
-       uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
-
+void ReaderMifare(bool first_try) {
        // free eventually allocated BigBuf memory. We want all for tracing.
        BigBuf_free();
        
        clear_trace();
        set_tracing(TRUE);
 
+       // Mifare AUTH
+       uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b };
+       uint8_t mf_nr_ar[8] = { 0x00 }; //{ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 };
+       static uint8_t mf_nr_ar3 = 0;
+
+       uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = { 0x00 };
+       uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = { 0x00 };
+
        byte_t nt_diff = 0;
        uint8_t par[1] = {0};   // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough
        static byte_t par_low = 0;
        bool led_on = TRUE;
-       uint8_t uid[10]  ={0};
-       uint32_t cuid;
+       uint8_t uid[10] = {0x00};
+       //uint32_t cuid = 0x00;
 
        uint32_t nt = 0;
        uint32_t previous_nt = 0;
@@ -2013,13 +2205,15 @@ void ReaderMifare(bool first_try)
        byte_t par_list[8] = {0x00};
        byte_t ks_list[8] = {0x00};
 
-       static uint32_t sync_time;
-       static uint32_t sync_cycles;
+       static uint32_t sync_time = 0;
+       static uint32_t sync_cycles = 0;
        int catch_up_cycles = 0;
        int last_catch_up = 0;
        uint16_t consecutive_resyncs = 0;
        int isOK = 0;
 
+       int numWrongDistance = 0;
+       
        if (first_try) { 
                mf_nr_ar3 = 0;
                iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
@@ -2039,20 +2233,22 @@ void ReaderMifare(bool first_try)
        LED_A_ON();
        LED_B_OFF();
        LED_C_OFF();
-       
+       LED_C_ON();     
   
        for(uint16_t i = 0; TRUE; i++) {
                
                WDT_HIT();
 
                // Test if the action was cancelled
-               if(BUTTON_PRESS()) {
+               if(BUTTON_PRESS()) break;
+               
+               if (numWrongDistance > 1000) {
+                       isOK = 0;
                        break;
                }
                
-               LED_C_ON();
-
-               if(!iso14443a_select_card(uid, NULL, &cuid)) {
+               //if(!iso14443a_select_card(uid, NULL, &cuid)) {
+               if(!iso14443a_select_card(uid, NULL, NULL)) {
                        if (MF_DBGLEVEL >= 1)   Dbprintf("Mifare: Can't select card");
                        continue;
                }
@@ -2086,9 +2282,14 @@ void ReaderMifare(bool first_try)
                                nt_attacked = nt;
                        }
                        else {
-                               if (nt_distance == -99999) { // invalid nonce received, try again
+                               
+                               // invalid nonce received, try again
+                               if (nt_distance == -99999) { 
+                                       numWrongDistance++;
+                                       if (MF_DBGLEVEL >= 3) Dbprintf("The two nonces has invalid distance, tag could have good PRNG\n");
                                        continue;
                                }
+                               
                                sync_cycles = (sync_cycles - nt_distance);
                                if (MF_DBGLEVEL >= 3) Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles);
                                continue;
@@ -2097,7 +2298,7 @@ void ReaderMifare(bool first_try)
 
                if ((nt != nt_attacked) && nt_attacked) {       // we somehow lost sync. Try to catch up again...
                        catch_up_cycles = -dist_nt(nt_attacked, nt);
-                       if (catch_up_cycles == 99999) {                 // invalid nonce received. Don't resync on that one.
+                       if (catch_up_cycles >= 99999) {                 // invalid nonce received. Don't resync on that one.
                                catch_up_cycles = 0;
                                continue;
                        }
@@ -2155,10 +2356,10 @@ void ReaderMifare(bool first_try)
                }
        }
 
-
        mf_nr_ar[3] &= 0x1F;
        
-       byte_t buf[28];
+       byte_t buf[28] = {0x00};
+       
        memcpy(buf + 0,  uid, 4);
        num_to_bytes(nt, 4, buf + 4);
        memcpy(buf + 8,  par_list, 8);
@@ -2167,14 +2368,13 @@ void ReaderMifare(bool first_try)
                
        cmd_send(CMD_ACK,isOK,0,0,buf,28);
 
-       // Thats it...
+       set_tracing(FALSE);
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
        LEDsoff();
-
-       set_tracing(FALSE);
 }
 
-/**
+
+ /*
   *MIFARE 1K simulate.
   *
   *@param flags :
@@ -2196,7 +2396,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
        uint8_t cardWRBL = 0;
        uint8_t cardAUTHSC = 0;
        uint8_t cardAUTHKEY = 0xff;  // no authentication
-       uint32_t cardRr = 0;
+//     uint32_t cardRr = 0;
        uint32_t cuid = 0;
        //uint32_t rn_enc = 0;
        uint32_t ans = 0;
@@ -2214,16 +2414,17 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
        uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID
        uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62};
        uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!!
-       uint8_t rSAK[] = {0x08, 0xb6, 0xdd};
+       //uint8_t rSAK[] = {0x08, 0xb6, 0xdd}; // Mifare Classic
+       uint8_t rSAK[] = {0x09, 0x3f, 0xcc };  // Mifare Mini 
        uint8_t rSAK1[] = {0x04, 0xda, 0x17};
 
-       uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
+       uint8_t rAUTH_NT[] = {0x01, 0x01, 0x01, 0x01};
        uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
                
        //Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2
        // This can be used in a reader-only attack.
        // (it can also be retrieved via 'hf 14a list', but hey...
-       uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0};
+       uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0,0,0};
        uint8_t ar_nr_collected = 0;
 
        // free eventually allocated BigBuf memory but keep Emulator Memory
@@ -2262,6 +2463,11 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                }
        }
 
+       // save uid.
+       ar_nr_responses[0*5]   = bytes_to_num(rUIDBCC1+1, 3);
+       if ( _7BUID )
+               ar_nr_responses[0*5+1] = bytes_to_num(rUIDBCC2, 4);
+
        /*
         * Regardless of what method was used to set the UID, set fifth byte and modify
         * the ATQA for 4 or 7-byte UID
@@ -2304,7 +2510,6 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                if(cardSTATE == MFEMUL_NOFIELD) continue;
 
                //Now, get data
-
                res = EmGetCmd(receivedCmd, &len, receivedCmd_par);
                if (res == 2) { //Field is off!
                        cardSTATE = MFEMUL_NOFIELD;
@@ -2375,34 +2580,42 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                                uint32_t nr = bytes_to_num(&receivedCmd[4], 4);
 
                                //Collect AR/NR
+                               //if(ar_nr_collected < 2 && cardAUTHSC == 2){
                                if(ar_nr_collected < 2){
                                        if(ar_nr_responses[2] != ar)
                                        {// Avoid duplicates... probably not necessary, ar should vary. 
-                                               ar_nr_responses[ar_nr_collected*4] = cuid;
-                                               ar_nr_responses[ar_nr_collected*4+1] = nonce;
-                                               ar_nr_responses[ar_nr_collected*4+2] = ar;
-                                               ar_nr_responses[ar_nr_collected*4+3] = nr;
+                                               //ar_nr_responses[ar_nr_collected*5]   = 0;
+                                               //ar_nr_responses[ar_nr_collected*5+1] = 0;
+                                               ar_nr_responses[ar_nr_collected*5+2] = nonce;
+                                               ar_nr_responses[ar_nr_collected*5+3] = nr;
+                                               ar_nr_responses[ar_nr_collected*5+4] = ar;
                                                ar_nr_collected++;
+                                       }                                               
+                                       // Interactive mode flag, means we need to send ACK
+                                       if(flags & FLAG_INTERACTIVE && ar_nr_collected == 2)
+                                       {
+                                               finished = true;
                                        }
                                }
 
                                // --- crypto
-                               crypto1_word(pcs, ar , 1);
-                               cardRr = nr ^ crypto1_word(pcs, 0, 0);
-
-                               // test if auth OK
-                               if (cardRr != prng_successor(nonce, 64)){
-                                       if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x",
-                                                       cardAUTHSC, cardAUTHKEY == 0 ? 'A' : 'B',
-                                                       cardRr, prng_successor(nonce, 64));
+                               //crypto1_word(pcs, ar , 1);
+                               //cardRr = nr ^ crypto1_word(pcs, 0, 0);
+
+                               //test if auth OK
+                               //if (cardRr != prng_successor(nonce, 64)){
+                                       
+                                       //if (MF_DBGLEVEL >= 4) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x",
+                                       //      cardAUTHSC, cardAUTHKEY == 0 ? 'A' : 'B',
+                                       //              cardRr, prng_successor(nonce, 64));
                                        // Shouldn't we respond anything here?
                                        // Right now, we don't nack or anything, which causes the
                                        // reader to do a WUPA after a while. /Martin
                                        // -- which is the correct response. /piwi
-                                       cardSTATE_TO_IDLE();
-                                       LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE);
-                                       break;
-                               }
+                                       //cardSTATE_TO_IDLE();
+                                       //LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE);
+                                       //break;
+                               //}
 
                                ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
 
@@ -2510,13 +2723,13 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                                                || receivedCmd[0] == 0xB0) { // transfer
                                        if (receivedCmd[1] >= 16 * 4) {
                                                EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
-                                               if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
+                                               if (MF_DBGLEVEL >= 4) Dbprintf("Reader tried to operate (0x%02) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
                                                break;
                                        }
 
                                        if (receivedCmd[1] / 4 != cardAUTHSC) {
                                                EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
-                                               if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC);
+                                               if (MF_DBGLEVEL >= 4) Dbprintf("Reader tried to operate (0x%02) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC);
                                                break;
                                        }
                                }
@@ -2530,7 +2743,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                                        mf_crypto1_encrypt(pcs, response, 18, response_par);
                                        EmSendCmdPar(response, 18, response_par);
                                        numReads++;
-                                       if(exitAfterNReads > 0 && numReads == exitAfterNReads) {
+                                       if(exitAfterNReads > 0 && numReads >= exitAfterNReads) {
                                                Dbprintf("%d reads done, exiting", numReads);
                                                finished = true;
                                        }
@@ -2548,7 +2761,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
                                if (receivedCmd[0] == 0xC0 || receivedCmd[0] == 0xC1 || receivedCmd[0] == 0xC2) {
                                        if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
                                        if (emlCheckValBl(receivedCmd[1])) {
-                                               if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking");
+                                               if (MF_DBGLEVEL >= 4) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking");
                                                EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
                                                break;
                                        }
@@ -2650,39 +2863,40 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
        if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK
        {
                //May just aswell send the collected ar_nr in the response aswell
-               cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4);
+               uint8_t len = ar_nr_collected*5*4;
+               cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, len, 0, &ar_nr_responses, len);
        }
 
-       if(flags & FLAG_NR_AR_ATTACK)
+       if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1 )
        {
-               if(ar_nr_collected > 1) {
+               if(ar_nr_collected > 1 ) {
                        Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:");
-                       Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x",
-                                       ar_nr_responses[0], // UID
-                                       ar_nr_responses[1], //NT
-                                       ar_nr_responses[2], //AR1
-                                       ar_nr_responses[3], //NR1
-                                       ar_nr_responses[6], //AR2
-                                       ar_nr_responses[7] //NR2
+                       Dbprintf("../tools/mfkey/mfkey32 %06x%08x %08x %08x %08x %08x %08x",
+                                       ar_nr_responses[0], // UID1
+                                       ar_nr_responses[1], // UID2
+                                       ar_nr_responses[2], // NT
+                                       ar_nr_responses[3], // AR1
+                                       ar_nr_responses[4], // NR1
+                                       ar_nr_responses[8], // AR2
+                                       ar_nr_responses[9]  // NR2
                                        );
                } else {
                        Dbprintf("Failed to obtain two AR/NR pairs!");
-                       if(ar_nr_collected >0) {
-                               Dbprintf("Only got these: UID=%08x, nonce=%08x, AR1=%08x, NR1=%08x",
-                                               ar_nr_responses[0], // UID
-                                               ar_nr_responses[1], //NT
-                                               ar_nr_responses[2], //AR1
-                                               ar_nr_responses[3] //NR1
+                       if(ar_nr_collected > 0 ) {
+                               Dbprintf("Only got these: UID=%07x%08x, nonce=%08x, AR1=%08x, NR1=%08x",
+                                               ar_nr_responses[0], // UID1
+                                               ar_nr_responses[1], // UID2
+                                               ar_nr_responses[2], // NT
+                                               ar_nr_responses[3], // AR1
+                                               ar_nr_responses[4]  // NR1
                                                );
                        }
                }
        }
-       if (MF_DBGLEVEL >= 1)   Dbprintf("Emulator stopped. Tracing: %d  trace length: %d ",    tracing, BigBuf_get_traceLen());
-       
+       if (MF_DBGLEVEL >= 1)   Dbprintf("Emulator stopped. Tracing: %d  trace length: %d ", tracing, BigBuf_get_traceLen());
 }
 
 
-
 //-----------------------------------------------------------------------------
 // MIFARE sniffer. 
 // 
@@ -2692,6 +2906,9 @@ void RAMFUNC SniffMifare(uint8_t param) {
        // bit 0 - trigger from first card answer
        // bit 1 - trigger from first reader 7-bit request
 
+       // free eventually allocated BigBuf memory
+       BigBuf_free();
+       
        // C(red) A(yellow) B(green)
        LEDsoff();
        // init trace buffer
@@ -2707,12 +2924,6 @@ void RAMFUNC SniffMifare(uint8_t param) {
        uint8_t receivedResponse[MAX_MIFARE_FRAME_SIZE];
        uint8_t receivedResponsePar[MAX_MIFARE_PARITY_SIZE];
 
-       // As we receive stuff, we copy it from receivedCmd or receivedResponse
-       // into trace, along with its length and other annotations.
-       //uint8_t *trace = (uint8_t *)BigBuf;
-       
-       // free eventually allocated BigBuf memory
-       BigBuf_free();
        // allocate the DMA buffer, used to stream samples from the FPGA
        uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
        uint8_t *data = dmaBuf;
@@ -2803,6 +3014,7 @@ void RAMFUNC SniffMifare(uint8_t param) {
                                        if (MfSniffLogic(receivedCmd, Uart.len, Uart.parity, Uart.bitCount, TRUE)) break;
 
                                        /* And ready to receive another command. */
+                                       //UartInit(receivedCmd, receivedCmdPar);
                                        UartReset();
                                        
                                        /* And also reset the demod code */
@@ -2820,6 +3032,9 @@ void RAMFUNC SniffMifare(uint8_t param) {
 
                                        // And ready to receive another response.
                                        DemodReset();
+
+                                       // And reset the Miller decoder including its (now outdated) input buffer
+                                       UartInit(receivedCmd, receivedCmdPar);
                                }
                                TagIsActive = (Demod.state != DEMOD_UNSYNCD);
                        }
index 1e978e8808fa683f7744211e8bd4060c32eb59c5..3344de4327a5a7d8fba8e2edb595547d54c39e64 100644 (file)
@@ -12,7 +12,8 @@
 
 #ifndef __ISO14443A_H
 #define __ISO14443A_H
-#include "common.h"
+#include "../include/common.h"
+#include "../include/mifare.h"
 #include "mifaresniff.h"
 
 typedef struct {
@@ -56,15 +57,14 @@ typedef struct {
                // DROP_FIRST_HALF,
                } state;
        uint16_t shiftReg;
-       uint16_t bitCount;
+       int16_t  bitCount;
        uint16_t len;
        uint16_t byteCntMax;
        uint16_t posCnt;
        uint16_t syncBit;
        uint8_t  parityBits;
        uint8_t  parityLen;
-       uint16_t highCnt;
-       uint16_t twoBits;
+       uint32_t fourBits;
        uint32_t startTime, endTime;
     uint8_t *output;
        uint8_t *parity;
diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c
new file mode 100644 (file)
index 0000000..860e96f
--- /dev/null
@@ -0,0 +1,1273 @@
+//-----------------------------------------------------------------------------
+// Jonathan Westhues, split Nov 2006
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Routines to support ISO 14443. This includes both the reader software and
+// the `fake tag' modes. At the moment only the Type B modulation is
+// supported.
+//-----------------------------------------------------------------------------
+
+#include "proxmark3.h"
+#include "apps.h"
+#include "util.h"
+#include "string.h"
+
+#include "iso14443crc.h"
+
+//static void GetSamplesFor14443(int weTx, int n);
+
+/*#define DEMOD_TRACE_SIZE 4096
+#define READER_TAG_BUFFER_SIZE 2048
+#define TAG_READER_BUFFER_SIZE 2048
+#define DEMOD_DMA_BUFFER_SIZE 1024
+*/
+
+#define RECEIVE_SAMPLES_TIMEOUT 2000
+
+//=============================================================================
+// An ISO 14443 Type B tag. We listen for commands from the reader, using
+// a UART kind of thing that's implemented in software. When we get a
+// frame (i.e., a group of bytes between SOF and EOF), we check the CRC.
+// If it's good, then we can do something appropriate with it, and send
+// a response.
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Code up a string of octets at layer 2 (including CRC, we don't generate
+// that here) so that they can be transmitted to the reader. Doesn't transmit
+// them yet, just leaves them ready to send in ToSend[].
+//-----------------------------------------------------------------------------
+static void CodeIso14443bAsTag(const uint8_t *cmd, int len)
+{
+       int i;
+
+       ToSendReset();
+
+       // Transmit a burst of ones, as the initial thing that lets the
+       // reader get phase sync. This (TR1) must be > 80/fs, per spec,
+       // but tag that I've tried (a Paypass) exceeds that by a fair bit,
+       // so I will too.
+       for(i = 0; i < 20; i++) {
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+       }
+
+       // Send SOF.
+       for(i = 0; i < 10; i++) {
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+       }
+       for(i = 0; i < 2; i++) {
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+       }
+
+       for(i = 0; i < len; i++) {
+               int j;
+               uint8_t b = cmd[i];
+
+               // Start bit
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+
+               // Data bits
+               for(j = 0; j < 8; j++) {
+                       if(b & 1) {
+                               ToSendStuffBit(1);
+                               ToSendStuffBit(1);
+                               ToSendStuffBit(1);
+                               ToSendStuffBit(1);
+                       } else {
+                               ToSendStuffBit(0);
+                               ToSendStuffBit(0);
+                               ToSendStuffBit(0);
+                               ToSendStuffBit(0);
+                       }
+                       b >>= 1;
+               }
+
+               // Stop bit
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+       }
+
+       // Send SOF.
+       for(i = 0; i < 10; i++) {
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+               ToSendStuffBit(0);
+       }
+       for(i = 0; i < 10; i++) {
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+       }
+
+       // Convert from last byte pos to length
+       ToSendMax++;
+
+       // Add a few more for slop
+       ToSendMax += 2;
+}
+
+//-----------------------------------------------------------------------------
+// The software UART that receives commands from the reader, and its state
+// variables.
+//-----------------------------------------------------------------------------
+static struct {
+       enum {
+               STATE_UNSYNCD,
+               STATE_GOT_FALLING_EDGE_OF_SOF,
+               STATE_AWAITING_START_BIT,
+               STATE_RECEIVING_DATA,
+               STATE_ERROR_WAIT
+       }       state;
+       uint16_t    shiftReg;
+       int     bitCnt;
+       int     byteCnt;
+       int     byteCntMax;
+       int     posCnt;
+       uint8_t   *output;
+} Uart;
+
+/* Receive & handle a bit coming from the reader.
+ *
+ * LED handling:
+ * LED A -> ON once we have received the SOF and are expecting the rest.
+ * LED A -> OFF once we have received EOF or are in error state or unsynced
+ *
+ * Returns: true if we received a EOF
+ *          false if we are still waiting for some more
+ */
+static int Handle14443UartBit(int bit)
+{
+       switch(Uart.state) {
+               case STATE_UNSYNCD:
+                       if(!bit) {
+                               // we went low, so this could be the beginning
+                               // of an SOF
+                               Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;
+                               Uart.posCnt = 0;
+                               Uart.bitCnt = 0;
+                       }
+                       break;
+
+               case STATE_GOT_FALLING_EDGE_OF_SOF:
+                       Uart.posCnt++;
+                       if(Uart.posCnt == 2) {
+                               if(bit) {
+                                       if(Uart.bitCnt >= 10) {
+                                               // we've seen enough consecutive
+                                               // zeros that it's a valid SOF
+                                               Uart.posCnt = 0;
+                                               Uart.byteCnt = 0;
+                                               Uart.state = STATE_AWAITING_START_BIT;
+                                               LED_A_ON(); // Indicate we got a valid SOF
+                                       } else {
+                                               // didn't stay down long enough
+                                               // before going high, error
+                                               Uart.state = STATE_ERROR_WAIT;
+                                       }
+                               } else {
+                                       // do nothing, keep waiting
+                               }
+                               Uart.bitCnt++;
+                       }
+                       if(Uart.posCnt >= 4) Uart.posCnt = 0;
+                       if(Uart.bitCnt > 14) {
+                               // Give up if we see too many zeros without
+                               // a one, too.
+                               Uart.state = STATE_ERROR_WAIT;
+                       }
+                       break;
+
+               case STATE_AWAITING_START_BIT:
+                       Uart.posCnt++;
+                       if(bit) {
+                               if(Uart.posCnt > 25) {
+                                       // stayed high for too long between
+                                       // characters, error
+                                       Uart.state = STATE_ERROR_WAIT;
+                               }
+                       } else {
+                               // falling edge, this starts the data byte
+                               Uart.posCnt = 0;
+                               Uart.bitCnt = 0;
+                               Uart.shiftReg = 0;
+                               Uart.state = STATE_RECEIVING_DATA;
+                       }
+                       break;
+
+               case STATE_RECEIVING_DATA:
+                       Uart.posCnt++;
+                       if(Uart.posCnt == 2) {
+                               // time to sample a bit
+                               Uart.shiftReg >>= 1;
+                               if(bit) {
+                                       Uart.shiftReg |= 0x200;
+                               }
+                               Uart.bitCnt++;
+                       }
+                       if(Uart.posCnt >= 4) {
+                               Uart.posCnt = 0;
+                       }
+                       if(Uart.bitCnt == 10) {
+                               if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))
+                               {
+                                       // this is a data byte, with correct
+                                       // start and stop bits
+                                       Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;
+                                       Uart.byteCnt++;
+
+                                       if(Uart.byteCnt >= Uart.byteCntMax) {
+                                               // Buffer overflowed, give up
+                                               Uart.posCnt = 0;
+                                               Uart.state = STATE_ERROR_WAIT;
+                                       } else {
+                                               // so get the next byte now
+                                               Uart.posCnt = 0;
+                                               Uart.state = STATE_AWAITING_START_BIT;
+                                       }
+                               } else if(Uart.shiftReg == 0x000) {
+                                       // this is an EOF byte
+                                       LED_A_OFF(); // Finished receiving
+                                       return TRUE;
+                               } else {
+                                       // this is an error
+                                       Uart.posCnt = 0;
+                                       Uart.state = STATE_ERROR_WAIT;
+                               }
+                       }
+                       break;
+
+               case STATE_ERROR_WAIT:
+                       // We're all screwed up, so wait a little while
+                       // for whatever went wrong to finish, and then
+                       // start over.
+                       Uart.posCnt++;
+                       if(Uart.posCnt > 10) {
+                               Uart.state = STATE_UNSYNCD;
+                               LED_A_OFF();
+                       }
+                       break;
+
+               default:
+                       Uart.state = STATE_UNSYNCD;
+                       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 TRUE) or someone presses the pushbutton on the board (FALSE).
+//
+// Assume that we're called with the SSC (to the FPGA) and ADC path set
+// correctly.
+//-----------------------------------------------------------------------------
+static int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen)
+{
+       uint8_t mask;
+       int i, bit;
+
+       // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
+       // only, since we are receiving, not transmitting).
+       // Signal field is off with the appropriate LED
+       LED_D_OFF();
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION);
+
+
+       // Now run a `software UART' on the stream of incoming samples.
+       Uart.output = received;
+       Uart.byteCntMax = maxLen;
+       Uart.state = STATE_UNSYNCD;
+
+       for(;;) {
+               WDT_HIT();
+
+               if(BUTTON_PRESS()) return FALSE;
+
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+                       AT91C_BASE_SSC->SSC_THR = 0x00;
+               }
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+                       uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+
+                       mask = 0x80;
+                       for(i = 0; i < 8; i++, mask >>= 1) {
+                               bit = (b & mask);
+                               if(Handle14443UartBit(bit)) {
+                                       *len = Uart.byteCnt;
+                                       return TRUE;
+                               }
+                       }
+               }
+       }
+}
+
+//-----------------------------------------------------------------------------
+// Main loop of simulated tag: receive commands from reader, decide what
+// response to send, and send it.
+//-----------------------------------------------------------------------------
+void SimulateIso14443Tag(void)
+{
+       static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
+       static const uint8_t response1[] = {
+               0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,
+               0x00, 0x21, 0x85, 0x5e, 0xd7
+       };
+
+       uint8_t *resp;
+       int respLen;
+
+       uint8_t *resp1 = BigBuf_get_addr() + 800;
+       int resp1Len;
+
+       uint8_t *receivedCmd = BigBuf_get_addr();
+       int len;
+
+       int i;
+
+       int cmdsRecvd = 0;
+
+       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+       memset(receivedCmd, 0x44, 400);
+
+       CodeIso14443bAsTag(response1, sizeof(response1));
+       memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;
+
+       // We need to listen to the high-frequency, peak-detected path.
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+       FpgaSetupSsc();
+
+       cmdsRecvd = 0;
+
+       for(;;) {
+               uint8_t b1, b2;
+
+               if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) {
+               Dbprintf("button pressed, received %d commands", cmdsRecvd);
+               break;
+               }
+
+               // Good, look at the command now.
+
+               if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) {
+                       resp = resp1; respLen = resp1Len;
+               } else {
+                       Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd);
+                       // And print whether the CRC fails, just for good measure
+                       ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2);
+                       if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) {
+                               // Not so good, try again.
+                               DbpString("+++CRC fail");
+                       } else {
+                               DbpString("CRC passes");
+                       }
+                       break;
+               }
+
+               memset(receivedCmd, 0x44, 32);
+
+               cmdsRecvd++;
+
+               if(cmdsRecvd > 0x30) {
+                       DbpString("many commands later...");
+                       break;
+               }
+
+               if(respLen <= 0) continue;
+
+               // Modulate BPSK
+               // Signal field is off with the appropriate LED
+               LED_D_OFF();
+               FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);
+               AT91C_BASE_SSC->SSC_THR = 0xff;
+               FpgaSetupSsc();
+
+               // Transmit the response.
+               i = 0;
+               for(;;) {
+                       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+                               uint8_t b = resp[i];
+
+                               AT91C_BASE_SSC->SSC_THR = b;
+
+                               i++;
+                               if(i > respLen) {
+                                       break;
+                               }
+                       }
+                       if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+                               volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+                               (void)b;
+                       }
+               }
+       }
+}
+
+//=============================================================================
+// An ISO 14443 Type B reader. We take layer two commands, code them
+// appropriately, and then send them to the tag. We then listen for the
+// tag's response, which we leave in the buffer to be demodulated on the
+// PC side.
+//=============================================================================
+
+static struct {
+       enum {
+               DEMOD_UNSYNCD,
+               DEMOD_PHASE_REF_TRAINING,
+               DEMOD_AWAITING_FALLING_EDGE_OF_SOF,
+               DEMOD_GOT_FALLING_EDGE_OF_SOF,
+               DEMOD_AWAITING_START_BIT,
+               DEMOD_RECEIVING_DATA,
+               DEMOD_ERROR_WAIT
+       }       state;
+       int     bitCount;
+       int     posCount;
+       int     thisBit;
+       int     metric;
+       int     metricN;
+       uint16_t    shiftReg;
+       uint8_t   *output;
+       int     len;
+       int     sumI;
+       int     sumQ;
+} Demod;
+
+/*
+ * Handles reception of a bit from the tag
+ *
+ * LED handling:
+ * LED C -> ON once we have received the SOF and are expecting the rest.
+ * LED C -> OFF once we have received EOF or are unsynced
+ *
+ * Returns: true if we received a EOF
+ *          false if we are still waiting for some more
+ *
+ */
+static RAMFUNC int Handle14443SamplesDemod(int ci, int cq)
+{
+       int v;
+
+       // The soft decision on the bit uses an estimate of just the
+       // quadrant of the reference angle, not the exact angle.
+#define MAKE_SOFT_DECISION() { \
+               if(Demod.sumI > 0) { \
+                       v = ci; \
+               } else { \
+                       v = -ci; \
+               } \
+               if(Demod.sumQ > 0) { \
+                       v += cq; \
+               } else { \
+                       v -= cq; \
+               } \
+       }
+
+       switch(Demod.state) {
+               case DEMOD_UNSYNCD:
+                       v = ci;
+                       if(v < 0) v = -v;
+                       if(cq > 0) {
+                               v += cq;
+                       } else {
+                               v -= cq;
+                       }
+                       if(v > 40) {
+                               Demod.posCount = 0;
+                               Demod.state = DEMOD_PHASE_REF_TRAINING;
+                               Demod.sumI = 0;
+                               Demod.sumQ = 0;
+                       }
+                       break;
+
+               case DEMOD_PHASE_REF_TRAINING:
+                       if(Demod.posCount < 8) {
+                               Demod.sumI += ci;
+                               Demod.sumQ += cq;
+                       } else if(Demod.posCount > 100) {
+                               // error, waited too long
+                               Demod.state = DEMOD_UNSYNCD;
+                       } else {
+                               MAKE_SOFT_DECISION();
+                               if(v < 0) {
+                                       Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
+                                       Demod.posCount = 0;
+                               }
+                       }
+                       Demod.posCount++;
+                       break;
+
+               case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:
+                       MAKE_SOFT_DECISION();
+                       if(v < 0) {
+                               Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
+                               Demod.posCount = 0;
+                       } else {
+                               if(Demod.posCount > 100) {
+                                       Demod.state = DEMOD_UNSYNCD;
+                               }
+                       }
+                       Demod.posCount++;
+                       break;
+
+               case DEMOD_GOT_FALLING_EDGE_OF_SOF:
+                       MAKE_SOFT_DECISION();
+                       if(v > 0) {
+                               if(Demod.posCount < 12) {
+                                       Demod.state = DEMOD_UNSYNCD;
+                               } else {
+                                       LED_C_ON(); // Got SOF
+                                       Demod.state = DEMOD_AWAITING_START_BIT;
+                                       Demod.posCount = 0;
+                                       Demod.len = 0;
+                                       Demod.metricN = 0;
+                                       Demod.metric = 0;
+                               }
+                       } else {
+                               if(Demod.posCount > 100) {
+                                       Demod.state = DEMOD_UNSYNCD;
+                                       LED_C_OFF();
+                               }
+                       }
+                       Demod.posCount++;
+                       break;
+
+               case DEMOD_AWAITING_START_BIT:
+                       MAKE_SOFT_DECISION();
+                       if(v > 0) {
+                               if(Demod.posCount > 10) {
+                                       Demod.state = DEMOD_UNSYNCD;
+                                       LED_C_OFF();
+                               }
+                       } else {
+                               Demod.bitCount = 0;
+                               Demod.posCount = 1;
+                               Demod.thisBit = v;
+                               Demod.shiftReg = 0;
+                               Demod.state = DEMOD_RECEIVING_DATA;
+                       }
+                       break;
+
+               case DEMOD_RECEIVING_DATA:
+                       MAKE_SOFT_DECISION();
+                       if(Demod.posCount == 0) {
+                               Demod.thisBit = v;
+                               Demod.posCount = 1;
+                       } else {
+                               Demod.thisBit += v;
+
+                               if(Demod.thisBit > 0) {
+                                       Demod.metric += Demod.thisBit;
+                               } else {
+                                       Demod.metric -= Demod.thisBit;
+                               }
+                               (Demod.metricN)++;
+
+                               Demod.shiftReg >>= 1;
+                               if(Demod.thisBit > 0) {
+                                       Demod.shiftReg |= 0x200;
+                               }
+
+                               Demod.bitCount++;
+                               if(Demod.bitCount == 10) {
+                                       uint16_t s = Demod.shiftReg;
+                                       if((s & 0x200) && !(s & 0x001)) {
+                                               uint8_t b = (s >> 1);
+                                               Demod.output[Demod.len] = b;
+                                               Demod.len++;
+                                               Demod.state = DEMOD_AWAITING_START_BIT;
+                                       } else {
+                                               Demod.state = DEMOD_UNSYNCD;
+                                               LED_C_OFF();
+                                               if(s == 0x000) {
+                                               // This is EOF
+                                               return TRUE;
+                                               }
+                                       }
+                               }
+                               Demod.posCount = 0;
+                       }
+                       break;
+
+               default:
+                       Demod.state = DEMOD_UNSYNCD;
+                       LED_C_OFF();
+                       break;
+       }
+
+       return FALSE;
+}
+
+
+static void DemodReset()
+{
+       // Clear out the state of the "UART" that receives from the tag.
+       Demod.len = 0;
+       Demod.state = DEMOD_UNSYNCD;
+       memset(Demod.output, 0x00, MAX_FRAME_SIZE);
+}
+
+
+static void DemodInit(uint8_t *data)
+{
+       Demod.output = data;
+       DemodReset();
+}
+
+
+static void UartReset()
+{
+       Uart.byteCntMax = MAX_FRAME_SIZE;
+       Uart.state = STATE_UNSYNCD;
+       Uart.byteCnt = 0;
+       Uart.bitCnt = 0;
+}
+
+
+static void UartInit(uint8_t *data)
+{
+       Uart.output = data;
+       UartReset();
+}
+
+
+/*
+ *  Demodulate the samples we received from the tag, also log to tracebuffer
+ *  weTx: set to 'TRUE' if we behave like a reader
+ *        set to 'FALSE' if we behave like a snooper
+ *  quiet: set to 'TRUE' to disable debug output
+ */
+static void GetSamplesFor14443Demod(int weTx, int n, int quiet)
+{
+       int max = 0;
+       int gotFrame = FALSE;
+       int lastRxCounter, ci, cq, samples = 0;
+
+       // Allocate memory from BigBuf for some buffers
+       // free all previous allocations first
+       BigBuf_free();
+       
+       // The response (tag -> reader) that we're receiving.
+       uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE);
+       
+       // The DMA buffer, used to stream samples from the FPGA
+       int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE);
+
+       // Set up the demodulator for tag -> reader responses.
+       DemodInit(receivedResponse);
+
+       // Setup and start DMA.
+       FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE);
+
+       int8_t *upTo = dmaBuf;
+       lastRxCounter = DMA_BUFFER_SIZE;
+
+       // Signal field is ON with the appropriate LED:
+       if (weTx) LED_D_ON(); else LED_D_OFF();
+       // And put the FPGA in the appropriate mode
+       FpgaWriteConfWord(
+               FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
+               (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));
+
+       for(;;) {
+               int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;
+               if(behindBy > max) max = behindBy;
+
+               while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1))
+                                       > 2)
+               {
+                       ci = upTo[0];
+                       cq = upTo[1];
+                       upTo += 2;
+                       if(upTo >= dmaBuf + DMA_BUFFER_SIZE) {
+                               upTo = dmaBuf;
+                               AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
+                               AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
+                       }
+                       lastRxCounter -= 2;
+                       if(lastRxCounter <= 0) {
+                               lastRxCounter += DMA_BUFFER_SIZE;
+                       }
+
+                       samples += 2;
+
+                       if(Handle14443SamplesDemod(ci, cq)) {
+                               gotFrame = 1;
+                       }
+               }
+
+               if(samples > n) {
+                       break;
+               }
+       }
+       AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+       if (!quiet) Dbprintf("%x %x %x", max, gotFrame, Demod.len);
+       //Tracing
+       if (tracing && Demod.len > 0) {
+               uint8_t parity[MAX_PARITY_SIZE];
+               GetParity(Demod.output, Demod.len, parity);
+               LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE);
+       }
+}
+
+
+//-----------------------------------------------------------------------------
+// Read the tag's response. We just receive a stream of slightly-processed
+// samples from the FPGA, which we will later do some signal processing on,
+// to get the bits.
+//-----------------------------------------------------------------------------
+/*static void GetSamplesFor14443(int weTx, int n)
+{
+       uint8_t *dest = (uint8_t *)BigBuf;
+       int c;
+
+       FpgaWriteConfWord(
+               FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
+               (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));
+
+       c = 0;
+       for(;;) {
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+                       AT91C_BASE_SSC->SSC_THR = 0x43;
+               }
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+                       int8_t b;
+                       b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
+
+                       dest[c++] = (uint8_t)b;
+
+                       if(c >= n) {
+                               break;
+                       }
+               }
+       }
+}*/
+
+
+//-----------------------------------------------------------------------------
+// Transmit the command (to the tag) that was placed in ToSend[].
+//-----------------------------------------------------------------------------
+static void TransmitFor14443(void)
+{
+       int c;
+
+       FpgaSetupSsc();
+
+       while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+               AT91C_BASE_SSC->SSC_THR = 0xff;
+       }
+
+       // Signal field is ON with the appropriate Red LED
+       LED_D_ON();
+       // Signal we are transmitting with the Green LED
+       LED_B_ON();
+       FpgaWriteConfWord(
+               FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
+
+       for(c = 0; c < 10;) {
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+                       AT91C_BASE_SSC->SSC_THR = 0xff;
+                       c++;
+               }
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+                       volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
+                       (void)r;
+               }
+               WDT_HIT();
+       }
+
+       c = 0;
+       for(;;) {
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+                       AT91C_BASE_SSC->SSC_THR = ToSend[c];
+                       c++;
+                       if(c >= ToSendMax) {
+                               break;
+                       }
+               }
+               if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+                       volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
+                       (void)r;
+               }
+               WDT_HIT();
+       }
+       LED_B_OFF(); // Finished sending
+}
+
+
+//-----------------------------------------------------------------------------
+// Code a layer 2 command (string of octets, including CRC) into ToSend[],
+// so that it is ready to transmit to the tag using TransmitFor14443().
+//-----------------------------------------------------------------------------
+static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
+{
+       int i, j;
+       uint8_t b;
+
+       ToSendReset();
+
+       // Establish initial reference level
+       for(i = 0; i < 40; i++) {
+               ToSendStuffBit(1);
+       }
+       // Send SOF
+       for(i = 0; i < 10; i++) {
+               ToSendStuffBit(0);
+       }
+
+       for(i = 0; i < len; i++) {
+               // Stop bits/EGT
+               ToSendStuffBit(1);
+               ToSendStuffBit(1);
+               // Start bit
+               ToSendStuffBit(0);
+               // Data bits
+               b = cmd[i];
+               for(j = 0; j < 8; j++) {
+                       if(b & 1) {
+                               ToSendStuffBit(1);
+                       } else {
+                               ToSendStuffBit(0);
+                       }
+                       b >>= 1;
+               }
+       }
+       // Send EOF
+       ToSendStuffBit(1);
+       for(i = 0; i < 10; i++) {
+               ToSendStuffBit(0);
+       }
+       for(i = 0; i < 8; i++) {
+               ToSendStuffBit(1);
+       }
+
+       // And then a little more, to make sure that the last character makes
+       // it out before we switch to rx mode.
+       for(i = 0; i < 24; i++) {
+               ToSendStuffBit(1);
+       }
+
+       // Convert from last character reference to length
+       ToSendMax++;
+}
+
+
+//-----------------------------------------------------------------------------
+// Read an ISO 14443 tag. We send it some set of commands, and record the
+// responses.
+// The command name is misleading, it actually decodes the reponse in HEX
+// into the output buffer (read the result using hexsamples, not hisamples)
+//
+// obsolete function only for test
+//-----------------------------------------------------------------------------
+void AcquireRawAdcSamplesIso14443(uint32_t parameter)
+{
+       uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
+
+       SendRawCommand14443B(sizeof(cmd1),1,1,cmd1);
+}
+
+
+/**
+  Convenience function to encode, transmit and trace iso 14443b comms
+  **/
+static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len)
+{
+       CodeIso14443bAsReader(cmd, len);
+       TransmitFor14443();
+       if (tracing) {
+               uint8_t parity[MAX_PARITY_SIZE];
+               GetParity(cmd, len, parity);
+               LogTrace(cmd,len, 0, 0, parity, TRUE);
+       }
+}
+
+
+//-----------------------------------------------------------------------------
+// Read a SRI512 ISO 14443 tag.
+//
+// SRI512 tags are just simple memory tags, here we're looking at making a dump
+// of the contents of the memory. No anticollision algorithm is done, we assume
+// we have a single tag in the field.
+//
+// I tried to be systematic and check every answer of the tag, every CRC, etc...
+//-----------------------------------------------------------------------------
+void ReadSTMemoryIso14443(uint32_t dwLast)
+{
+       clear_trace();
+       set_tracing(TRUE);
+
+       uint8_t i = 0x00;
+
+       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+       // Make sure that we start from off, since the tags are stateful;
+       // confusing things will happen if we don't reset them between reads.
+       LED_D_OFF();
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       SpinDelay(200);
+
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+       FpgaSetupSsc();
+
+       // Now give it time to spin up.
+       // Signal field is on with the appropriate LED
+       LED_D_ON();
+       FpgaWriteConfWord(
+               FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
+       SpinDelay(200);
+
+       // First command: wake up the tag using the INITIATE command
+       uint8_t cmd1[] = { 0x06, 0x00, 0x97, 0x5b};
+
+       CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
+//    LED_A_ON();
+       GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
+//    LED_A_OFF();
+
+       if (Demod.len == 0) {
+       DbpString("No response from tag");
+       return;
+       } else {
+       Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x",
+               Demod.output[0], Demod.output[1],Demod.output[2]);
+       }
+       // There is a response, SELECT the uid
+       DbpString("Now SELECT tag:");
+       cmd1[0] = 0x0E; // 0x0E is SELECT
+       cmd1[1] = Demod.output[0];
+       ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
+       CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
+
+//    LED_A_ON();
+       GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
+//    LED_A_OFF();
+       if (Demod.len != 3) {
+       Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);
+       return;
+       }
+       // Check the CRC of the answer:
+       ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);
+       if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {
+       DbpString("CRC Error reading select response.");
+       return;
+       }
+       // Check response from the tag: should be the same UID as the command we just sent:
+       if (cmd1[1] != Demod.output[0]) {
+       Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]);
+       return;
+       }
+       // Tag is now selected,
+       // First get the tag's UID:
+       cmd1[0] = 0x0B;
+       ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]);
+       CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one
+
+//    LED_A_ON();
+       GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
+//    LED_A_OFF();
+       if (Demod.len != 10) {
+       Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);
+       return;
+       }
+       // The check the CRC of the answer (use cmd1 as temporary variable):
+       ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]);
+                  if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) {
+       Dbprintf("CRC Error reading block! - Below: expected, got %x %x",
+               (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]);
+       // Do not return;, let's go on... (we should retry, maybe ?)
+       }
+       Dbprintf("Tag UID (64 bits): %08x %08x",
+       (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4],
+       (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]);
+
+       // Now loop to read all 16 blocks, address from 0 to last block
+       Dbprintf("Tag memory dump, block 0 to %d",dwLast);
+       cmd1[0] = 0x08;
+       i = 0x00;
+       dwLast++;
+       for (;;) {
+                  if (i == dwLast) {
+                       DbpString("System area block (0xff):");
+                       i = 0xff;
+               }
+               cmd1[1] = i;
+               ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
+               CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
+
+//         LED_A_ON();
+               GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
+//         LED_A_OFF();
+               if (Demod.len != 6) { // Check if we got an answer from the tag
+               DbpString("Expected 6 bytes from tag, got less...");
+               return;
+               }
+               // The check the CRC of the answer (use cmd1 as temporary variable):
+               ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]);
+                       if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) {
+               Dbprintf("CRC Error reading block! - Below: expected, got %x %x",
+                       (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]);
+               // Do not return;, let's go on... (we should retry, maybe ?)
+               }
+               // Now print out the memory location:
+               Dbprintf("Address=%x, Contents=%x, CRC=%x", i,
+               (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0],
+               (Demod.output[4]<<8)+Demod.output[5]);
+               if (i == 0xff) {
+               break;
+               }
+               i++;
+       }
+}
+
+
+//=============================================================================
+// Finally, the `sniffer' combines elements from both the reader and
+// simulated tag, to show both sides of the conversation.
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Record the sequence of commands sent by the reader to the tag, with
+// triggering so that we start recording at the point that the tag is moved
+// near the reader.
+//-----------------------------------------------------------------------------
+/*
+ * Memory usage for this function, (within BigBuf)
+ * Last Received command (reader->tag) - MAX_FRAME_SIZE
+ * Last Received command (tag->reader) - MAX_FRAME_SIZE
+ * DMA Buffer, 1024 bytes (samples) - DMA_BUFFER_SIZE
+ * Demodulated samples received - all the rest
+ */
+void RAMFUNC SnoopIso14443(void)
+{
+       // We won't start recording the frames that we acquire until we trigger;
+       // a good trigger condition to get started is probably when we see a
+       // response from the tag.
+       int triggered = TRUE;                   // TODO: set and evaluate trigger condition
+
+       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+       BigBuf_free();
+
+       clear_trace();
+       set_tracing(TRUE);
+
+       // The DMA buffer, used to stream samples from the FPGA
+       int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE);
+       int lastRxCounter;
+       int8_t *upTo;
+       int ci, cq;
+       int maxBehindBy = 0;
+
+       // Count of samples received so far, so that we can include timing
+       // information in the trace buffer.
+       int samples = 0;
+
+       DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
+       UartInit(BigBuf_malloc(MAX_FRAME_SIZE));
+
+       // Print some debug information about the buffer sizes
+       Dbprintf("Snooping buffers initialized:");
+       Dbprintf("  Trace: %i bytes", BigBuf_max_traceLen());
+       Dbprintf("  Reader -> tag: %i bytes", MAX_FRAME_SIZE);
+       Dbprintf("  tag -> Reader: %i bytes", MAX_FRAME_SIZE);
+       Dbprintf("  DMA: %i bytes", DMA_BUFFER_SIZE);
+
+       // Signal field is off with the appropriate LED
+       LED_D_OFF();
+
+       // And put the FPGA in the appropriate mode
+       FpgaWriteConfWord(
+               FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
+               FPGA_HF_READER_RX_XCORR_SNOOP);
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+
+       // Setup for the DMA.
+       FpgaSetupSsc();
+       upTo = dmaBuf;
+       lastRxCounter = DMA_BUFFER_SIZE;
+       FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE);
+       uint8_t parity[MAX_PARITY_SIZE];
+       LED_A_ON();
+               
+       bool TagIsActive = FALSE;
+       bool ReaderIsActive = FALSE;
+       
+       // And now we loop, receiving samples.
+       for(;;) {
+               int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &
+                                                               (DMA_BUFFER_SIZE-1);
+               if(behindBy > maxBehindBy) {
+                       maxBehindBy = behindBy;
+                       if(behindBy > (9*DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not?
+                               Dbprintf("blew circular buffer! behindBy=0x%x", behindBy);
+                               break;
+                       }
+               }
+               if(behindBy < 2) continue;
+
+               ci = upTo[0];
+               cq = upTo[1];
+               upTo += 2;
+               lastRxCounter -= 2;
+               if(upTo >= dmaBuf + DMA_BUFFER_SIZE) {
+                       upTo = dmaBuf;
+                       lastRxCounter += DMA_BUFFER_SIZE;
+                       AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf;
+                       AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
+               }
+
+               samples += 2;
+
+               if (!TagIsActive) {                                                     // no need to try decoding reader data if the tag is sending
+                       if(Handle14443UartBit(ci & 0x01)) {
+                       if(triggered && tracing) {
+                               GetParity(Uart.output, Uart.byteCnt, parity);
+                               LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE);
+                       }
+                       if(Uart.byteCnt==0) Dbprintf("[1] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt);
+
+                       /* And ready to receive another command. */
+                       UartReset();
+                       /* And also reset the demod code, which might have been */
+                       /* false-triggered by the commands from the reader. */
+                       DemodReset();
+               }
+                       if(Handle14443UartBit(cq & 0x01)) {
+                       if(triggered && tracing) {
+                               GetParity(Uart.output, Uart.byteCnt, parity);
+                               LogTrace(Uart.output,Uart.byteCnt,samples, samples, parity, TRUE);
+                       }
+                       if(Uart.byteCnt==0) Dbprintf("[2] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt);
+
+                       /* And ready to receive another command. */
+                       UartReset();
+                       /* And also reset the demod code, which might have been */
+                       /* false-triggered by the commands from the reader. */
+                       DemodReset();
+               }
+                       ReaderIsActive = (Uart.state != STATE_UNSYNCD);
+               }
+
+               if(!ReaderIsActive) {                                           // no need to try decoding tag data if the reader is sending - and we cannot afford the time
+                       if(Handle14443SamplesDemod(ci & 0xFE, cq & 0xFE)) {
+
+                       //Use samples as a time measurement
+                       if(tracing)
+                       {
+                               uint8_t parity[MAX_PARITY_SIZE];
+                               GetParity(Demod.output, Demod.len, parity);
+                               LogTrace(Demod.output, Demod.len,samples, samples, parity, FALSE);
+                       }
+                       triggered = TRUE;
+                       LED_A_OFF();
+                       LED_B_ON();
+
+                       // And ready to receive another response.
+                       DemodReset();
+               }
+                       TagIsActive = (Demod.state != DEMOD_UNSYNCD);
+               }
+
+               WDT_HIT();
+
+               if(!tracing) {
+                       DbpString("Reached trace limit");
+                       break;
+               }
+
+               if(BUTTON_PRESS()) {
+                       DbpString("cancelled");
+                       break;
+               }
+       }
+       FpgaDisableSscDma();
+       LED_A_OFF();
+       LED_B_OFF();
+       LED_C_OFF();
+       AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+       DbpString("Snoop statistics:");
+       Dbprintf("  Max behind by: %i", maxBehindBy);
+       Dbprintf("  Uart State: %x", Uart.state);
+       Dbprintf("  Uart ByteCnt: %i", Uart.byteCnt);
+       Dbprintf("  Uart ByteCntMax: %i", Uart.byteCntMax);
+       Dbprintf("  Trace length: %i", BigBuf_get_traceLen());
+}
+
+
+/*
+ * Send raw command to tag ISO14443B
+ * @Input
+ * datalen     len of buffer data
+ * recv        bool when true wait for data from tag and send to client
+ * powerfield  bool leave the field on when true
+ * data        buffer with byte to send
+ *
+ * @Output
+ * none
+ *
+ */
+void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield_trace, uint8_t data[])
+{
+       uint8_t powerfield = powerfield_trace & 1;
+       uint8_t trace = powerfield_trace & 2;
+       if (trace){
+               clear_trace();
+               set_tracing(TRUE);
+       }
+       FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+       if(!powerfield)
+       {
+               // Make sure that we start from off, since the tags are stateful;
+               // confusing things will happen if we don't reset them between reads.
+               FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+               LED_D_OFF();
+               SpinDelay(200);
+       }
+
+       if(!GETBIT(GPIO_LED_D))
+       {
+               SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+               FpgaSetupSsc();
+
+               // Now give it time to spin up.
+               // Signal field is on with the appropriate LED
+               LED_D_ON();
+               FpgaWriteConfWord(
+                       FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
+               SpinDelay(200);
+       }
+
+       CodeAndTransmit14443bAsReader(data, datalen);
+
+       if(recv)
+       {
+               GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE);
+               uint16_t iLen = MIN(Demod.len,USB_CMD_DATA_SIZE);
+               cmd_send(CMD_ACK,iLen,0,0,Demod.output,iLen);
+       }
+       if(!powerfield)
+       {
+               FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+               LED_D_OFF();
+       }
+}
+
index 074a0f7896333bc5ece3020bb63aaa989029eecc..d11436ec72c21905bf89c19764012b3148e80536 100644 (file)
@@ -8,14 +8,14 @@
 // LEGIC RF simulation code
 //-----------------------------------------------------------------------------
 
-#include "proxmark3.h"
+#include "../include/proxmark3.h"
 #include "apps.h"
 #include "util.h"
 #include "string.h"
 
 #include "legicrf.h"
-#include "legic_prng.h"
-#include "crc.h"
+#include "../include/legic_prng.h"
+#include "../common/crc.h"
 
 static struct legic_frame {
        int bits;
index c3fa8a0e630f2f743aaedd247b2d711c89610385..c26d063b847fb1facdaea0b5ad714ca8249ff73a 100644 (file)
@@ -379,7 +379,7 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc)
        AcquireTiType();
 
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       DbpString("Now use tiread to check");
+       DbpString("Now use 'lf ti read' to check");
 }
 
 void SimulateTagLowFrequency(int period, int gap, int ledcontrol)
@@ -756,7 +756,7 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
 {
        uint8_t *dest = BigBuf_get_addr();
        //const size_t sizeOfBigBuff = BigBuf_max_traceLen();
-       size_t size; 
+       size_t size = 0
        uint32_t hi2=0, hi=0, lo=0;
        int idx=0;
        // Configure to go in 125Khz listen mode
@@ -866,24 +866,24 @@ void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol)
 
                if (errCnt<0) continue;
        
-               errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo);
-               if (errCnt){
-                       if (size>64){
-                               Dbprintf("EM XL TAG ID: %06x%08x%08x - (%05d_%03d_%08d)",
-                                 hi,
-                                 (uint32_t)(lo>>32),
-                                 (uint32_t)lo,
-                                 (uint32_t)(lo&0xFFFF),
-                                 (uint32_t)((lo>>16LL) & 0xFF),
-                                 (uint32_t)(lo & 0xFFFFFF));
-                       } else {
-                               Dbprintf("EM TAG ID: %02x%08x - (%05d_%03d_%08d)",
-                                 (uint32_t)(lo>>32),
-                                 (uint32_t)lo,
-                                 (uint32_t)(lo&0xFFFF),
-                                 (uint32_t)((lo>>16LL) & 0xFF),
-                                 (uint32_t)(lo & 0xFFFFFF));
-                       }
+                       errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo);
+                       if (errCnt){
+                               if (size>64){
+                                       Dbprintf("EM XL TAG ID: %06x%08x%08x - (%05d_%03d_%08d)",
+                                         hi,
+                                         (uint32_t)(lo>>32),
+                                         (uint32_t)lo,
+                                         (uint32_t)(lo&0xFFFF),
+                                         (uint32_t)((lo>>16LL) & 0xFF),
+                                         (uint32_t)(lo & 0xFFFFFF));
+                               } else {
+                                       Dbprintf("EM TAG ID: %02x%08x - (%05d_%03d_%08d)",
+                                         (uint32_t)(lo>>32),
+                                         (uint32_t)lo,
+                                         (uint32_t)(lo&0xFFFF),
+                                         (uint32_t)((lo>>16LL) & 0xFF),
+                                         (uint32_t)(lo & 0xFFFFFF));
+                               }
 
                        if (findone){
                                if (ledcontrol) LED_A_OFF();
@@ -908,6 +908,8 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
        uint8_t version=0;
        uint8_t facilitycode=0;
        uint16_t number=0;
+       uint8_t crc = 0;
+       uint16_t calccrc = 0;
        // Configure to go in 125Khz listen mode
        LFSetupFPGAForADC(95, true);
 
@@ -919,45 +921,62 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
                WDT_HIT();
                idx = IOdemodFSK(dest, BigBuf_max_traceLen());
                if (idx<0) continue;
-               //valid tag found
-
-               //Index map
-               //0           10          20          30          40          50          60
-               //|           |           |           |           |           |           |
-               //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
-               //-----------------------------------------------------------------------------
-               //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 ???????? 11
-               //
-               //XSF(version)facility:codeone+codetwo
-               //Handle the data
-               if(findone){ //only print binary if we are doing one
-                       Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx],   dest[idx+1],   dest[idx+2],dest[idx+3],dest[idx+4],dest[idx+5],dest[idx+6],dest[idx+7],dest[idx+8]);
-                       Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+9], dest[idx+10],dest[idx+11],dest[idx+12],dest[idx+13],dest[idx+14],dest[idx+15],dest[idx+16],dest[idx+17]);
-                       Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+18],dest[idx+19],dest[idx+20],dest[idx+21],dest[idx+22],dest[idx+23],dest[idx+24],dest[idx+25],dest[idx+26]);
-                       Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+27],dest[idx+28],dest[idx+29],dest[idx+30],dest[idx+31],dest[idx+32],dest[idx+33],dest[idx+34],dest[idx+35]);
-                       Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+36],dest[idx+37],dest[idx+38],dest[idx+39],dest[idx+40],dest[idx+41],dest[idx+42],dest[idx+43],dest[idx+44]);
-                       Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+45],dest[idx+46],dest[idx+47],dest[idx+48],dest[idx+49],dest[idx+50],dest[idx+51],dest[idx+52],dest[idx+53]);
-                       Dbprintf("%d%d%d%d%d%d%d%d %d%d",dest[idx+54],dest[idx+55],dest[idx+56],dest[idx+57],dest[idx+58],dest[idx+59],dest[idx+60],dest[idx+61],dest[idx+62],dest[idx+63]);
-               }
-               code = bytebits_to_byte(dest+idx,32);
-               code2 = bytebits_to_byte(dest+idx+32,32);
-               version = bytebits_to_byte(dest+idx+27,8); //14,4
+                       //valid tag found
+
+                       //Index map
+                       //0           10          20          30          40          50          60
+                       //|           |           |           |           |           |           |
+                       //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
+                       //-----------------------------------------------------------------------------
+            //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 checksum 11
+                       //
+                       //Checksum:  
+                       //00000000 0 11110000 1 11100000 1 00000001 1 00000011 1 10110110 1 01110101 11
+                       //preamble      F0         E0         01         03         B6         75
+                       // How to calc checksum,
+                       // http://www.proxmark.org/forum/viewtopic.php?id=364&p=6
+                       //   F0 + E0 + 01 + 03 + B6 = 28A
+                       //   28A & FF = 8A
+                       //   FF - 8A = 75
+                       // Checksum: 0x75
+                       //XSF(version)facility:codeone+codetwo
+                       //Handle the data
+                       if(findone){ //only print binary if we are doing one
+                               Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx],   dest[idx+1],   dest[idx+2],dest[idx+3],dest[idx+4],dest[idx+5],dest[idx+6],dest[idx+7],dest[idx+8]);
+                               Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+9], dest[idx+10],dest[idx+11],dest[idx+12],dest[idx+13],dest[idx+14],dest[idx+15],dest[idx+16],dest[idx+17]);
+                               Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+18],dest[idx+19],dest[idx+20],dest[idx+21],dest[idx+22],dest[idx+23],dest[idx+24],dest[idx+25],dest[idx+26]);
+                               Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+27],dest[idx+28],dest[idx+29],dest[idx+30],dest[idx+31],dest[idx+32],dest[idx+33],dest[idx+34],dest[idx+35]);
+                               Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+36],dest[idx+37],dest[idx+38],dest[idx+39],dest[idx+40],dest[idx+41],dest[idx+42],dest[idx+43],dest[idx+44]);
+                               Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+45],dest[idx+46],dest[idx+47],dest[idx+48],dest[idx+49],dest[idx+50],dest[idx+51],dest[idx+52],dest[idx+53]);
+                               Dbprintf("%d%d%d%d%d%d%d%d %d%d",dest[idx+54],dest[idx+55],dest[idx+56],dest[idx+57],dest[idx+58],dest[idx+59],dest[idx+60],dest[idx+61],dest[idx+62],dest[idx+63]);
+                       }
+                       code = bytebits_to_byte(dest+idx,32);
+                       code2 = bytebits_to_byte(dest+idx+32,32);
+                       version = bytebits_to_byte(dest+idx+27,8); //14,4
                facilitycode = bytebits_to_byte(dest+idx+18,8);
-               number = (bytebits_to_byte(dest+idx+36,8)<<8)|(bytebits_to_byte(dest+idx+45,8)); //36,9
-
-               Dbprintf("XSF(%02d)%02x:%05d (%08x%08x)",version,facilitycode,number,code,code2);
-               // if we're only looking for one tag
-               if (findone){
-                       if (ledcontrol) LED_A_OFF();
-                       //LED_A_OFF();
-                       *high=code;
-                       *low=code2;
-                       return;
-               }
-               code=code2=0;
-               version=facilitycode=0;
-               number=0;
-               idx=0;
+                       number = (bytebits_to_byte(dest+idx+36,8)<<8)|(bytebits_to_byte(dest+idx+45,8)); //36,9
+
+                       crc = bytebits_to_byte(dest+idx+54,8);
+                       for (uint8_t i=1; i<6; ++i)
+                               calccrc += bytebits_to_byte(dest+idx+9*i,8);
+                       calccrc &= 0xff;
+                       calccrc = 0xff - calccrc;
+                       
+                       char *crcStr = (crc == calccrc) ? "ok":"!crc";
+
+            Dbprintf("IO Prox XSF(%02d)%02x:%05d (%08x%08x)  [%02x %s]",version,facilitycode,number,code,code2, crc, crcStr);
+                       // if we're only looking for one tag
+                       if (findone){
+                               if (ledcontrol) LED_A_OFF();
+                               //LED_A_OFF();
+                               *high=code;
+                               *low=code2;
+                               return;
+                       }
+                       code=code2=0;
+                       version=facilitycode=0;
+                       number=0;
+                       idx=0;
 
                WDT_HIT();
        }
@@ -1024,10 +1043,24 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
  * To compensate antenna falling times shorten the write times
  * and enlarge the gap ones.
  */
-#define START_GAP 50*8 // 10 - 50fc 250
-#define WRITE_GAP 20*8 //    - 30fc 160
-#define WRITE_0   24*8 // 16 - 63fc 54fc 144
-#define WRITE_1   54*8 // 48 - 63fc 54fc 432 for T55x7; 448 for E5550 //400
+#define START_GAP 31*8 // was 250 // SPEC:   8 - 50fc [15fc]
+#define WRITE_GAP 20*8 // was 160 // SPEC:   8 - 20fc [10fc]
+#define WRITE_0   18*8 // was 144 // SPEC:  16 - 32fc [24fc]  192
+#define WRITE_1   50*8 // was 400 // SPEC:  48 - 64fc [56fc]  432 for T55x7; 448 for E5550
+
+//  VALUES TAKEN FROM EM4x function: SendForward
+//  START_GAP = 440;       (55*8) cycles at 125Khz (8us = 1cycle)
+//  WRITE_GAP = 128;       (16*8)
+//  WRITE_1   = 256 32*8;  (32*8) 
+
+//  These timings work for 4469/4269/4305 (with the 55*8 above)
+//  WRITE_0 = 23*8 , 9*8  SpinDelayUs(23*8); 
+
+// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK)
+// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
+// Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier)
+// T0 = TIMER_CLOCK1 / 125000 = 192
+// 1 Cycle = 8 microseconds(us)
 
 #define T55xx_SAMPLES_SIZE      12000 // 32 x 32 x 10  (32 bit times numofblock (7), times clock skip..)
 
@@ -1037,7 +1070,7 @@ void T55xxWriteBit(int bit)
        FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
        FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
        FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
-       if (bit == 0)
+       if (!bit)
                SpinDelayUs(WRITE_0);
        else
                SpinDelayUs(WRITE_1);
@@ -1491,10 +1524,16 @@ void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int
 #define max(x,y) ( x<y ? y:x)
 
 int DemodPCF7931(uint8_t **outBlocks) {
-       uint8_t BitStream[256];
-       uint8_t Blocks[8][16];
-       uint8_t *GraphBuffer = BigBuf_get_addr();
+
+    uint8_t bits[256] = {0x00};
+       uint8_t blocks[8][16];
+    uint8_t *dest = BigBuf_get_addr();
+    
        int GraphTraceLen = BigBuf_max_traceLen();
+       if (  GraphTraceLen > 18000 )
+               GraphTraceLen = 18000;
+       
+       
        int i, j, lastval, bitidx, half_switch;
        int clock = 64;
        int tolerance = clock / 8;
@@ -1505,8 +1544,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
        uint8_t dir;
 
        LFSetupFPGAForADC(95, true);
-       DoAcquisition_default(0, 0);
-
+       DoAcquisition_default(0, true);
 
        lmin = 64;
        lmax = 192;
@@ -1514,9 +1552,9 @@ int DemodPCF7931(uint8_t **outBlocks) {
        i = 2;
 
        /* Find first local max/min */
-       if(GraphBuffer[1] > GraphBuffer[0]) {
+    if(dest[1] > dest[0]) {
                while(i < GraphTraceLen) {
-                       if( !(GraphBuffer[i] > GraphBuffer[i-1]) && GraphBuffer[i] > lmax)
+            if( !(dest[i] > dest[i-1]) && dest[i] > lmax)
                                break;
                        i++;
                }
@@ -1524,7 +1562,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
        }
        else {
                while(i < GraphTraceLen) {
-                       if( !(GraphBuffer[i] < GraphBuffer[i-1]) && GraphBuffer[i] < lmin)
+            if( !(dest[i] < dest[i-1]) && dest[i] < lmin)
                                break;
                        i++;
                }
@@ -1538,7 +1576,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
 
        for (bitidx = 0; i < GraphTraceLen; i++)
        {
-               if ( (GraphBuffer[i-1] > GraphBuffer[i] && dir == 1 && GraphBuffer[i] > lmax) || (GraphBuffer[i-1] < GraphBuffer[i] && dir == 0 && GraphBuffer[i] < lmin))
+        if ( (dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin))
                {
                        lc = i - lastval;
                        lastval = i;
@@ -1567,14 +1605,14 @@ int DemodPCF7931(uint8_t **outBlocks) {
                                        block_done = 1;
                                }
                                else if(half_switch == 1) {
-                                       BitStream[bitidx++] = 0;
+                    bits[bitidx++] = 0;
                                        half_switch = 0;
                                }
                                else
                                        half_switch++;
                        } else if (abs(lc-clock) < tolerance) {
                                // 64TO
-                               BitStream[bitidx++] = 1;
+                bits[bitidx++] = 1;
                        } else {
                                // Error
                                warnings++;
@@ -1588,14 +1626,15 @@ int DemodPCF7931(uint8_t **outBlocks) {
                        if(block_done == 1) {
                                if(bitidx == 128) {
                                        for(j=0; j<16; j++) {
-                                               Blocks[num_blocks][j] = 128*BitStream[j*8+7]+
-                                                               64*BitStream[j*8+6]+
-                                                               32*BitStream[j*8+5]+
-                                                               16*BitStream[j*8+4]+
-                                                               8*BitStream[j*8+3]+
-                                                               4*BitStream[j*8+2]+
-                                                               2*BitStream[j*8+1]+
-                                                               BitStream[j*8];
+                        blocks[num_blocks][j] = 128*bits[j*8+7]+
+                                64*bits[j*8+6]+
+                                32*bits[j*8+5]+
+                                16*bits[j*8+4]+
+                                8*bits[j*8+3]+
+                                4*bits[j*8+2]+
+                                2*bits[j*8+1]+
+                                bits[j*8];
+                                               
                                        }
                                        num_blocks++;
                                }
@@ -1604,17 +1643,14 @@ int DemodPCF7931(uint8_t **outBlocks) {
                                half_switch = 0;
                        }
                        if(i < GraphTraceLen)
-                       {
-                               if (GraphBuffer[i-1] > GraphBuffer[i]) dir=0;
-                               else dir = 1;
-                       }
+                dir =(dest[i-1] > dest[i]) ? 0 : 1;
                }
                if(bitidx==255)
                        bitidx=0;
                warnings = 0;
                if(num_blocks == 4) break;
        }
-       memcpy(outBlocks, Blocks, 16*num_blocks);
+    memcpy(outBlocks, blocks, 16*num_blocks);
        return num_blocks;
 }
 
@@ -1912,9 +1948,14 @@ void EM4xLogin(uint32_t Password) {
 
 void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
 
-       uint8_t fwd_bit_count;
        uint8_t *dest = BigBuf_get_addr();
-       int m=0, i=0;
+       uint16_t bufferlength = BigBuf_max_traceLen();
+       uint32_t i = 0;
+
+       // Clear destination buffer before sending the command  0x80 = average.
+       memset(dest, 0x80, bufferlength);
+       
+    uint8_t fwd_bit_count;
 
        //If password mode do login
        if (PwdMode == 1) EM4xLogin(Pwd);
@@ -1923,9 +1964,6 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
        fwd_bit_count = Prepare_Cmd( FWD_CMD_READ );
        fwd_bit_count += Prepare_Addr( Address );
 
-       m = BigBuf_max_traceLen();
-       // Clear destination buffer before sending the command
-       memset(dest, 128, m);
        // Connect the A/D to the peak-detected low-frequency path.
        SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
        // Now set up the SSC to get the ADC samples that are now streaming at us.
@@ -1941,10 +1979,12 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
                }
                if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
                        dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
-                       i++;
-                       if (i >= m) break;
+                       ++i;
+                       if (i >= bufferlength) break;
                }
        }
+  
+       cmd_send(CMD_ACK,0,0,0,0,0);
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
        LED_D_OFF();
 }
index 939c90028796ef823e0e0c3d5acfbd841cf4f48f..5d10ad8161c2a97227ff9fbd91b728d87bfb68a9 100644 (file)
 #include "mifarecmd.h"\r
 #include "apps.h"\r
 #include "util.h"\r
-#include "crc.h"\r
 \r
-// the block number for the ISO14443-4 PCB\r
-uint8_t pcb_blocknum = 0;\r
-// Deselect card by sending a s-block. the crc is precalced for speed\r
-static  uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4};\r
+#include "crc.h"\r
 \r
 //-----------------------------------------------------------------------------\r
 // Select, Authenticate, Read a MIFARE tag. \r
@@ -173,7 +169,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
                return;\r
        }\r
 \r
-       cmd_send(CMD_ACK,1,0,0,dataout,16);\r
+    cmd_send(CMD_ACK,1,0,0,dataout,16);\r
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
        LEDsoff();\r
 }\r
@@ -213,7 +209,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
                isOK = 0;\r
                if (MF_DBGLEVEL >= 1)   Dbprintf("Can't select card");\r
        }\r
-\r
+       \r
        \r
        if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {\r
                isOK = 0;\r
@@ -308,15 +304,15 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
                        Dbprintf("Data exceeds buffer!!");\r
                        break;\r
                }\r
-       \r
-               len = mifare_ultra_readblock(blockNo + i, dataout + 4 * i);\r
 \r
+               len = mifare_ultra_readblock(blockNo + i, dataout + 4 * i);\r
+               \r
                if (len) {\r
                        if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block %d error",i);\r
                        // if no blocks read - error out\r
                        if (i==0){\r
                                OnError(2);\r
-                               return;\r
+                       return;\r
                        } else {\r
                                //stop at last successful read block and return what we got\r
                                break;\r
@@ -483,26 +479,26 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
 \r
        // UL-C authentication\r
        if ( useKey ) {\r
-               uint8_t key[16] = {0x00};\r
+               uint8_t key[16] = {0x00};       \r
                memcpy(key, datain+4, sizeof(key) );\r
 \r
                if ( !mifare_ultra_auth(key) ) {\r
                        OnError(1);\r
-                       return;\r
+                       return;                 \r
                }\r
        }\r
        \r
        // UL-EV1 / NTAG authentication\r
-       if (usePwd) {\r
+       if (usePwd) { \r
                uint8_t pwd[4] = {0x00};\r
                memcpy(pwd, datain+4, 4);\r
                uint8_t pack[4] = {0,0,0,0};\r
                if (!mifare_ul_ev1_auth(pwd, pack)) {\r
                        OnError(1);\r
-                       return;\r
+                       return;                 \r
                }\r
        }\r
-\r
+       \r
        if(mifare_ultra_writeblock(blockNo, blockdata)) {\r
                if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");\r
                OnError(0);\r
@@ -717,7 +713,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
                LED_B_OFF();\r
        \r
        }\r
-       //  -------------------------------------------------------------------------------------------------   \r
+//  -------------------------------------------------------------------------------------------------  \r
        \r
        LED_C_ON();\r
 \r
@@ -1040,12 +1036,12 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
                if (workFlags & 0x01) {\r
                        if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
                                if (MF_DBGLEVEL >= 1)   Dbprintf("Can't select card");\r
-                               break;\r
+                               //break;\r
                        };\r
 \r
                        if(mifare_classic_halt(NULL, cuid)) {\r
                                if (MF_DBGLEVEL >= 1)   Dbprintf("Halt error");\r
-                               break;\r
+                               //break;\r
                        };\r
                };\r
        \r
@@ -1224,7 +1220,74 @@ void MifareCIdent(){
        cmd_send(CMD_ACK,isOK,0,0,0,0);\r
 }\r
 \r
-                       //\r
+void MifareCollectNonces(uint32_t arg0, uint32_t arg1){\r
+\r
+       BigBuf_free();\r
+\r
+       uint32_t iterations = arg0;\r
+       uint8_t uid[10] = {0x00};\r
+\r
+       uint8_t *response = BigBuf_malloc(MAX_MIFARE_FRAME_SIZE);\r
+       uint8_t *responsePar = BigBuf_malloc(MAX_MIFARE_PARITY_SIZE);\r
+\r
+       uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b };\r
+       \r
+       // get memory from BigBuf.\r
+       uint8_t *nonces = BigBuf_malloc(iterations * 4);\r
+\r
+       LED_A_ON();\r
+       LED_B_OFF();\r
+       LED_C_OFF();\r
+\r
+       clear_trace();\r
+       set_tracing(TRUE);\r
+       iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
+       \r
+       for (int i = 0; i < iterations; i++) {\r
+                                               \r
+               WDT_HIT();\r
+\r
+               // Test if the action was cancelled\r
+               if(BUTTON_PRESS()) break;\r
+               \r
+               //              if(mifare_classic_halt(pcs, cuid)) {\r
+               //                      if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
+               //}\r
+\r
+               if(!iso14443a_select_card(uid, NULL, NULL)) {\r
+                       if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
+                       continue;\r
+               };\r
+\r
+               // Transmit MIFARE_CLASSIC_AUTH.\r
+               ReaderTransmit(mf_auth, sizeof(mf_auth), NULL);\r
+\r
+               // Receive the (4 Byte) "random" nonce\r
+               if (!ReaderReceive(response, responsePar)) {\r
+                       if (MF_DBGLEVEL >= 1)   Dbprintf("Couldn't receive tag nonce");\r
+                       continue;\r
+               }       \r
+               \r
+               nonces[i*4] = bytes_to_num(response, 4);\r
+       }\r
+               \r
+       int packLen =  iterations * 4;\r
+       int packSize = 0;\r
+       int packNum = 0;\r
+       while (packLen > 0) {\r
+               packSize = MIN(USB_CMD_DATA_SIZE, packLen);\r
+               LED_B_ON();\r
+               cmd_send(CMD_ACK, 77, 0, packSize, nonces - packLen, packSize);\r
+               LED_B_OFF();\r
+\r
+               packLen -= packSize;\r
+               packNum++;\r
+       }\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+       LEDsoff();\r
+}\r
+\r
+//\r
 // DESFIRE\r
 //\r
 \r
@@ -1232,7 +1295,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){
 \r
        byte_t dataout[11] = {0x00};\r
        uint8_t uid[10] = {0x00};\r
-       uint32_t cuid;\r
+       uint32_t cuid = 0x00;\r
     \r
        clear_trace();\r
        iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
@@ -1258,15 +1321,15 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){
 \r
        uint32_t cuid = arg0;\r
        uint8_t key[16] = {0x00};\r
-       byte_t isOK = 0;\r
        byte_t dataout[12] = {0x00};\r
+       byte_t isOK = 0;\r
     \r
        memcpy(key, datain, 16);\r
        \r
        isOK = mifare_desfire_des_auth2(cuid, key, dataout);\r
        \r
        if( isOK) {\r
-               if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed");  \r
+           if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed");  \r
                OnError(4);\r
                return;\r
        }\r
@@ -1276,19 +1339,4 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){
        cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout));\r
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
        LEDsoff();\r
-}\r
-\r
-void OnSuccess(){\r
-       pcb_blocknum = 0;\r
-       ReaderTransmit(deselect_cmd, 3 , NULL);\r
-       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
-       LEDsoff();\r
-}\r
-\r
-void OnError(uint8_t reason){\r
-       pcb_blocknum = 0;\r
-       ReaderTransmit(deselect_cmd, 3 , NULL);\r
-       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
-       cmd_send(CMD_ACK,0,reason,0,0,0);\r
-       LEDsoff();\r
-}\r
+}
\ No newline at end of file
index 3c00a3437b25fc9c48764f96b996a8b2fca86e76..2c5a7e3fcf6484d3783dac57d0b7c9e0634a438f 100644 (file)
 #ifndef __MIFARECMD_H\r
 #define __MIFARECMD_H\r
 \r
-#include "proxmark3.h"\r
+#include "../include/proxmark3.h"\r
 #include "apps.h"\r
 #include "util.h"\r
 #include "string.h"\r
 \r
-#include "iso14443crc.h"\r
+#include "../common/iso14443crc.h"\r
 #include "iso14443a.h"\r
 #include "crapto1.h"\r
 #include "mifareutil.h"\r
-#include "common.h"\r
-\r
+#include "../include/common.h"\r
 \r
 #endif
\ No newline at end of file
diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c
new file mode 100644 (file)
index 0000000..fb48647
--- /dev/null
@@ -0,0 +1,509 @@
+#include "mifaredesfire.h"
+#include "des.h"
+#include "BigBuf.h"
+
+#define MAX_APPLICATION_COUNT 28
+#define MAX_FILE_COUNT 16
+#define MAX_DESFIRE_FRAME_SIZE 60
+#define NOT_YET_AUTHENTICATED 255
+#define FRAME_PAYLOAD_SIZE (MAX_DESFIRE_FRAME_SIZE - 5)
+#define RECEIVE_SIZE 64
+
+// the block number for the ISO14443-4 PCB
+uint8_t pcb_blocknum = 0;
+// Deselect card by sending a s-block. the crc is precalced for speed
+static  uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4};
+
+//static uint8_t __msg[MAX_FRAME_SIZE] = { 0x0A, 0x00, 0x00, /* ..., */ 0x00 };
+/*                                       PCB   CID   CMD    PAYLOAD    */
+//static uint8_t __res[MAX_FRAME_SIZE];
+
+bool InitDesfireCard(){
+       
+       byte_t cardbuf[USB_CMD_DATA_SIZE] = {0x00};
+
+       iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf;
+       
+       set_tracing(TRUE);
+       iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
+       
+       int len = iso14443a_select_card(NULL,card,NULL);
+
+       if (!len) {
+               if (MF_DBGLEVEL >= MF_DBG_ERROR)
+                       Dbprintf("Can't select card");
+               OnError(1);
+               return false;
+       }
+       return true;
+}
+
+// ARG0 flag enums
+enum  {
+ NONE          =       0x00,
+ INIT          =       0x01,
+ DISCONNECT =  0x02,
+ CLEARTRACE    =       0x04,
+ BAR           =       0x08,
+} CmdOptions ;
+
+void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){
+       
+       /* ARG0 contains flags.
+               0x01 = init card.
+               0x02 = Disconnect
+               0x03
+       */
+       uint8_t flags = arg0;
+       size_t datalen = arg1;
+       uint8_t resp[RECEIVE_SIZE];
+       memset(resp,0,sizeof(resp));
+       
+       if (MF_DBGLEVEL >= 4) {
+               Dbprintf(" flags : %02X", flags);
+               Dbprintf(" len   : %02X", datalen);
+               print_result(" RX    : ", datain, datalen);
+       }
+       
+       if ( flags & CLEARTRACE ){
+               clear_trace();
+       }
+       
+       if ( flags & INIT ){
+               if ( !InitDesfireCard() )
+                       return;
+       }
+       
+       int len = DesfireAPDU(datain, datalen, resp);
+       if (MF_DBGLEVEL >= 4) {
+               print_result("ERR <--: ", resp, len);
+       }
+
+       if ( !len ) {
+               OnError(2);
+               return;
+       }
+       
+       // reset the pcb_blocknum,
+       pcb_blocknum = 0;
+       
+       if ( flags & DISCONNECT ){
+               OnSuccess();
+       }
+       
+       cmd_send(CMD_ACK,1,len,0,resp,len);
+}
+
+void MifareDesfireGetInformation(){
+               
+       int len = 0;
+       uint8_t resp[USB_CMD_DATA_SIZE] = {0x00};
+       uint8_t dataout[USB_CMD_DATA_SIZE] = {0x00};
+       byte_t cardbuf[USB_CMD_DATA_SIZE] = {0x00};
+       
+       /*
+               1 = PCB                                 1
+               2 = cid                                 2
+               3 = desfire command             3 
+               4-5 = crc                               4  key
+                                                               5-6 crc                                                         
+               PCB == 0x0A because sending CID byte.
+               CID == 0x00 first card?         
+       */
+       clear_trace();
+       set_tracing(TRUE);
+       iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
+
+       // card select - information
+       iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf;
+       byte_t isOK = iso14443a_select_card(NULL, card, NULL);
+       if ( isOK == 0) {
+               if (MF_DBGLEVEL >= MF_DBG_ERROR) {
+                       Dbprintf("Can't select card");
+               }
+               OnError(1);
+               return;
+       }
+
+       memcpy(dataout,card->uid,7);
+
+       LED_A_ON();
+       LED_B_OFF();
+       LED_C_OFF();
+       
+       uint8_t cmd[] = {GET_VERSION};  
+       size_t cmd_len = sizeof(cmd);
+       
+       len =  DesfireAPDU(cmd, cmd_len, resp);
+       if ( !len ) {
+               print_result("ERROR <--: ", resp, len); 
+               OnError(2);
+               return;
+       }
+       
+       LED_A_OFF();
+       LED_B_ON();
+       memcpy(dataout+7,resp+3,7);
+       
+       // ADDITION_FRAME 1
+       cmd[0] = ADDITIONAL_FRAME;
+       len =  DesfireAPDU(cmd, cmd_len, resp);
+       if ( !len ) {
+               print_result("ERROR <--: ", resp, len); 
+               OnError(2);
+               return;
+       }       
+       
+       LED_B_OFF();
+       LED_C_ON();
+       memcpy(dataout+7+7,resp+3,7);
+
+       // ADDITION_FRAME 2
+       len =  DesfireAPDU(cmd, cmd_len, resp);
+       if ( !len ) {
+               print_result("ERROR <--: ", resp, len); 
+               OnError(2);
+               return;
+       }
+       
+       memcpy(dataout+7+7+7,resp+3,14);
+       
+       cmd_send(CMD_ACK,1,0,0,dataout,sizeof(dataout));
+               
+       // reset the pcb_blocknum,
+       pcb_blocknum = 0;
+       OnSuccess();
+}
+
+void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno,  uint8_t *datain){
+
+       int len = 0;
+       //uint8_t PICC_MASTER_KEY8[8] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47};
+       uint8_t PICC_MASTER_KEY16[16] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f };
+       uint8_t null_key_data8[8] = {0x00};
+       //uint8_t null_key_data16[16] = {0x00}; 
+       //uint8_t new_key_data8[8]  = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
+       //uint8_t new_key_data16[16]  = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
+
+       uint8_t resp[256] = {0x00};
+       uint8_t IV[16] = {0x00};
+
+       size_t datalen = datain[0];
+       
+       uint8_t cmd[40] = {0x00};
+       uint8_t encRndB[16] = {0x00};
+       uint8_t decRndB[16] = {0x00};
+       uint8_t nonce[16] = {0x00};
+       uint8_t both[32] = {0x00};
+       uint8_t encBoth[32] = {0x00};
+
+       InitDesfireCard();
+       
+       // 3 olika sätt att authenticera.   AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
+       // 4 olika crypto algo   DES, 3DES, 3K3DES, AES
+       // 3 olika kommunikations sätt,   PLAIN,MAC,CRYPTO
+       
+       // des, nyckel 0, 
+       switch (mode){
+        case 1:{
+            if (algo == 1) {
+
+            uint8_t keybytes[8] = {0x00};
+            uint8_t RndA[8] = {0x00};
+            uint8_t RndB[8] = {0x00};
+            
+            if (datain[1] == 0xff){
+                memcpy(keybytes,null_key_data8,8);
+            } else{
+                memcpy(keybytes, datain+1, datalen);
+            }
+            
+            struct desfire_key defaultkey = {0};
+            desfirekey_t key = &defaultkey;
+            Desfire_des_key_new(keybytes, key);
+            
+            cmd[0] = AUTHENTICATE;
+            cmd[1] = keyno;  //keynumber
+            len = DesfireAPDU(cmd, 2, resp);
+            if ( !len ) {
+                if (MF_DBGLEVEL >= MF_DBG_ERROR) {
+                    DbpString("Authentication failed. Card timeout.");
+                }
+                OnError(3);
+                return;
+            }
+            
+            if ( resp[2] == 0xaf ){
+            } else {
+                DbpString("Authetication failed. Invalid key number.");
+                OnError(3);
+                return;
+            }
+            
+            memcpy( encRndB, resp+3, 8);
+            
+            des_dec(&decRndB, &encRndB, key->data);
+            memcpy(RndB, decRndB, 8);
+            rol(decRndB,8);
+            
+            // This should be random
+            uint8_t decRndA[8] = {0x00};
+            memcpy(RndA, decRndA, 8);
+            uint8_t encRndA[8] = {0x00};
+            
+            des_dec(&encRndA, &decRndA, key->data);
+            
+            memcpy(both, encRndA, 8);
+            
+            for (int x = 0; x < 8; x++) {
+                decRndB[x] = decRndB[x] ^ encRndA[x];
+            }
+            
+            des_dec(&encRndB, &decRndB, key->data);
+            
+            memcpy(both + 8, encRndB, 8);
+            
+            cmd[0] = ADDITIONAL_FRAME;
+            memcpy(cmd+1, both, 16 );
+            
+            len = DesfireAPDU(cmd, 17, resp);
+            if ( !len ) {
+                if (MF_DBGLEVEL >= MF_DBG_ERROR) {
+                    DbpString("Authentication failed. Card timeout.");
+                }
+                OnError(3);
+                return;
+            }
+            
+            if ( resp[2] == 0x00 ){
+                
+                struct desfire_key sessionKey = {0};
+                desfirekey_t skey = &sessionKey;
+                Desfire_session_key_new( RndA, RndB , key, skey );
+                //print_result("SESSION : ", skey->data, 8);
+                
+                memcpy(encRndA, resp+3, 8);
+                des_dec(&encRndA, &encRndA, key->data);
+                rol(decRndA,8);
+                for (int x = 0; x < 8; x++) {
+                    if (decRndA[x] != encRndA[x]) {
+                        DbpString("Authetication failed. Cannot varify PICC.");
+                        OnError(4);
+                        return;
+                    }
+                }
+                
+                //Change the selected key to a new value.
+                /*
+                 
+                cmd[0] = CHANGE_KEY;
+                cmd[1] = keyno;
+                
+                uint8_t newKey[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
+                
+                uint8_t first, second;
+                uint8_t buff1[8] = {0x00};
+                uint8_t buff2[8] = {0x00};
+                uint8_t buff3[8] = {0x00};
+                
+                memcpy(buff1,newKey, 8);
+                memcpy(buff2,newKey + 8, 8);
+                
+                ComputeCrc14443(CRC_14443_A, newKey, 16, &first, &second);
+                memcpy(buff3, &first, 1);
+                memcpy(buff3 + 1, &second, 1);
+                
+                des_dec(&buff1, &buff1, skey->data);
+                memcpy(cmd+2,buff1,8);
+                
+                for (int x = 0; x < 8; x++) {
+                    buff2[x] = buff2[x] ^ buff1[x];
+                }
+                des_dec(&buff2, &buff2, skey->data);
+                memcpy(cmd+10,buff2,8);
+                
+                for (int x = 0; x < 8; x++) {
+                    buff3[x] = buff3[x] ^ buff2[x];
+                }
+                des_dec(&buff3, &buff3, skey->data);
+                memcpy(cmd+18,buff3,8);
+                
+                // The command always times out on the first attempt, this will retry until a response
+                // is recieved.
+                len = 0;
+                while(!len) {
+                    len = DesfireAPDU(cmd,26,resp);
+                }
+                */
+                
+                OnSuccess();
+                cmd_send(CMD_ACK,1,0,0,skey->data,8);
+                
+            } else {
+                DbpString("Authetication failed.");
+                OnError(6);
+                return;
+            }
+            
+            }
+            }
+                       break;
+               case 2:
+                       //SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp);
+                       break;
+               case 3:{
+               
+                       //defaultkey
+                       uint8_t keybytes[16] = {0x00};
+                       if (datain[1] == 0xff){
+                               memcpy(keybytes,PICC_MASTER_KEY16,16); 
+                       } else{
+                               memcpy(keybytes, datain+1, datalen);
+                       }
+                       
+                       struct desfire_key defaultkey = {0x00};
+                       desfirekey_t key = &defaultkey;
+                       Desfire_aes_key_new( keybytes, key);
+               
+                       AesCtx ctx;
+                       if ( AesCtxIni(&ctx, IV, key->data, KEY128, CBC) < 0 ){
+                               if( MF_DBGLEVEL >= 4) {
+                                       Dbprintf("AES context failed to init");
+                               }
+                               OnError(7);
+                               return;
+                       }
+                       
+                       cmd[0] = AUTHENTICATE_AES;
+                       cmd[1] = 0x00;  //keynumber
+                       len = DesfireAPDU(cmd, 2, resp);
+                       if ( !len ) {
+                               if (MF_DBGLEVEL >= MF_DBG_ERROR) {
+                                       DbpString("Authentication failed. Card timeout.");
+                               }
+                               OnError(3);
+                               return;
+                       }
+                       
+                       memcpy( encRndB, resp+3, 16);
+               
+                       // dekryptera tagnonce.
+                       AesDecrypt(&ctx, encRndB, decRndB, 16);
+                       rol(decRndB,16);
+                       memcpy(both, nonce,16);
+                       memcpy(both+16, decRndB ,16 );
+                       AesEncrypt(&ctx, both, encBoth, 32 );
+                       
+                       cmd[0] = ADDITIONAL_FRAME;
+                       memcpy(cmd+1, encBoth, 32 );
+                       
+                       len = DesfireAPDU(cmd, 33, resp);  // 1 + 32 == 33
+                       if ( !len ) {
+                               if (MF_DBGLEVEL >= MF_DBG_ERROR) {
+                                       DbpString("Authentication failed. Card timeout.");
+                               }
+                OnError(3);
+                               return;
+                       }
+                       
+                       if ( resp[2] == 0x00 ){
+                               // Create AES Session key               
+                               struct desfire_key sessionKey = {0};
+                               desfirekey_t skey = &sessionKey;
+                               Desfire_session_key_new( nonce, decRndB , key, skey );
+                               print_result("SESSION : ", skey->data, 16);
+                       } else {
+                               DbpString("Authetication failed.");
+                               OnError(7);
+                               return;
+                       }
+                       break;
+               }       
+       }
+       
+       OnSuccess();
+       cmd_send(CMD_ACK,1,len,0,resp,len);
+}
+
+// 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat ISO)
+// cmd  =  cmd bytes to send
+// cmd_len = length of cmd
+// dataout = pointer to response data array
+int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){
+
+       size_t len = 0;
+       size_t wrappedLen = 0;
+       uint8_t wCmd[USB_CMD_DATA_SIZE] = {0x00};
+       
+       uint8_t resp[MAX_FRAME_SIZE];
+    uint8_t par[MAX_PARITY_SIZE];
+       
+       wrappedLen = CreateAPDU( cmd, cmd_len, wCmd);
+       
+       if (MF_DBGLEVEL >= 4) {
+               print_result("WCMD <--: ", wCmd, wrappedLen);   
+       }
+       ReaderTransmit( wCmd, wrappedLen, NULL);
+
+       len = ReaderReceive(resp, par);
+       
+       if( len == 0x00 ){
+               if (MF_DBGLEVEL >= 4) {
+                       Dbprintf("fukked");
+               }
+               return FALSE; //DATA LINK ERROR
+       }
+       // if we received an I- or R(ACK)-Block with a block number equal to the
+       // current block number, toggle the current block number
+       else if (len >= 4 // PCB+CID+CRC = 4 bytes
+                && ((resp[0] & 0xC0) == 0 // I-Block
+                    || (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
+                && (resp[0] & 0x01) == pcb_blocknum) // equal block numbers
+       {
+               pcb_blocknum ^= 1;  //toggle next block 
+       }
+
+       memcpy(dataout, resp, len);
+       return len;
+}      
+
+// CreateAPDU
+size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout){
+       
+       size_t cmdlen = MIN(len+4, USB_CMD_DATA_SIZE-1);
+
+       uint8_t cmd[cmdlen];
+       memset(cmd, 0, cmdlen);
+       
+       cmd[0] = 0x0A;  //  0x0A = skicka cid,  0x02 = ingen cid. Särskilda bitar //
+       cmd[0] |= pcb_blocknum; // OR the block number into the PCB     
+       cmd[1] = 0x00;  //  CID: 0x00 //TODO: allow multiple selected cards
+       
+       memcpy(cmd+2, datain, len);
+       AppendCrc14443a(cmd, len+2);
+       
+       memcpy(dataout, cmd, cmdlen);
+       
+       return cmdlen;
+}
+
+       // crc_update(&desfire_crc32, 0, 1); /* CMD_WRITE */
+       // crc_update(&desfire_crc32, addr, addr_sz);
+       // crc_update(&desfire_crc32, byte, 8);
+       // uint32_t crc = crc_finish(&desfire_crc32);
+
+void OnSuccess(){
+       pcb_blocknum = 0;
+       ReaderTransmit(deselect_cmd, 3 , NULL);
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       LEDsoff();
+}
+
+void OnError(uint8_t reason){
+       pcb_blocknum = 0;
+       ReaderTransmit(deselect_cmd, 3 , NULL);
+       
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+       cmd_send(CMD_ACK,0,reason,0,0,0);
+       LEDsoff();
+}
diff --git a/armsrc/mifaredesfire.h b/armsrc/mifaredesfire.h
new file mode 100644 (file)
index 0000000..659e005
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __MIFAREDESFIRE_H
+#define __MIFAREDESFIRE_H
+
+#include "../include/proxmark3.h"
+#include "apps.h"
+#include "util.h"
+#include "string.h"
+
+#include "../common/iso14443crc.h"
+#include "iso14443a.h"
+#include "desfire_key.h"
+#include "mifareutil.h"
+#include "../include/common.h"
+
+#endif
index 22daffee7b04ec74247b493c99addeb9088e4859..aa2a860f7bcf174b69769f1db4c3d4cc40d651ef 100644 (file)
 #ifndef __MIFARESNIFF_H\r
 #define __MIFARESNIFF_H\r
 \r
-#include "proxmark3.h"\r
+#include "../include/proxmark3.h"\r
 #include "apps.h"\r
 #include "util.h"\r
 #include "string.h"\r
 \r
-#include "iso14443crc.h"\r
+#include "../common/iso14443crc.h"\r
 #include "iso14443a.h"\r
 #include "crapto1.h"\r
 #include "mifareutil.h"\r
-#include "common.h"\r
+#include "../include/common.h"\r
 \r
 #define SNF_INIT                               0\r
 #define SNF_NO_FIELD           1\r
index 8ef364c259f0d16216834a87dac9bef073be1e92..c9ff8c6487c2da866efe84e0d87658c304c431d0 100644 (file)
@@ -69,7 +69,7 @@ uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) {
 int mifare_sendcmd(uint8_t cmd, uint8_t* data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing)\r
 {\r
        uint8_t dcmd[data_size+3];\r
-       dcmd[0] = cmd;\r
+    dcmd[0] = cmd;\r
        memcpy(dcmd+1,data,data_size);\r
        AppendCrc14443a(dcmd, data_size+1);\r
        ReaderTransmit(dcmd, sizeof(dcmd), timing);\r
@@ -78,7 +78,7 @@ int mifare_sendcmd(uint8_t cmd, uint8_t* data, uint8_t data_size, uint8_t* answe
                if (MF_DBGLEVEL >= MF_DBG_ERROR)   Dbprintf("%02X Cmd failed. Card timeout.", cmd);\r
                        len = ReaderReceive(answer,answer_parity);\r
                //return 0;\r
-       }\r
+    }\r
        return len;\r
 }\r
 \r
@@ -404,9 +404,9 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
 {\r
        // variables\r
        uint16_t len, i;        \r
-       uint32_t pos;\r
-       uint8_t par[3] = {0};           // enough for 18 Bytes to send\r
-       byte_t res;\r
+       uint32_t pos = 0;\r
+       uint8_t par[3] = {0x00};                // enough for 18 Bytes to send\r
+       byte_t res = 0;\r
        \r
        uint8_t d_block[18], d_block_enc[18];\r
        uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];\r
@@ -451,21 +451,21 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
 int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) \r
 {\r
        uint16_t len;\r
-       uint8_t par[3] = {0};  // enough for 18 parity bits\r
+    uint8_t par[3] = {0};  // enough for 18 parity bits\r
        uint8_t d_block[18] = {0x00};\r
        uint8_t receivedAnswer[MAX_FRAME_SIZE];\r
        uint8_t receivedAnswerPar[MAX_PARITY_SIZE];\r
 \r
-       len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL);\r
+    len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL);\r
 \r
-       if ((len != 1) || (receivedAnswer[0] != 0x0A)) {   //  0x0a - ACK\r
+    if ((len != 1) || (receivedAnswer[0] != 0x0A)) {   //  0x0a - ACK\r
                if (MF_DBGLEVEL >= MF_DBG_ERROR)\r
                        Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]);\r
-               return 1;\r
-       }\r
+        return 1;\r
+    }\r
 \r
        memcpy(d_block, blockData, 16);\r
-       AppendCrc14443a(d_block, 16);\r
+    AppendCrc14443a(d_block, 16);\r
 \r
        ReaderTransmitPar(d_block, sizeof(d_block), par, NULL);\r
 \r
@@ -474,32 +474,32 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData)
        if ((len != 1) || (receivedAnswer[0] != 0x0A)) {   //  0x0a - ACK\r
                if (MF_DBGLEVEL >= MF_DBG_ERROR)\r
                        Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len);\r
-               return 2;\r
+        return 2;\r
        }\r
-       return 0;\r
+    return 0;\r
 }\r
 */\r
 \r
 int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData)\r
 {\r
-       uint16_t len;\r
+    uint16_t len;\r
        uint8_t d_block[5] = {0x00};\r
        uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];\r
        uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];\r
 \r
-       // command MIFARE_CLASSIC_WRITEBLOCK\r
+    // command MIFARE_CLASSIC_WRITEBLOCK\r
        d_block[0]= blockNo;\r
        memcpy(d_block+1,blockData,4);\r
        //AppendCrc14443a(d_block, 6);\r
 \r
        len = mifare_sendcmd(0xA2, d_block, sizeof(d_block), receivedAnswer, receivedAnswerPar, NULL);\r
 \r
-       if (receivedAnswer[0] != 0x0A) {   //  0x0a - ACK\r
+    if (receivedAnswer[0] != 0x0A) {   //  0x0a - ACK\r
                if (MF_DBGLEVEL >= MF_DBG_ERROR)\r
                        Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0],len);\r
-               return 1;\r
-       }\r
-       return 0;\r
+        return 1;\r
+    }\r
+    return 0;\r
 }\r
 \r
 int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) \r
@@ -713,8 +713,8 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){
        data[0] = 0xAF;\r
        memcpy(data+1,key,16);\r
        \r
-       uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];\r
-       uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];\r
+       uint8_t receivedAnswer[MAX_FRAME_SIZE];\r
+       uint8_t receivedAnswerPar[MAX_PARITY_SIZE];\r
        \r
        len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar ,NULL);\r
        \r
index 85a34ef62104fa2445503eac3517436d43fa8438..679b68d694334aeb01edd7be039b24ea718f3740 100644 (file)
@@ -52,13 +52,13 @@ extern int MF_DBGLEVEL;
 \r
 #define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF();\r
 \r
-//functions\r
+//functions
 int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);\r
-int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);\r
-\r
+int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
+
 // mifare classic\r
 int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);\r
-int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing);\r
+int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing);
 int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);\r
 int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); \r
 int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);\r
@@ -67,18 +67,18 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
 int mifare_ul_ev1_auth(uint8_t *key, uint8_t *pack);\r
 int mifare_ultra_auth(uint8_t *key);\r
 int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData);\r
-//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);\r
-int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData);\r
-int mifare_ultra_halt();\r
+//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);
+int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData);
+int mifare_ultra_halt();
 \r
 // desfire\r
 int mifare_sendcmd_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);\r
 int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing);\r
 int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData);\r
 int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData);\r
-\r
-// crypto functions\r
-void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len);\r
+
+// crypto functions
+void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len);
 void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par);\r
 uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data);\r
 \r
@@ -93,7 +93,7 @@ void emlGetMem(uint8_t *data, int blockNum, int blocksCount);
 void emlGetMemBt(uint8_t *data, int bytePtr, int byteCount);\r
 uint64_t emlGetKey(int sectorNum, int keyType);\r
 int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum);\r
-int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum);\r
-int emlCheckValBl(int blockNum);\r
-\r
-#endif\r
+int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum);
+int emlCheckValBl(int blockNum);
+
+#endif
index c2c81a9da1594ce4bb1205ac0e89dae9f954b085..7f4aa17811290496b314434b1e54b5bc082b6fb6 100644 (file)
@@ -217,7 +217,7 @@ static void flash_mode(int externally_entered)
 
                if(!externally_entered && !BUTTON_PRESS()) {
                        /* Perform a reset to leave flash mode */
-      usb_disable();
+               usb_disable();
                        LED_B_ON();
                        AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
                        for(;;);
index d7126da60efd9e3670a310b30816f5515bcf3d48..2a4dfd64d6c303073450bf8608397ebbe8adbc7b 100644 (file)
@@ -12,9 +12,9 @@ CXX=g++
 VPATH = ../common
 OBJDIR = obj
 
-LDLIBS = -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lm
+LDLIBS =  -L/mingw/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lm -lreadline -lpthread -lgdi32
 LDFLAGS = $(COMMON_FLAGS)
-CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
+CFLAGS = -std=c99 -I. -I../include -I../common -I/mingw/include -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
 LUAPLATFORM = generic
 
 ifneq (,$(findstring MINGW,$(platform)))
@@ -42,6 +42,15 @@ else
     LUAPLATFORM = linux
 endif
 
+# QT version,  4 or 5
+qtplatform = $(shell $(MOC) -v)
+ifneq (, $(findstring moc 5,$(qtplatform)))
+   CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -I$(QTDIR)/include/QtWidgets  -I/mingw/include
+   QTLDLIBS = -L$(QTDIR)/lib  -lQt5Core -lQt5Gui -lQt5Widgets 
+else
+   CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
+   QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
+endif
 
 ifneq ($(QTLDLIBS),)
     QTGUI = $(OBJDIR)/proxgui.o $(OBJDIR)/proxguiqt.o $(OBJDIR)/proxguiqt.moc.o
@@ -85,6 +94,8 @@ CMDSRCS =     nonce2key/crapto1.c\
                        cmdhficlass.c \
                        cmdhfmf.c \
             cmdhfmfu.c \
+                       cmdhfmfdes.c \
+                       cmdhftopaz.c \
                        cmdhw.c \
                        cmdlf.c \
                        cmdlfio.c \
@@ -103,7 +114,13 @@ CMDSRCS =  nonce2key/crapto1.c\
                        aes.c\
                        protocols.c\
                        sha1.c\
-
+                       cmdcrc.c\
+                       reveng/reveng.c\
+                       reveng/cli.c\
+                       reveng/bmpbit.c\
+                       reveng/model.c\
+                       reveng/poly.c\
+                       reveng/getopt.c\
 
 COREOBJS = $(CORESRCS:%.c=$(OBJDIR)/%.o)
 CMDOBJS = $(CMDSRCS:%.c=$(OBJDIR)/%.o)
@@ -146,6 +163,17 @@ clean:
 tarbin: $(BINS)
        $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%)
 
+# must be run as root
+install_kext: Info.plist
+       mkdir -p /System/Library/Extensions/Proxmark3.kext/Contents
+       cp Info.plist /System/Library/Extensions/Proxmark3.kext/Contents
+       chown -R root:wheel /System/Library/Extensions/Proxmark3.kext
+       chmod 755 /System/Library/Extensions/Proxmark3.kext /System/Library/Extensions/Proxmark3.kext/Contents
+       chmod 644 /System/Library/Extensions/Proxmark3.kext/Contents/Info.plist
+       rm -rf /System/Library/Caches/com.apple.kext.caches
+       touch /System/Library/Extensions
+       @echo "*** You may need to reboot for the kext to take effect."
+
 lua_build:
        @echo Compiling liblua, using platform $(LUAPLATFORM)
        cd ../liblua && make $(LUAPLATFORM)
diff --git a/client/cmdcrc.c b/client/cmdcrc.c
new file mode 100644 (file)
index 0000000..666b4a8
--- /dev/null
@@ -0,0 +1,473 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2015 iceman <iceman at iuse.se>
+//
+// 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.
+//-----------------------------------------------------------------------------
+// CRC Calculations from the software reveng commands
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#ifdef _WIN32
+#  include <io.h>
+#  include <fcntl.h>
+#  ifndef STDIN_FILENO
+#    define STDIN_FILENO 0
+#  endif /* STDIN_FILENO */
+#endif /* _WIN32 */
+
+#include <stdio.h>
+#include <string.h>
+//#include <stdlib.h>
+//#include <ctype.h>
+#include "cmdmain.h"
+#include "cmdcrc.h"
+#include "reveng/reveng.h"
+#include "ui.h"
+#include "util.h"
+
+#define MAX_ARGS 20
+
+int uerr(char *msg){
+       PrintAndLog("%s",msg);
+       return 0;
+}
+
+int split(char *str, char *arr[MAX_ARGS]){
+    int beginIndex = 0;
+    int endIndex;
+    int maxWords = MAX_ARGS;
+    int wordCnt = 0;
+
+    while(1){
+        while(isspace(str[beginIndex])){
+            ++beginIndex;
+        }
+        if(str[beginIndex] == '\0')
+            break;
+        endIndex = beginIndex;
+        while (str[endIndex] && !isspace(str[endIndex])){
+            ++endIndex;
+        }
+        int len = endIndex - beginIndex;
+        char *tmp = calloc(len + 1, sizeof(char));
+        memcpy(tmp, &str[beginIndex], len);
+        arr[wordCnt++] = tmp;
+        //PrintAndLog("cnt: %d, %s",wordCnt-1, arr[wordCnt-1]);
+        beginIndex = endIndex;
+        if (wordCnt == maxWords)
+            break;
+    }
+    return wordCnt;
+}
+
+int CmdCrc(const char *Cmd)
+{
+       char name[] = {"reveng "};
+       char Cmd2[50 + 7];
+       memcpy(Cmd2, name, 7);
+       memcpy(Cmd2 + 7, Cmd, 50);
+       char *argv[MAX_ARGS];
+       int argc = split(Cmd2, argv);
+
+       if (argc == 3 && memcmp(argv[1],"-g",2)==0) {
+               CmdrevengSearch(argv[2]);
+       } else {
+       reveng_main(argc, argv);
+       }
+       //PrintAndLog("DEBUG argc: %d, %s %s Cmd: %s",argc, argv[0], Cmd2, Cmd);
+       for(int i = 0; i < argc; ++i){
+               free(argv[i]);
+       }
+
+  return 0; 
+}
+
+//returns array of model names and the count of models returning
+//  as well as a width array for the width of each model
+int GetModels(char *Models[], int *count, uint8_t *width){
+       /* default values */
+       static model_t model = {
+               PZERO,          /* no CRC polynomial, user must specify */
+               PZERO,          /* Init = 0 */
+               P_BE,           /* RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h */
+               PZERO,          /* XorOut = 0 */
+               PZERO,          /* check value unused */
+               NULL            /* no model name */
+       };
+
+       int ibperhx = 8;//, obperhx = 8;
+       int rflags = 0, uflags = 0; /* search and UI flags */
+       poly_t apoly, crc, qpoly = PZERO, *apolys = NULL, *pptr = NULL, *qptr = NULL;
+       model_t pset = model, *candmods, *mptr;
+
+       /* stdin must be binary */
+       #ifdef _WIN32
+               _setmode(STDIN_FILENO, _O_BINARY);
+       #endif /* _WIN32 */
+
+       SETBMP();
+       
+       int args = 0, psets, pass;
+       int Cnt = 0;
+       if (width[0] == 0) { //reveng -D
+               *count = mcount();
+               if(!*count)
+                       return uerr("no preset models available");
+
+               for(int mode = 0; mode < *count; ++mode) {
+                       mbynum(&model, mode);
+                       mcanon(&model);
+                       size_t size = (model.name && *model.name) ? strlen(model.name) : 6;
+                       char *tmp = calloc(size+1, sizeof(char));
+                       if (tmp==NULL)
+                               return uerr("out of memory?");
+
+                       memcpy(tmp, model.name, size);
+                       Models[mode] = tmp;
+                       width[mode] = plen(model.spoly);
+               }
+               mfree(&model);
+       } else { //reveng -s
+
+                       if(~model.flags & P_MULXN)
+                               return uerr("cannot search for non-Williams compliant models");
+
+               praloc(&model.spoly, (unsigned long)width[0]);
+               praloc(&model.init, (unsigned long)width[0]);
+               praloc(&model.xorout, (unsigned long)width[0]);
+                       if(!plen(model.spoly))
+                       palloc(&model.spoly, (unsigned long)width[0]);
+                       else
+                       width[0] = (uint8_t)plen(model.spoly);
+
+                       /* special case if qpoly is zero, search to end of range */
+                       if(!ptst(qpoly))
+                               rflags &= ~R_HAVEQ;
+
+                       /* if endianness not specified, try
+                        * little-endian then big-endian.
+                        * NB: crossed-endian algorithms will not be
+                        * searched.
+                        */
+                       /* scan against preset models */
+                       if(~uflags & C_FORCE) {
+                               pass = 0;
+                               Cnt = 0;
+                               do {
+                                       psets = mcount();
+
+                                       while(psets) {
+                                               mbynum(&pset, --psets);
+                                               
+                                               /* skip if different width, or refin or refout don't match */
+                                       if(plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT))
+                                                       continue;
+                                               /* skip if the preset doesn't match specified parameters */
+                                               if(rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly))
+                                                       continue;
+                                               if(rflags & R_HAVEI && psncmp(&model.init, &pset.init))
+                                                       continue;
+                                               if(rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
+                                                       continue;
+                               
+                                       //for additional args (not used yet, maybe future?)
+                                               apoly = pclone(pset.xorout);
+                                               if(pset.flags & P_REFOUT)
+                                                       prev(&apoly);
+                                       
+                                               for(qptr = apolys; qptr < pptr; ++qptr) {
+                                                       crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
+                                                       if(ptst(crc)) {
+                                                               pfree(&crc);
+                                                               break;
+                                                       } else
+                                                               pfree(&crc);
+                                               }
+                                               pfree(&apoly);
+                                               if(qptr == pptr) {
+
+                                                       /* the selected model solved all arguments */
+
+                                                       mcanon(&pset);
+                                                       
+                                                       size_t size = (pset.name && *pset.name) ? strlen(pset.name) : 6;
+                                                       //PrintAndLog("Size: %d, %s, count: %d",size,pset.name, Cnt);
+                                                       char *tmp = calloc(size+1, sizeof(char));
+                                                       if (tmp == NULL){
+                                                               PrintAndLog("out of memory?");
+                                                               return 0;
+                                                       }
+                                               width[Cnt] = width[0];
+                                                       memcpy(tmp, pset.name, size);
+                                                       Models[Cnt++] = tmp;
+                                                       *count = Cnt;
+                                                       uflags |= C_RESULT;
+                                               }
+                                       }
+                                       mfree(&pset);
+
+                                       /* toggle refIn/refOut and reflect arguments */
+                                       if(~rflags & R_HAVERI) {
+                                               model.flags ^= P_REFIN | P_REFOUT;
+                                               for(qptr = apolys; qptr < pptr; ++qptr)
+                                                       prevch(qptr, ibperhx);
+                                       }
+                               } while(~rflags & R_HAVERI && ++pass < 2);
+                       }
+               //got everything now free the memory...
+
+                       if(uflags & C_RESULT) {
+                               for(qptr = apolys; qptr < pptr; ++qptr)
+                                       pfree(qptr);
+                       }
+                       if(!(model.flags & P_REFIN) != !(model.flags & P_REFOUT))
+                               return uerr("cannot search for crossed-endian models");
+
+                       pass = 0;
+                       do {
+                               mptr = candmods = reveng(&model, qpoly, rflags, args, apolys);
+                               if(mptr && plen(mptr->spoly))
+                                       uflags |= C_RESULT;
+                               while(mptr && plen(mptr->spoly)) {
+                                       mfree(mptr++);
+                               }
+                               free(candmods);
+                               if(~rflags & R_HAVERI) {
+                                       model.flags ^= P_REFIN | P_REFOUT;
+                                       for(qptr = apolys; qptr < pptr; ++qptr)
+                                               prevch(qptr, ibperhx);
+                               }
+                       } while(~rflags & R_HAVERI && ++pass < 2);
+                       for(qptr = apolys; qptr < pptr; ++qptr)
+                               pfree(qptr);
+                       free(apolys);
+                       if(~uflags & C_RESULT)
+                               return uerr("no models found");
+                       mfree(&model);
+
+       }
+       return 1;
+}
+
+//-c || -v
+//inModel = valid model name string - CRC-8
+//inHexStr = input hex string to calculate crc on
+//reverse = reverse calc option if true
+//endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified
+//          l = little endian input and output, L = little endian output only, t = left justified}
+//result = calculated crc hex string
+int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result){
+       /* default values */
+       static model_t model = {
+               PZERO,          // no CRC polynomial, user must specify
+               PZERO,          // Init = 0
+               P_BE,             // RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h
+               PZERO,          // XorOut = 0
+               PZERO,          // check value unused 
+               NULL              // no model name 
+       };
+       int ibperhx = 8, obperhx = 8;
+       int rflags = 0; // search flags 
+       int c;
+       poly_t apoly, crc;
+
+       char *string;
+
+       // stdin must be binary
+       #ifdef _WIN32
+               _setmode(STDIN_FILENO, _O_BINARY);
+       #endif /* _WIN32 */
+
+       SETBMP();
+       //set model
+       if(!(c = mbynam(&model, inModel))) {
+               PrintAndLog("error: preset model '%s' not found.  Use reveng -D to list presets.", inModel);
+               return 0;
+       }
+       if(c < 0)
+               return uerr("no preset models available");
+
+       rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX;
+       
+       //set flags
+       switch (endian) {
+               case 'b': /* b  big-endian (RefIn = false, RefOut = false ) */
+                       model.flags &= ~P_REFIN;
+                       rflags |= R_HAVERI;
+                       /* fall through: */
+               case 'B': /* B  big-endian output (RefOut = false) */
+                       model.flags &= ~P_REFOUT;
+                       rflags |= R_HAVERO;
+                       mnovel(&model);
+                       /* fall through: */
+               case 'r': /* r  right-justified */
+                       model.flags |= P_RTJUST;
+                       break;
+               case 'l': /* l  little-endian input and output */
+                       model.flags |= P_REFIN;
+                       rflags |= R_HAVERI;
+                       /* fall through: */
+               case 'L': /* L  little-endian output */
+                       model.flags |= P_REFOUT;
+                       rflags |= R_HAVERO;
+                       mnovel(&model);
+                       /* fall through: */
+               case 't': /* t  left-justified */
+                       model.flags &= ~P_RTJUST;
+                       break;
+       }
+
+       mcanon(&model);
+
+       if (reverse) {
+               // v  calculate reversed CRC
+               /* Distinct from the -V switch as this causes
+                * the arguments and output to be reversed as well.
+                */
+               // reciprocate Poly
+               prcp(&model.spoly);
+
+               /* mrev() does:
+                *   if(refout) prev(init); else prev(xorout);
+                * but here the entire argument polynomial is
+                * reflected, not just the characters, so RefIn
+                * and RefOut are not inverted as with -V.
+                * Consequently Init is the mirror image of the
+                * one resulting from -V, and so we have:
+                */
+               if(~model.flags & P_REFOUT) {
+                       prev(&model.init);
+                       prev(&model.xorout);
+               }
+
+               // swap init and xorout
+               apoly = model.init;
+               model.init = model.xorout;
+               model.xorout = apoly;
+       }
+       // c  calculate CRC
+
+       /* in the Williams model, xorout is applied after the refout stage.
+        * as refout is part of ptostr(), we reverse xorout here.
+        */
+       if(model.flags & P_REFOUT)
+               prev(&model.xorout);
+
+       apoly = strtop(inHexStr, model.flags, ibperhx);
+
+       if(reverse)
+               prev(&apoly);
+
+       crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags);
+
+       if(reverse)
+               prev(&crc);
+
+       string = ptostr(crc, model.flags, obperhx);
+       for (int i = 0; i < 50; i++){
+               result[i] = string[i];
+               if (result[i]==0) break;
+       }
+       free(string);
+       pfree(&crc);
+       pfree(&apoly);
+       return 1;
+}
+//returns a calloced string (needs to be freed)
+char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize){
+       char *tmp = calloc(len+1, sizeof(char));
+       for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){
+               for (size_t i = 0; i < blockSize; i+=2){
+                       tmp[i+(blockSize*block)] = inStr[(blockSize-1-i-1)+(blockSize*block)];
+                       tmp[i+(blockSize*block)+1] = inStr[(blockSize-1-i)+(blockSize*block)];
+               }
+       }
+       return tmp;
+}
+
+// takes hex string in and searches for a matching result (hex string must include checksum)
+int CmdrevengSearch(const char *Cmd){
+       char inHexStr[50] = {0x00};
+       int dataLen = param_getstr(Cmd, 0, inHexStr);
+       if (dataLen < 4) return 0;
+
+       char *Models[80];
+       int count = 0;
+       uint8_t width[80];
+       width[0] = 0;
+       uint8_t crcChars = 0;
+       char result[30];
+       char revResult[30];
+       int ans = GetModels(Models, &count, width);
+       bool found = false;
+       if (!ans) return 0;
+       
+       // try each model and get result
+       for (int i = 0; i < count; i++){
+               /*if (found) {
+                       free(Models[i]);
+                       continue;
+               }*/
+               // round up to # of characters in this model's crc
+               crcChars = ((width[i]+7)/8)*2; 
+               // can't test a model that has more crc digits than our data
+               if (crcChars >= dataLen) 
+                       continue;
+               memset(result, 0, 30);
+               char *inCRC = calloc(crcChars+1, sizeof(char));
+               memcpy(inCRC, inHexStr+(dataLen-crcChars), crcChars);
+
+               char *outHex = calloc(dataLen-crcChars+1, sizeof(char));
+               memcpy(outHex, inHexStr, dataLen-crcChars);
+
+               //PrintAndLog("DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex);
+               ans = RunModel(Models[i], outHex, false, 0, result);
+               if (ans) {
+                       //test for match
+                       if (memcmp(result, inCRC, crcChars)==0){
+                               PrintAndLog("\nFound a possible match!\nModel: %s\nValue: %s\n",Models[i], result);
+                               //optional - stop searching if found...
+                               found = true;
+                       } else {
+                               if (crcChars > 2){
+                                       char *swapEndian = SwapEndianStr(result, crcChars, crcChars);
+                                       if (memcmp(swapEndian, inCRC, crcChars)==0){
+                                               PrintAndLog("\nFound a possible match!\nModel: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian);
+                                               //optional - stop searching if found...
+                                               found = true;
+                                       }
+                                       free(swapEndian);
+                               }
+                       }
+               }
+               
+               //if (!found){
+                       ans = RunModel(Models[i], outHex, true, 0, revResult);
+                       if (ans) {
+                               //test for match
+                               if (memcmp(revResult, inCRC, crcChars)==0){
+                                       PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue: %s\n",Models[i], revResult);
+                                       //optional - stop searching if found...
+                                       found = true;
+                               } else {
+                                       if (crcChars > 2){
+                                               char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars);
+                                               if (memcmp(swapEndian, inCRC, crcChars)==0){
+                                                       PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian);
+                                                       //optional - stop searching if found...
+                                                       found = true;
+                                               }
+                                               free(swapEndian);
+                                       }
+                               }
+                       }
+               //}
+               free(inCRC);
+               free(outHex);
+               free(Models[i]);
+       }
+       if (!found) PrintAndLog("\nNo matches found\n");
+       return 1;
+}
diff --git a/client/cmdcrc.h b/client/cmdcrc.h
new file mode 100644 (file)
index 0000000..d1dd1c1
--- /dev/null
@@ -0,0 +1,19 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2015 iceman <iceman at iuse.se>
+//
+// 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.
+//-----------------------------------------------------------------------------
+// CRC Calculations from the software reveng commands
+//-----------------------------------------------------------------------------
+
+#ifndef CMDCRC_H__
+#define CMDCRC_H__
+
+int CmdCrc(const char *Cmd);
+
+int CmdrevengSearch(const char *Cmd);
+int GetModels(char *Models[], int *count, uint8_t *width);
+int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result);
+#endif
index 309044e10d48cefe327f028d83c4d13bca9e170c..ebab14396f28f456ef128dafeb3b0ffa06b93552 100644 (file)
@@ -392,7 +392,7 @@ int Cmdmandecoderaw(const char *Cmd)
        int errCnt=0;
        size_t size=0;
        int invert=0;
-       size_t maxErr = 20;
+       int maxErr = 20;
        char cmdp = param_getchar(Cmd, 0);
        if (strlen(Cmd) > 5 || cmdp == 'h' || cmdp == 'H') {
                PrintAndLog("Usage:  data manrawdecode [invert] [maxErr]");
@@ -500,10 +500,9 @@ int ASKbiphaseDemod(const char *Cmd, bool verbose)
        //ask raw demod GraphBuffer first
        int offset=0, clk=0, invert=0, maxErr=0;
        sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr);
-
-       uint8_t BitStream[MAX_DEMOD_BUF_LEN];     
+       
+       uint8_t BitStream[MAX_DEMOD_BUF_LEN];
        size_t size = getFromGraphBuf(BitStream);         
-       //invert here inverts the ask raw demoded bits which has no effect on the demod, but we need the pointer
        int errCnt = askdemod(BitStream, &size, &clk, &invert, maxErr, 0, 0);  
        if ( errCnt < 0 || errCnt > maxErr ) {   
                if (g_debugMode) PrintAndLog("DEBUG: no data or error found %d, clock: %d", errCnt, clk);  
@@ -1462,6 +1461,17 @@ int CmdFSKdemodPyramid(const char *Cmd)
 // NATIONAL CODE, ICAR database
 // COUNTRY CODE (ISO3166) or http://cms.abvma.ca/uploads/ManufacturersISOsandCountryCodes.pdf
 // FLAG (animal/non-animal)
+/*
+38 IDbits   
+10 country code 
+1 extra app bit
+14 reserved bits
+1 animal bit
+16 ccitt CRC chksum over 64bit ID CODE.
+24 appli bits.
+
+-- sample: 985121004515220  [ 37FF65B88EF94 ]
+*/
 int CmdFDXBdemodBI(const char *Cmd){
 
        int invert = 1;
@@ -1482,13 +1492,13 @@ int CmdFDXBdemodBI(const char *Cmd){
                if (g_debugMode) PrintAndLog("Error BiphaseRawDecode: %d", errCnt);
                return 0;
        } 
-
+       
        int preambleIndex = FDXBdemodBI(BitStream, &size);
        if (preambleIndex < 0){
                if (g_debugMode) PrintAndLog("Error FDXBDemod , no startmarker found :: %d",preambleIndex);
                return 0;
        }
-
+       
        setDemodBuf(BitStream, 128, preambleIndex);
 
        // remove but don't verify parity. (pType = 2)
@@ -1947,7 +1957,7 @@ typedef struct {
        uint8_t * buffer;
        uint32_t numbits;
        uint32_t position;
-}BitstreamOut;
+} BitstreamOut;
 
 bool _headBit( BitstreamOut *stream)
 {
index 16f7bb0f39f661c180723bd0c52bd1306407f8bd..614dcdc4460e98bf7ed5b90de015970cfe6c10ea 100644 (file)
@@ -23,6 +23,8 @@
 #include "cmdhficlass.h"
 #include "cmdhfmf.h"
 #include "cmdhfmfu.h"
+#include "cmdhfmfdes.h"
+#include "cmdhftopaz.h"
 #include "protocols.h"
 
 static int CmdHelp(const char *Cmd);
@@ -34,7 +36,6 @@ int CmdHFTune(const char *Cmd)
   return 0;
 }
 
-
 void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
 {
        switch(cmd[0])
@@ -83,45 +84,46 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
        case MIFARE_MAGICWUPC1:                 snprintf(exp,size,"MAGIC WUPC1"); break;
        case MIFARE_MAGICWUPC2:                 snprintf(exp,size,"MAGIC WUPC2"); break;
        case MIFARE_MAGICWIPEC:                 snprintf(exp,size,"MAGIC WIPEC"); break;
-       case MIFARE_ULC_AUTH_1:         snprintf(exp,size,"AUTH "); break;
-       case MIFARE_ULC_AUTH_2:         snprintf(exp,size,"AUTH_ANSW"); break;
-       case MIFARE_ULEV1_AUTH:
+       case MIFARE_ULC_AUTH_1 :                snprintf(exp,size,"AUTH "); break;
+       case MIFARE_ULC_AUTH_2 :                snprintf(exp,size,"AUTH_ANSW"); break;
+       case MIFARE_ULEV1_AUTH :        
                if ( cmdsize == 7 )
                        snprintf(exp,size,"PWD-AUTH KEY: 0x%02x%02x%02x%02x", cmd[1], cmd[2], cmd[3], cmd[4] );
                else
                        snprintf(exp,size,"PWD-AUTH");
                break;
-       case MIFARE_ULEV1_FASTREAD:{
+
+       case MIFARE_ULEV1_FASTREAD : {
                if ( cmdsize >=3 && cmd[2] <= 0xE6)
                        snprintf(exp,size,"READ RANGE (%d-%d)",cmd[1],cmd[2]); 
                else
                        snprintf(exp,size,"?");
                break;
        }
-       case MIFARE_ULC_WRITE:{
+       case MIFARE_ULC_WRITE : {
                if ( cmd[1] < 0x21 )
                        snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); 
                else
                        snprintf(exp,size,"?");
                break;
        }
-       case MIFARE_ULEV1_READ_CNT:{
+       case MIFARE_ULEV1_READ_CNT :{
                if ( cmd[1] < 5 )
                        snprintf(exp,size,"READ CNT(%d)",cmd[1]);
                else
                        snprintf(exp,size,"?");
                break;
        }
-       case MIFARE_ULEV1_INCR_CNT:{
+       case MIFARE_ULEV1_INCR_CNT : {
                if ( cmd[1] < 5 )
                        snprintf(exp,size,"INCR(%d)",cmd[1]);
                else
                        snprintf(exp,size,"?");
                break;
        }
-       case MIFARE_ULEV1_READSIG             snprintf(exp,size,"READ_SIG"); break;
-       case MIFARE_ULEV1_CHECKTEAR   snprintf(exp,size,"CHK_TEARING(%d)",cmd[1]); break;
-       case MIFARE_ULEV1_VCSL:         snprintf(exp,size,"VCSL"); break;
+       case MIFARE_ULEV1_READSIG :             snprintf(exp,size,"READ_SIG"); break;
+       case MIFARE_ULEV1_CHECKTEAR :   snprintf(exp,size,"CHK_TEARING(%d)",cmd[1]); break;
+       case MIFARE_ULEV1_VCSL :                snprintf(exp,size,"VCSL"); break;
        default:                                                snprintf(exp,size,"?"); break;
        }
        return;
@@ -187,6 +189,26 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
        }
 }
 
+
+void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
+{
+       switch(cmd[0]) {
+               case TOPAZ_REQA                                         :snprintf(exp, size, "REQA");break;
+               case TOPAZ_WUPA                                         :snprintf(exp, size, "WUPA");break;
+               case TOPAZ_RID                                          :snprintf(exp, size, "RID");break;
+               case TOPAZ_RALL                                         :snprintf(exp, size, "RALL");break;
+               case TOPAZ_READ                                         :snprintf(exp, size, "READ");break;
+               case TOPAZ_WRITE_E                                      :snprintf(exp, size, "WRITE-E");break;
+               case TOPAZ_WRITE_NE                                     :snprintf(exp, size, "WRITE-NE");break;
+               case TOPAZ_RSEG                                         :snprintf(exp, size, "RSEG");break;
+               case TOPAZ_READ8                                        :snprintf(exp, size, "READ8");break;
+               case TOPAZ_WRITE_E8                                     :snprintf(exp, size, "WRITE-E8");break;
+               case TOPAZ_WRITE_NE8                            :snprintf(exp, size, "WRITE-NE8");break;
+               default:                            snprintf(exp,size,"?"); break;
+       }
+}
+
+
 /**
 06 00 = INITIATE
 0E xx = SELECT ID (xx = Chip-ID)
@@ -218,7 +240,34 @@ void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
 }
 
 /**
- * @brief iso14443B_CRC_Ok Checks CRC in command or response
+ * @brief iso14443A_CRC_check Checks CRC in command or response
+ * @param isResponse
+ * @param data
+ * @param len
+ * @return  0 : CRC-command, CRC not ok
+ *          1 : CRC-command, CRC ok
+ *          2 : Not crc-command
+ */
+
+uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
+{
+       uint8_t b1,b2;
+
+       if(len <= 2) return 2;
+
+       if(isResponse & (len < 6)) return 2;
+       
+       ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2);
+       if (b1 != data[len-2] || b2 != data[len-1]) {
+               return 0;
+       } else {
+               return 1;
+       }
+}
+
+
+/**
+ * @brief iso14443B_CRC_check Checks CRC in command or response
  * @param isResponse
  * @param data
  * @param len
@@ -301,11 +350,66 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
        }
 }
 
-uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles)
+
+bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen)
 {
-       bool isResponse;
-       uint16_t duration, data_len, parity_len;
+       return(tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen);
+}
+
+
+bool next_record_is_response(uint16_t tracepos, uint8_t *trace)
+{
+       uint16_t next_records_datalen = *((uint16_t *)(trace + tracepos + sizeof(uint32_t) + sizeof(uint16_t)));
+       
+       return(next_records_datalen & 0x8000);
+}
+
+
+bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len)
+{
+
+#define MAX_TOPAZ_READER_CMD_LEN       16
+
+       uint32_t last_timestamp = timestamp + *duration;
+
+       if ((*data_len != 1) || (frame[0] == TOPAZ_WUPA) || (frame[0] == TOPAZ_REQA)) return false;
+
+       memcpy(topaz_reader_command, frame, *data_len);
 
+       while (!is_last_record(*tracepos, trace, traceLen) && !next_record_is_response(*tracepos, trace)) {
+               uint32_t next_timestamp = *((uint32_t *)(trace + *tracepos));
+               *tracepos += sizeof(uint32_t);
+               uint16_t next_duration = *((uint16_t *)(trace + *tracepos));
+               *tracepos += sizeof(uint16_t);
+               uint16_t next_data_len = *((uint16_t *)(trace + *tracepos)) & 0x7FFF;
+               *tracepos += sizeof(uint16_t);
+               uint8_t *next_frame = (trace + *tracepos);
+               *tracepos += next_data_len;
+               if ((next_data_len == 1) && (*data_len + next_data_len <= MAX_TOPAZ_READER_CMD_LEN)) {
+                       memcpy(topaz_reader_command + *data_len, next_frame, next_data_len);
+                       *data_len += next_data_len;
+                       last_timestamp = next_timestamp + next_duration;
+               } else {
+                       // rewind and exit
+                       *tracepos = *tracepos - next_data_len - sizeof(uint16_t) - sizeof(uint16_t) - sizeof(uint32_t);
+                       break;
+               }
+               uint16_t next_parity_len = (next_data_len-1)/8 + 1;
+               *tracepos += next_parity_len;
+       }
+
+       *duration = last_timestamp - timestamp;
+       
+       return true;
+}
+
+
+uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes)
+{
+       bool isResponse;
+       uint16_t data_len, parity_len;
+       uint32_t duration;
+       uint8_t topaz_reader_command[9];
        uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp;
        char explanation[30] = {0};
 
@@ -336,29 +440,31 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
        uint8_t *parityBytes = trace + tracepos;
        tracepos += parity_len;
 
+       if (protocol == TOPAZ && !isResponse) {
+               // topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each.
+               // merge them:
+               if (merge_topaz_reader_frames(timestamp, &duration, &tracepos, traceLen, trace, frame, topaz_reader_command, &data_len)) {
+                       frame = topaz_reader_command;
+               }
+       }
+       
        //Check the CRC status
        uint8_t crcStatus = 2;
 
        if (data_len > 2) {
-               uint8_t b1, b2;
-               if(protocol == ICLASS)
-               {
-                       crcStatus = iclass_CRC_check(isResponse, frame, data_len);
-
-               }else if (protocol == ISO_14443B)
-               {
-                       crcStatus = iso14443B_CRC_check(isResponse, frame, data_len);
-               }
-               else if (protocol == ISO_14443A){//Iso 14443a
-
-                       ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2);
-
-                       if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) {
-                               if(!(isResponse & (data_len < 6)))
-                               {
-                                               crcStatus = 0;
-                               }
-                       }
+               switch (protocol) {
+                       case ICLASS:
+                               crcStatus = iclass_CRC_check(isResponse, frame, data_len);
+                               break;
+                       case ISO_14443B:
+                       case TOPAZ:
+                               crcStatus = iso14443B_CRC_check(isResponse, frame, data_len);
+                               break;
+                       case ISO_14443A:
+                               crcStatus = iso14443A_CRC_check(isResponse, frame, data_len);
+                               break;
+                       default: 
+                               break;
                }
        }
        //0 CRC-command, CRC not ok
@@ -366,7 +472,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
        //2 Not crc-command
 
        //--- Draw the data column
-       //char line[16][110];
        char line[16][110];
 
        for (int j = 0; j < data_len && j/16 < 16; j++) {
@@ -380,45 +485,44 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
                uint8_t parityBits = parityBytes[j>>3];
                if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
                        snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]);
-
                } else {
                        snprintf(line[j/16]+(( j % 16) * 4),110, "%02x  ", frame[j]);
                }
-
-       }
-       if(crcStatus == 1)
-       {//CRC-command
-               char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4)-1;
-               (*pos1) = '[';
-               char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4)-2;
-               (*pos2) = ']';
        }
-       if(data_len == 0)
-       {
-               if(data_len == 0){
-                       sprintf(line[0],"<empty trace - possible error>");
+
+       if (markCRCBytes) {
+               //CRC-command
+               if(crcStatus == 0 || crcStatus == 1) {
+                       char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4);
+                       (*pos1) = '[';
+                       char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4);
+                       sprintf(pos2, "%c", ']');
                }
        }
-       //--- Draw the CRC column
 
+       if(data_len == 0){
+               sprintf(line[0],"<empty trace - possible error>");
+       }
+       //--- Draw the CRC column
        char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : "    "));
 
        EndOfTransmissionTimestamp = timestamp + duration;
 
        if(!isResponse)
        {
-               if(protocol == ICLASS)
-                       annotateIclass(explanation,sizeof(explanation),frame,data_len);
-               else if (protocol == ISO_14443A)
-                       annotateIso14443a(explanation,sizeof(explanation),frame,data_len);
-               else if(protocol == ISO_14443B)
-                       annotateIso14443b(explanation,sizeof(explanation),frame,data_len);
+               switch(protocol) {
+                       case ICLASS:            annotateIclass(explanation,sizeof(explanation),frame,data_len); break;
+                       case ISO_14443A:        annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break;
+                       case ISO_14443B:        annotateIso14443b(explanation,sizeof(explanation),frame,data_len); break;
+                       case TOPAZ:                     annotateTopaz(explanation,sizeof(explanation),frame,data_len); break;
+                       default:                        break;
+               }
        }
 
        int num_lines = MIN((data_len - 1)/16 + 1, 16);
        for (int j = 0; j < num_lines ; j++) {
                if (j == 0) {
-                       PrintAndLog(" %9d | %9d | %s | %-64s| %s| %s",
+                       PrintAndLog(" %10d | %10d | %s |%-64s | %s| %s",
                                (timestamp - first_timestamp),
                                (EndOfTransmissionTimestamp - first_timestamp),
                                (isResponse ? "Tag" : "Rdr"),
@@ -426,27 +530,23 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
                                (j == num_lines-1) ? crc : "    ",
                                (j == num_lines-1) ? explanation : "");
                } else {
-                       PrintAndLog("           |           |     | %-64s| %s| %s",
+                       PrintAndLog("            |            |     |%-64s | %s| %s",
                                line[j],
-                               (j == num_lines-1)?crc:"    ",
+                               (j == num_lines-1) ? crc : "    ",
                                (j == num_lines-1) ? explanation : "");
                }
        }
 
-       if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen;
+       if (is_last_record(tracepos, trace, traceLen)) return traceLen;
        
-       bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000;
-
-       if (showWaitCycles && !isResponse && next_isResponse) {
+       if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) {
                uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
-               if (next_timestamp != 0x44444444) {
-                       PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d",
+                       PrintAndLog(" %10d | %10d | %s |fdt (Frame Delay Time): %d",
                                (EndOfTransmissionTimestamp - first_timestamp),
                                (next_timestamp - first_timestamp),
                                "   ",
                                (next_timestamp - EndOfTransmissionTimestamp));
                }
-       }
 
        return tracepos;
 }
@@ -455,34 +555,35 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
 int CmdHFList(const char *Cmd)
 {
        bool showWaitCycles = false;
+       bool markCRCBytes = false;
        char type[40] = {0};
        int tlen = param_getstr(Cmd,0,type);
-       char param = param_getchar(Cmd, 1);
+       char param1 = param_getchar(Cmd, 1);
+       char param2 = param_getchar(Cmd, 2);
        bool errors = false;
        uint8_t protocol = 0;
        //Validate params
-       if(tlen == 0)
-       {
+
+       if(tlen == 0) {
                errors = true;
        }
-       if(param == 'h' || (param !=0 && param != 'f'))
-       {
+
+       if(param1 == 'h'
+                       || (param1 != 0 && param1 != 'f' && param1 != 'c')
+                       || (param2 != 0 && param2 != 'f' && param2 != 'c')) {
                errors = true;
        }
-       if(!errors)
-       {
-               if(strcmp(type, "iclass") == 0)
-               {
+
+       if(!errors) {
+               if(strcmp(type, "iclass") == 0) {
                        protocol = ICLASS;
-               }else if(strcmp(type, "14a") == 0)
-               {
+               } else if(strcmp(type, "14a") == 0) {
                        protocol = ISO_14443A;
-               }
-               else if(strcmp(type, "14b") == 0)
-               {
+               } else if(strcmp(type, "14b") == 0)     {
                        protocol = ISO_14443B;
-               }else if(strcmp(type,"raw")== 0)
-               {
+               } else if(strcmp(type,"topaz")== 0) {
+                       protocol = TOPAZ;
+               } else if(strcmp(type,"raw")== 0) {
                        protocol = -1;//No crc, no annotations
                }else{
                        errors = true;
@@ -491,13 +592,15 @@ int CmdHFList(const char *Cmd)
 
        if (errors) {
                PrintAndLog("List protocol data in trace buffer.");
-               PrintAndLog("Usage:  hf list <protocol> [f]");
+               PrintAndLog("Usage:  hf list <protocol> [f][c]");
                PrintAndLog("    f      - show frame delay times as well");
+               PrintAndLog("    c      - mark CRC bytes");
                PrintAndLog("Supported <protocol> values:");
                PrintAndLog("    raw    - just show raw data without annotations");
                PrintAndLog("    14a    - interpret data as iso14443a communications");
                PrintAndLog("    14b    - interpret data as iso14443b communications");
                PrintAndLog("    iclass - interpret data as iclass communications");
+               PrintAndLog("    topaz  - interpret data as topaz communications");
                PrintAndLog("");
                PrintAndLog("example: hf list 14a f");
                PrintAndLog("example: hf list iclass");
@@ -505,10 +608,13 @@ int CmdHFList(const char *Cmd)
        }
 
 
-       if (param == 'f') {
+       if (param1 == 'f' || param2 == 'f') {
                showWaitCycles = true;
        }
 
+       if (param1 == 'c' || param2 == 'c') {
+               markCRCBytes = true;
+       }
 
        uint8_t *trace;
        uint16_t tracepos = 0;
@@ -537,12 +643,12 @@ int CmdHFList(const char *Cmd)
        PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)");
        PrintAndLog("iClass    - Timings are not as accurate");
        PrintAndLog("");
-       PrintAndLog("     Start |       End | Src | Data (! denotes parity error)                                   | CRC | Annotation         |");
-       PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------|-----|--------------------|");
+    PrintAndLog("      Start |        End | Src | Data (! denotes parity error)                                   | CRC | Annotation         |");
+       PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|");
 
        while(tracepos < traceLen)
        {
-               tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles);
+               tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes);
        }
 
        free(trace);
@@ -585,9 +691,11 @@ static command_t CommandTable[] =
   {"epa",         CmdHFEPA,         1, "{ German Identification Card... }"},
   {"legic",       CmdHFLegic,       0, "{ LEGIC RFIDs... }"},
   {"iclass",      CmdHFiClass,      1, "{ ICLASS RFIDs... }"},
-  {"mf",          CmdHFMF,          1, "{ MIFARE RFIDs... }"},
+  {"mf",               CmdHFMF,                1, "{ MIFARE RFIDs... }"},
   {"mfu",         CmdHFMFUltra,     1, "{ MIFARE Ultralight RFIDs... }"},
-  {"tune",        CmdHFTune,        0, "Continuously measure HF antenna tuning"},
+  {"mfdes",                    CmdHFMFDes,             1, "{ MIFARE Desfire RFIDs... }"},
+  {"topaz",                    CmdHFTopaz,             1, "{ TOPAZ (NFC Type 1) RFIDs... }"},
+  {"tune",                     CmdHFTune,      0, "Continuously measure HF antenna tuning"},
   {"list",        CmdHFList,        1, "List protocol data in trace buffer"},
   {"search",      CmdHFSearch,      1, "Search for known HF tags [preliminary]"},
        {NULL, NULL, 0, NULL}
index 026357b5a973b4c133cc2e14fa5d4b8d08737584..2eef3c9cd239671fd74ce77b36848b242705b3e2 100644 (file)
@@ -14,4 +14,5 @@
 int CmdHF(const char *Cmd);
 int CmdHFTune(const char *Cmd);
 int CmdHFList(const char *Cmd);
+int CmdHFSearch(const char *Cmd);
 #endif
index 9a761864b3fbc984ef21d839b0db886a69aeb647..8d6afadd8feb59d9863f60886ba42c4ec21fd136 100644 (file)
@@ -24,6 +24,9 @@
 #include "cmdmain.h"
 #include "mifare.h"
 #include "cmdhfmfu.h"
+#include "nonce2key/nonce2key.h"
+
+#define llx PRIx64
 
 static int CmdHelp(const char *Cmd);
 static void waitCmd(uint8_t iLen);
@@ -141,7 +144,7 @@ int CmdHF14AReader(const char *Cmd)
        iso14a_card_select_t card;
        memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
 
-       uint64_t select_status = resp.arg[0];           // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS
+       uint64_t select_status = resp.arg[0];           // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
        
        if(select_status == 0) {
                if (Cmd[0] != 's') PrintAndLog("iso14443a card select failed");
@@ -172,11 +175,7 @@ int CmdHF14AReader(const char *Cmd)
                case 0x00: 
 
                        //***************************************test****************
-                       // disconnect
-                       c.arg[0] = 0;
-                       c.arg[1] = 0;
-                       c.arg[2] = 0;
-                       SendCommand(&c);
+                       ul_switch_off_field();
                        
                        uint32_t tagT = GetHF14AMfU_Type();
                        ul_print_type(tagT, 0);
@@ -196,12 +195,7 @@ int CmdHF14AReader(const char *Cmd)
                        select_status = resp.arg[0];            // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS
                        
                        if(select_status == 0) {
-                               //PrintAndLog("iso14443a card select failed");
-                               // disconnect
-                               c.arg[0] = 0;
-                               c.arg[1] = 0;
-                               c.arg[2] = 0;
-                               SendCommand(&c);
+                               ul_switch_off_field();
                                return 0;
                        }
 
@@ -213,16 +207,16 @@ int CmdHF14AReader(const char *Cmd)
                        c.d.asBytes[0] = 0x60;
                        SendCommand(&c);
                        WaitForResponse(CMD_ACK,&resp);
-
+               
                        uint8_t version[10] = {0};
                        memcpy(version, resp.d.asBytes, resp.arg[0] < sizeof(version) ? resp.arg[0] : sizeof(version));
-                       uint8_t len = resp.arg[0] & 0xff;
-                       switch ( len ){
-                               // todo, identify "Magic UL-C tags". // they usually have a static nonce response to 0x1A command.
+                       uint8_t len  = resp.arg[0] & 0xff;
+                       switch ( len){
+                               // todo, identify "Magic UL-C tags".  // they usually have a static nonce response to 0x1A command.
                                // UL-EV1, size, check version[6] == 0x0b (smaller)  0x0b * 4 == 48
-                               case 0x0A:PrintAndLog("TYPE : NXP MIFARE Ultralight EV1 %d bytes", (version[6] == 0xB) ? 48 : 128);break;
+                               case 0x0A:PrintAndLog("TYPE : NXP MIFARE Ultralight EV1 %d bytes", (version[6] == 0xB) ? 48 : 128);     break;                          
                                case 0x01:PrintAndLog("TYPE : NXP MIFARE Ultralight C");break;
-                               case 0x00:PrintAndLog("TYPE : NXP MIFARE Ultralight");break;    
+                               case 0x00:PrintAndLog("TYPE : NXP MIFARE Ultralight");break;
                        }
                        */
                        break;
@@ -243,11 +237,10 @@ int CmdHF14AReader(const char *Cmd)
        }
 
        // Double & triple sized UID, can be mapped to a manufacturer.
-       // HACK: does this apply for Ultralight cards?
        if ( card.uidlen > 4 ) {
                PrintAndLog("MANUFACTURER : %s", getTagInfo(card.uid[0]));
        }
-
+       
        // try to request ATS even if tag claims not to support it
        if (select_status == 2) {
                uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
@@ -458,99 +451,123 @@ int CmdHF14ACUIDs(const char *Cmd)
        return 1;
 }
 
+
+static int usage_hf_14a_sim(void)
+{
+       PrintAndLog("\n Emulating ISO/IEC 14443 type A tag with 4 or 7 byte UID\n");
+       PrintAndLog("Usage: hf 14a sim t <type> u <uid> x");
+       PrintAndLog("  Options : ");
+       PrintAndLog("    h     : this help");
+       PrintAndLog("    t     : 1 = MIFARE Classic");
+       PrintAndLog("            2 = MIFARE Ultralight");
+       PrintAndLog("            3 = MIFARE Desfire");
+       PrintAndLog("            4 = ISO/IEC 14443-4");
+       PrintAndLog("            5 = MIFARE Tnp3xxx");
+       PrintAndLog("            6 = MIFARE Mini");
+       PrintAndLog("            7 = AMIIBO (NTAG 215),  pack 0x8080");
+       PrintAndLog("    u     : 4 or 7 byte UID");
+       PrintAndLog("    x     : (Optional) performs the 'reader attack', nr/ar attack against a legitimate reader");
+       PrintAndLog("\n   sample : hf 14a sim t 1 u 1122344");
+       PrintAndLog("          : hf 14a sim t 1 u 1122344 x\n");
+       return 0;
+}
+
 // ## simulate iso14443a tag
 // ## greg - added ability to specify tag UID
 int CmdHF14ASim(const char *Cmd)
 {
-       UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,{0,0,0}};
+       bool errors = FALSE;
+       uint8_t flags = 0;
+       uint8_t tagtype = 1;
+       uint64_t uid = 0;
+       uint8_t cmdp = 0;
        
-       // Retrieve the tag type
-       uint8_t tagtype = param_get8ex(Cmd,0,0,10);
+       clearCommandBuffer();
        
-       // When no argument was given, just print help message
-       if (tagtype == 0) {
-               PrintAndLog("");
-               PrintAndLog(" Emulating ISO/IEC 14443 type A tag with 4 or 7 byte UID");
-               PrintAndLog("");
-               PrintAndLog("   syntax: hf 14a sim <type> <uid>");
-               PrintAndLog("    types: 1 = MIFARE Classic");
-               PrintAndLog("           2 = MIFARE Ultralight");
-               PrintAndLog("           3 = MIFARE Desfire");
-               PrintAndLog("           4 = ISO/IEC 14443-4");
-               PrintAndLog("           5 = MIFARE Tnp3xxx");           
-               PrintAndLog("");
-               return 1;
+       while(param_getchar(Cmd, cmdp) != 0x00)
+       {
+               switch(param_getchar(Cmd, cmdp))
+               {
+                       case 'h':
+                       case 'H':
+                               return usage_hf_14a_sim();
+                       case 't':
+                       case 'T':
+                               // Retrieve the tag type
+                               tagtype = param_get8ex(Cmd, cmdp+1, 0, 10);
+                               if (tagtype == 0)
+                                       errors = true; 
+                               cmdp += 2;
+                               break;
+                       case 'u':
+                       case 'U':
+                               // Retrieve the full 4 or 7 byte long uid 
+                               uid = param_get64ex(Cmd, cmdp+1, 0, 16);
+                               if (uid == 0 )
+                                       errors = TRUE;
+                                
+                               if (uid > 0xffffffff) {
+                                       PrintAndLog("Emulating ISO/IEC 14443 type A tag with 7 byte UID (%014"llx")",uid);
+                                       flags |= FLAG_7B_UID_IN_DATA;
+                               } else {
+                                       PrintAndLog("Emulating ISO/IEC 14443 type A tag with 4 byte UID (%08x)",uid);
+                                       flags |= FLAG_4B_UID_IN_DATA;
+                               }
+                               cmdp += 2;
+                               break;
+                       case 'x':
+                       case 'X':
+                               flags |= FLAG_NR_AR_ATTACK;
+                               cmdp++;
+                               break;
+                       default:
+                               PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+                               errors = true;
+                               break;
+                       }
+               if(errors) break;
        }
+
+       //Validations
+       if (errors) return usage_hf_14a_sim();
+
+       PrintAndLog("Press pm3-button to abort simulation");
        
-       // Store the tag type
-       c.arg[0] = tagtype;
+       UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,{ tagtype, flags, 0 }};
        
-       // Retrieve the full 4 or 7 byte long uid 
-       uint64_t long_uid = param_get64ex(Cmd,1,0,16);
-
-       // Are we handling the (optional) second part uid?
-       if (long_uid > 0xffffffff) {
-               PrintAndLog("Emulating ISO/IEC 14443 type A tag with 7 byte UID (%014"llx")",long_uid);
-               // Store the second part
-               c.arg[2] = (long_uid & 0xffffffff);
-               long_uid >>= 32;
-               // Store the first part, ignore the first byte, it is replaced by cascade byte (0x88)
-               c.arg[1] = (long_uid & 0xffffff);
-       } else {
-               PrintAndLog("Emulating ISO/IEC 14443 type A tag with 4 byte UID (%08x)",long_uid);
-               // Only store the first part
-               c.arg[1] = long_uid & 0xffffffff;
-       }
-/*
-               // At lease save the mandatory first part of the UID
-               c.arg[0] = long_uid & 0xffffffff;
+       num_to_bytes(uid, 7, c.d.asBytes);
+       SendCommand(&c);        
 
-       if (c.arg[1] == 0) {
-               PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]);
+       uint8_t data[40];
+       uint8_t key[6];
+       UsbCommand resp;
+       while(!ukbhit()){
+               if ( WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+                       if ( (resp.arg[0] & 0xffff) == CMD_SIMULATE_MIFARE_CARD ){
+                               memset(data, 0x00, sizeof(data));
+                               memset(key, 0x00, sizeof(key));
+                               int len = (resp.arg[1] > sizeof(data)) ? sizeof(data) : resp.arg[1];
+                               memcpy(data, resp.d.asBytes, len);
+                               tryMfk32(uid, data, key);
+                               //tryMfk64(uid, data, key);
+                               PrintAndLog("--");
+                       }
+               }
        }
-       
-       switch (c.arg[0]) {
-               case 1: {
-                       PrintAndLog("Emulating ISO/IEC 14443-3 type A tag with 4 byte UID");
-                       UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16)};
-               } break;
-               case 2: {
-                       PrintAndLog("Emulating ISO/IEC 14443-4 type A tag with 7 byte UID");
-               } break;
-               default: {
-                       PrintAndLog("Error: unkown tag type (%d)",c.arg[0]);
-                       PrintAndLog("syntax: hf 14a sim <uid>",c.arg[0]);
-                       PrintAndLog(" type1: 4 ",c.arg[0]);
-
-                       return 1;
-               } break;
-       }       
-*/
-/*
-  unsigned int hi = 0, lo = 0;
-  int n = 0, i = 0;
-  while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
-    hi= (hi << 4) | (lo >> 28);
-    lo= (lo << 4) | (n & 0xf);
-  }
-*/
-//     UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16)};
-//  PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]);
-  SendCommand(&c);
-  return 0;
+       return 0;
 }
 
-int CmdHF14ASnoop(const char *Cmd) {
+int CmdHF14ASniff(const char *Cmd) {
        int param = 0;
        
        uint8_t ctmp = param_getchar(Cmd, 0) ;
        if (ctmp == 'h' || ctmp == 'H') {
                PrintAndLog("It get data from the field and saves it into command buffer.");
-               PrintAndLog("Buffer accessible from command hf list 14a.");
-               PrintAndLog("Usage:  hf 14a snoop [c][r]");
+               PrintAndLog("Buffer accessible from command 'hf list 14a'");
+               PrintAndLog("Usage:  hf 14a sniff [c][r]");
                PrintAndLog("c - triggered by first data from card");
                PrintAndLog("r - triggered by first 7-bit request from reader (REQ,WUP,...)");
-               PrintAndLog("sample: hf 14a snoop c r");
+               PrintAndLog("sample: hf 14a sniff c r");
                return 0;
        }       
        
@@ -565,16 +582,18 @@ int CmdHF14ASnoop(const char *Cmd) {
   return 0;
 }
 
+
 int CmdHF14ACmdRaw(const char *cmd) {
     UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
-    uint8_t reply=1;
-    uint8_t crc=0;
-    uint8_t power=0;
-    uint8_t active=0;
-    uint8_t active_select=0;
+    bool reply=1;
+    bool crc = FALSE;
+    bool power = FALSE;
+    bool active = FALSE;
+    bool active_select = FALSE;
     uint16_t numbits=0;
+       bool bTimeout = FALSE;
        uint32_t timeout=0;
-       uint8_t bTimeout=0;
+       bool topazmode = FALSE;
     char buf[5]="";
     int i=0;
     uint8_t data[USB_CMD_DATA_SIZE];
@@ -582,7 +601,7 @@ int CmdHF14ACmdRaw(const char *cmd) {
        uint32_t temp;
 
     if (strlen(cmd)<2) {
-        PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <number of bits> <0A 0B 0C ... hex>");
+        PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-a] [-t] <milliseconds> [-b] <number of bits>  <0A 0B 0C ... hex>");
         PrintAndLog("       -r    do not read response");
         PrintAndLog("       -c    calculate and append CRC");
         PrintAndLog("       -p    leave the signal field ON after receive");
@@ -590,9 +609,11 @@ int CmdHF14ACmdRaw(const char *cmd) {
         PrintAndLog("       -s    active signal field ON with select");
         PrintAndLog("       -b    number of bits to send. Useful for send partial byte");
                PrintAndLog("       -t    timeout in ms");
+               PrintAndLog("       -T    use Topaz protocol to send command");
         return 0;
     }
 
+
     // strip
     while (*cmd==' ' || *cmd=='\t') cmd++;
 
@@ -601,19 +622,19 @@ int CmdHF14ACmdRaw(const char *cmd) {
         if (cmd[i]=='-') {
             switch (cmd[i+1]) {
                 case 'r': 
-                    reply=0;
+                    reply = FALSE;
                     break;
                 case 'c':
-                    crc=1;
+                    crc = TRUE;
                     break;
                 case 'p':
-                    power=1;
+                    power = TRUE;
                     break;
                 case 'a':
-                    active=1;
+                    active = TRUE;
                     break;
                 case 's':
-                    active_select=1;
+                    active_select = TRUE;
                     break;
                 case 'b': 
                     sscanf(cmd+i+2,"%d",&temp);
@@ -623,13 +644,16 @@ int CmdHF14ACmdRaw(const char *cmd) {
                     i-=2;
                     break;
                                case 't':
-                                       bTimeout=1;
+                                       bTimeout = TRUE;
                                        sscanf(cmd+i+2,"%d",&temp);
                                        timeout = temp;
                                        i+=3;
                                        while(cmd[i]!=' ' && cmd[i]!='\0') { i++; }
                                        i-=2;
                                        break;
+                case 'T':
+                                       topazmode = TRUE;
+                                       break;
                 default:
                     PrintAndLog("Invalid option");
                     return 0;
@@ -648,7 +672,7 @@ int CmdHF14ACmdRaw(const char *cmd) {
                 sscanf(buf,"%x",&temp);
                 data[datalen]=(uint8_t)(temp & 0xff);
                 *buf=0;
-                               if (++datalen>sizeof(data)){
+                               if (++datalen >= sizeof(data)){
                                        if (crc)
                                                PrintAndLog("Buffer is full, we can't add CRC to your data");
                                        break;
@@ -659,10 +683,15 @@ int CmdHF14ACmdRaw(const char *cmd) {
         PrintAndLog("Invalid char on input");
         return 0;
     }
+
     if(crc && datalen>0 && datalen<sizeof(data)-2)
     {
         uint8_t first, second;
-        ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second);
+               if (topazmode) {
+                       ComputeCrc14443(CRC_14443_B, data, datalen, &first, &second);
+               } else {
+                       ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second);
+               }
         data[datalen++] = first;
         data[datalen++] = second;
     }
@@ -675,7 +704,7 @@ int CmdHF14ACmdRaw(const char *cmd) {
     }
 
        if(bTimeout){
-           #define MAX_TIMEOUT 40542464        // (2^32-1) * (8*16) / 13560000Hz * 1000ms/s = 
+           #define MAX_TIMEOUT 40542464        // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s
         c.arg[0] |= ISO14A_SET_TIMEOUT;
         if(timeout > MAX_TIMEOUT) {
             timeout = MAX_TIMEOUT;
@@ -683,11 +712,16 @@ int CmdHF14ACmdRaw(const char *cmd) {
         }
                c.arg[2] = 13560000 / 1000 / (8*16) * timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
        }
+
     if(power)
         c.arg[0] |= ISO14A_NO_DISCONNECT;
+
     if(datalen>0)
         c.arg[0] |= ISO14A_RAW;
 
+       if(topazmode)
+               c.arg[0] |= ISO14A_TOPAZMODE;
+               
        // Max buffer is USB_CMD_DATA_SIZE
     c.arg[1] = (datalen & 0xFFFF) | (numbits << 16);
     memcpy(c.d.asBytes,data,datalen);
@@ -703,6 +737,7 @@ int CmdHF14ACmdRaw(const char *cmd) {
     return 0;
 }
 
+
 static void waitCmd(uint8_t iSelect)
 {
     uint8_t *recv;
@@ -737,7 +772,7 @@ static command_t CommandTable[] =
   {"reader", CmdHF14AReader,       0, "Act like an ISO14443 Type A reader"},
   {"cuids",  CmdHF14ACUIDs,        0, "<n> Collect n>0 ISO14443 Type A UIDs in one go"},
   {"sim",    CmdHF14ASim,          0, "<UID> -- Simulate ISO 14443a tag"},
-  {"snoop",  CmdHF14ASnoop,        0, "Eavesdrop ISO 14443 Type A"},
+  {"sniff",  CmdHF14ASniff,        0, "sniff ISO 14443 Type A traffic"},
   {"raw",    CmdHF14ACmdRaw,       0, "Send raw hex data to tag"},
   {NULL, NULL, 0, NULL}
 };
@@ -747,8 +782,8 @@ int CmdHF14A(const char *Cmd) {
        WaitForResponseTimeout(CMD_ACK,NULL,100);
 
        // parse
-  CmdsParse(CommandTable, Cmd);
-  return 0;
+       CmdsParse(CommandTable, Cmd);
+       return 0;
 }
 
 int CmdHelp(const char *Cmd)
index aa35dec6d18d7718ed6a1d2c3cbdb8368747f78e..17c40bac1db68442fbe85d34489fbd5be2c6185b 100644 (file)
@@ -18,7 +18,8 @@ int CmdHF14AList(const char *Cmd);
 int CmdHF14AMifare(const char *Cmd);
 int CmdHF14AReader(const char *Cmd);
 int CmdHF14ASim(const char *Cmd);
-int CmdHF14ASnoop(const char *Cmd);
+int CmdHF14ASniff(const char *Cmd);
 
 char* getTagInfo(uint8_t uid);
+
 #endif
index 525ffcc63d1d62a79c14c1845ff8099fe3390b06..2a804c2170448d62f08aa94225699beee06930ac 100644 (file)
@@ -22,6 +22,8 @@
 #include "cmdparser.h"
 #include "cmdhf14b.h"
 #include "cmdmain.h"
+#include "cmdhf14a.h"
+#include "sleep.h"
 
 static int CmdHelp(const char *Cmd);
 
@@ -149,12 +151,6 @@ int CmdHF14BList(const char *Cmd)
 
        return 0;
 }
-int CmdHF14BRead(const char *Cmd)
-{
-  UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443, {strtol(Cmd, NULL, 0), 0, 0}};
-  SendCommand(&c);
-  return 0;
-}
 
 int CmdHF14Sim(const char *Cmd)
 {
@@ -199,20 +195,70 @@ int CmdSrix4kRead(const char *Cmd)
   return 0;
 }
 
-int CmdHF14BCmdRaw (const char *cmd) {
+int rawClose(void){
     UsbCommand resp;
-    uint8_t *recv;
-    UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; // len,recv?
-    uint8_t reply=1;
-    uint8_t crc=0;
-    uint8_t power=0;
+       UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}};
+       SendCommand(&c);
+       if (!WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
+               return 0;
+       }
+       return 0;       
+}
+
+int HF14BCmdRaw(bool reply, bool *crc, uint8_t power_trace, uint8_t *data, uint8_t *datalen, bool verbose){
+       UsbCommand resp;
+       UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; // len,recv,power
+  if(*crc)
+  {
+    uint8_t first, second;
+    ComputeCrc14443(CRC_14443_B, data, *datalen, &first, &second);
+    data[*datalen] = first;
+    data[*datalen + 1] = second;
+    *datalen += 2;
+  }
+  
+  c.arg[0] = *datalen;
+  c.arg[1] = reply;
+       c.arg[2] = power_trace;
+  memcpy(c.d.asBytes,data,*datalen);
+  SendCommand(&c);
+  
+  if (!reply) return 1; 
+
+  if (!WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
+    if (verbose) PrintAndLog("timeout while waiting for reply.");
+    return 0;
+  }
+  *datalen = resp.arg[0];
+       if (verbose) PrintAndLog("received %u octets", *datalen);
+  if(!*datalen)
+    return 0;
+
+  memcpy(data, resp.d.asBytes, *datalen);
+  if (verbose) PrintAndLog("%s", sprint_hex(data, *datalen));
+
+  uint8_t first, second;
+  ComputeCrc14443(CRC_14443_B, data, *datalen-2, &first, &second);
+  if(data[*datalen-2] == first && data[*datalen-1] == second) {
+    if (verbose) PrintAndLog("CRC OK");
+    *crc = true;
+  } else {
+    if (verbose) PrintAndLog("CRC failed");
+    *crc = false;
+  }
+  return 1;
+}
+
+int CmdHF14BCmdRaw (const char *Cmd) {
+    bool reply = true;
+    bool crc = false;
+       uint8_t power_trace = 0;
     char buf[5]="";
-    int i=0;
     uint8_t data[100] = {0x00};
-    unsigned int datalen=0, temp;
-    char *hexout;
-    
-    if (strlen(cmd)<3) {
+    uint8_t datalen = 0;
+    unsigned int temp;
+    int i = 0;
+    if (strlen(Cmd)<3) {
         PrintAndLog("Usage: hf 14b raw [-r] [-c] [-p] <0A 0B 0C ... hex>");
         PrintAndLog("       -r    do not read response");
         PrintAndLog("       -c    calculate and append CRC");
@@ -221,23 +267,23 @@ int CmdHF14BCmdRaw (const char *cmd) {
     }
 
     // strip
-    while (*cmd==' ' || *cmd=='\t') cmd++;
+    while (*Cmd==' ' || *Cmd=='\t') Cmd++;
     
-    while (cmd[i]!='\0') {
-        if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; }
-        if (cmd[i]=='-') {
-            switch (cmd[i+1]) {
+    while (Cmd[i]!='\0') {
+        if (Cmd[i]==' ' || Cmd[i]=='\t') { i++; continue; }
+        if (Cmd[i]=='-') {
+            switch (Cmd[i+1]) {
                 case 'r': 
                 case 'R': 
-                    reply=0;
+                    reply = false;
                     break;
                 case 'c':
                 case 'C':                
-                    crc=1;
+                    crc = true;
                     break;
                 case 'p': 
                 case 'P': 
-                    power=1;
+                                       power_trace |= 1;
                     break;
                 default:
                     PrintAndLog("Invalid option");
@@ -246,17 +292,16 @@ int CmdHF14BCmdRaw (const char *cmd) {
             i+=2;
             continue;
         }
-        if ((cmd[i]>='0' && cmd[i]<='9') ||
-            (cmd[i]>='a' && cmd[i]<='f') ||
-            (cmd[i]>='A' && cmd[i]<='F') ) {
+        if ((Cmd[i]>='0' && Cmd[i]<='9') ||
+            (Cmd[i]>='a' && Cmd[i]<='f') ||
+            (Cmd[i]>='A' && Cmd[i]<='F') ) {
             buf[strlen(buf)+1]=0;
-            buf[strlen(buf)]=cmd[i];
+            buf[strlen(buf)]=Cmd[i];
             i++;
             
             if (strlen(buf)>=2) {
                 sscanf(buf,"%x",&temp);
-                data[datalen]=(uint8_t)(temp & 0xff);
-                datalen++;
+                data[datalen++]=(uint8_t)(temp & 0xff);
                 *buf=0;
             }
             continue;
@@ -269,49 +314,166 @@ int CmdHF14BCmdRaw (const char *cmd) {
       PrintAndLog("Missing data input");
       return 0;
     }
-    if(crc)
-    {
-        uint8_t first, second;
-        ComputeCrc14443(CRC_14443_B, data, datalen, &first, &second);
-        data[datalen++] = first;
-        data[datalen++] = second;
-    }
-    
-    c.arg[0] = datalen;
-    c.arg[1] = reply;
-    c.arg[2] = power;
-    memcpy(c.d.asBytes,data,datalen);
-    
-    SendCommand(&c);
-    
-    if (reply) {
-        if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
-            recv = resp.d.asBytes;
-            PrintAndLog("received %i octets",resp.arg[0]);
-            if(!resp.arg[0])
-                return 0;
-            hexout = (char *)malloc(resp.arg[0] * 3 + 1);
-            if (hexout != NULL) {
-                uint8_t first, second;
-                for (int i = 0; i < resp.arg[0]; i++) { // data in hex
-                    sprintf(&hexout[i * 3], "%02X ", recv[i]);
-                }
-                PrintAndLog("%s", hexout);
-                free(hexout);
-                ComputeCrc14443(CRC_14443_B, recv, resp.arg[0]-2, &first, &second);
-                if(recv[resp.arg[0]-2]==first && recv[resp.arg[0]-1]==second) {
-                    PrintAndLog("CRC OK");
-                } else {
-                    PrintAndLog("CRC failed");
-                }
-            } else {
-                PrintAndLog("malloc failed your client has low memory?");
-            }
-        } else {
-            PrintAndLog("timeout while waiting for reply.");
-        }
-    } // if reply
-    return 0;
+
+       return HF14BCmdRaw(reply, &crc, power_trace, data, &datalen, true);
+}
+
+static void print_atqb_resp(uint8_t *data){
+  PrintAndLog ("           UID: %s", sprint_hex(data+1,4));
+  PrintAndLog ("      App Data: %s", sprint_hex(data+5,4));
+  PrintAndLog ("      Protocol: %s", sprint_hex(data+9,3));
+  uint8_t BitRate = data[9];
+  if (!BitRate) 
+    PrintAndLog ("      Bit Rate: 106 kbit/s only PICC <-> PCD");
+  if (BitRate & 0x10)
+    PrintAndLog ("      Bit Rate: 212 kbit/s PICC -> PCD supported");
+  if (BitRate & 0x20)
+    PrintAndLog ("      Bit Rate: 424 kbit/s PICC -> PCD supported"); 
+  if (BitRate & 0x40)
+    PrintAndLog ("      Bit Rate: 847 kbit/s PICC -> PCD supported"); 
+  if (BitRate & 0x01)
+    PrintAndLog ("      Bit Rate: 212 kbit/s PICC <- PCD supported");
+  if (BitRate & 0x02)
+    PrintAndLog ("      Bit Rate: 424 kbit/s PICC <- PCD supported"); 
+  if (BitRate & 0x04)
+    PrintAndLog ("      Bit Rate: 847 kbit/s PICC <- PCD supported"); 
+  if (BitRate & 0x80) 
+    PrintAndLog ("                Same bit rate <-> required");
+
+  uint16_t maxFrame = data[10]>>4;
+  if (maxFrame < 5) 
+    maxFrame = 8*maxFrame + 16;
+  else if (maxFrame == 5)
+    maxFrame = 64;
+  else if (maxFrame == 6)
+    maxFrame = 96;
+  else if (maxFrame == 7)
+    maxFrame = 128;
+  else if (maxFrame == 8)
+    maxFrame = 256;
+  else
+    maxFrame = 257;
+
+  PrintAndLog ("Max Frame Size: %d%s",maxFrame, (maxFrame == 257) ? "+ RFU" : "");
+
+  uint8_t protocolT = data[10] & 0xF;
+  PrintAndLog (" Protocol Type: Protocol is %scompliant with ISO/IEC 14443-4",(protocolT) ? "" : "not " );
+  PrintAndLog ("Frame Wait Int: %d", data[11]>>4);
+  PrintAndLog (" App Data Code: Application is %s",(data[11]&4) ? "Standard" : "Proprietary");
+  PrintAndLog (" Frame Options: NAD is %ssupported",(data[11]&2) ? "" : "not ");
+  PrintAndLog (" Frame Options: CID is %ssupported",(data[11]&1) ? "" : "not ");
+  
+  return;
+}
+
+char *get_ST_Chip_Model(uint8_t data){
+       static char model[20];
+       char *retStr = model;
+       memset(model,0, sizeof(model));
+
+       switch (data) {
+               case 0x0: sprintf(retStr, "SRIX4K (Special)"); break;
+               case 0x2: sprintf(retStr, "SR176"); break;
+               case 0x3: sprintf(retStr, "SRIX4K"); break;
+               case 0x4: sprintf(retStr, "SRIX512"); break;
+               case 0x6: sprintf(retStr, "SRI512"); break;
+               case 0x7: sprintf(retStr, "SRI4K"); break;
+               case 0xC: sprintf(retStr, "SRT512"); break;
+               default: sprintf(retStr, "Unknown"); break;
+       }
+       return retStr;
+}
+
+static void print_st_info(uint8_t *data){
+       //uid = first 8 bytes in data
+       PrintAndLog(" UID: %s", sprint_hex(data,8));
+       PrintAndLog(" MFG: %02X, %s", data[1], getTagInfo(data[1]));
+       PrintAndLog("Chip: %02X, %s", data[2]>>2, get_ST_Chip_Model(data[2]>>2));
+       return;
+}
+
+int HF14BStdRead(uint8_t *data, uint8_t *datalen){
+  bool crc = true;
+  *datalen = 3;
+  //std read cmd
+  data[0] = 0x05;
+  data[1] = 0x00;
+  data[2] = 0x08;
+
+       int ans = HF14BCmdRaw(true, &crc, 2, data, datalen, false);
+
+  if (!ans) return 0;
+  if (data[0] != 0x50  || *datalen < 14 || !crc) return 0;
+
+  PrintAndLog ("\n14443-3b tag found:");
+  print_atqb_resp(data);
+
+  return 1;
+}
+
+
+
+int HF14B_ST_Read(uint8_t *data, uint8_t *datalen){
+  bool crc = true;
+  *datalen = 2;
+       //wake cmd
+  data[0] = 0x06;
+  data[1] = 0x00;
+       //power on and reset tracing
+       int ans = HF14BCmdRaw(true, &crc, 3, data, datalen, true);
+
+       if (!ans) return rawClose();
+       if (*datalen < 3 || !crc) return rawClose();
+
+  uint8_t chipID = data[0];
+       // select
+  data[0] = 0x0E;
+  data[1] = chipID;
+  *datalen = 2;
+       msleep(100);
+       //power on
+       ans = HF14BCmdRaw(true, &crc, 1, data, datalen, true);
+
+       if (!ans) return rawClose();
+       if (*datalen < 3 || !crc) return rawClose();
+
+       // get uid
+  data[0] = 0x0B;
+  *datalen = 1;
+       msleep(100);
+       //power off
+       ans = HF14BCmdRaw(true, &crc, 0, data, datalen, true);
+
+  if (!ans) return 0;
+  if (*datalen < 10 || !crc) return 0;
+
+       PrintAndLog("\n14443-3b ST tag found:");
+       print_st_info(data);
+  return 1;
+
+}
+
+int HF14BReader(bool verbose){
+  uint8_t data[100];
+  uint8_t datalen = 5;
+  
+  // try std 14b (atqb)
+  int ans = HF14BStdRead(data, &datalen);
+  if (ans) return 1;
+
+  // try st 14b
+  ans = HF14B_ST_Read(data, &datalen);
+  if (ans) return 1;
+       if (verbose) PrintAndLog("no 14443B tag found");
+       return 0;
+
+}
+
+int CmdHF14BReader(const char *Cmd)
+{
+       return HF14BReader(true);
+  //UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443, {strtol(Cmd, NULL, 0), 0, 0}};
+  //SendCommand(&c);
 }
 
 int CmdHF14BWrite( const char *Cmd){
@@ -387,7 +549,7 @@ static command_t CommandTable[] =
   {"help",        CmdHelp,        1, "This help"},
   {"demod",       CmdHF14BDemod,  1, "Demodulate ISO14443 Type B from tag"},
   {"list",        CmdHF14BList,   0, "[Deprecated] List ISO 14443b history"},
-  {"read",        CmdHF14BRead,   0, "Read HF tag (ISO 14443)"},
+  {"reader",      CmdHF14BReader, 0, "Find 14b tag (HF ISO 14443b)"},
   {"sim",         CmdHF14Sim,     0, "Fake ISO 14443 tag"},
   {"simlisten",   CmdHFSimlisten, 0, "Get HF samples as fake tag"},
   {"snoop",       CmdHF14BSnoop,  0, "Eavesdrop ISO 14443"},
index cc8b9dbd810c15a889c40e406f6d4f980b5c5ca2..66fd430f2bef20b110fe07f095a30cfb3a0a391e 100644 (file)
@@ -15,7 +15,8 @@ int CmdHF14B(const char *Cmd);
 
 int CmdHF14BDemod(const char *Cmd);
 int CmdHF14BList(const char *Cmd);
-int CmdHF14BRead(const char *Cmd);
+int CmdHF14BReader(const char *Cmd);
+int HF14BReader(bool verbose);
 int CmdHF14Sim(const char *Cmd);
 int CmdHFSimlisten(const char *Cmd);
 int CmdHF14BSnoop(const char *Cmd);
index 8ddbea89bbab5cf8034ead823a6f6a2ea9c10f34..caf0799e585102295661c55b40b7eba02bc66625 100644 (file)
@@ -175,9 +175,9 @@ const productName uidmapping[] = {
        { 0xE02E000000000000LL, 16, "Broadcom Corporation USA" },
        { 0xE02F000000000000LL, 16, "MStar Semiconductor, Inc Taiwan, ROC" },
        { 0xE030000000000000LL, 16, "BeeDar Technology Inc. USA" },
-       { 0xE031000000000000LL, 16, " RFIDsec Denmark" },
-       { 0xE032000000000000LL, 16, " Schweizer Electronic AG Germany" },
-       { 0xE033000000000000LL, 16, " AMIC Technology Corp Taiwan" }, 
+       { 0xE031000000000000LL, 16, "RFIDsec Denmark" },
+       { 0xE032000000000000LL, 16, "Schweizer Electronic AG Germany" },
+       { 0xE033000000000000LL, 16, "AMIC Technology Corp Taiwan" }, 
        { 0xE034000000000000LL, 16, "Mikron JSC Russia" },
        { 0xE035000000000000LL, 16, "Fraunhofer Institute for Photonic Microsystems Germany" },
        { 0xE036000000000000LL, 16, "IDS Microchip AG Switzerland" },
@@ -682,9 +682,9 @@ int CmdHF15CmdRaw (const char *cmd) {
  */
 int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) {
        int temp;
-       uint8_t *req=c->d.asBytes;
+       uint8_t *req = c->d.asBytes;
        uint8_t uid[8] = {0x00};
-       uint32_t reqlen=0;
+       uint32_t reqlen = 0;
 
        // strip
        while (**cmd==' ' || **cmd=='\t') (*cmd)++;
@@ -777,10 +777,10 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
        UsbCommand resp;
        uint8_t *recv;
        UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
-       uint8_t *req=c.d.asBytes;
-       int reqlen=0;
+       uint8_t *req = c.d.asBytes;
+       int reqlen = 0;
        char cmdbuf[100];
-       char *cmd=cmdbuf;
+       char *cmd = cmdbuf;
        char output[2048]="";
        int i;
        
@@ -802,7 +802,7 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
        }       
        
        prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_SYSINFO},1);      
-       reqlen=c.arg[0];
+       reqlen = c.arg[0];
        
        reqlen=AddCrc(req,reqlen);
        c.arg[0]=reqlen;
diff --git a/client/cmdhfdes.c b/client/cmdhfdes.c
new file mode 100644 (file)
index 0000000..1876e5c
--- /dev/null
@@ -0,0 +1,69 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2012 nuit
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// High frequency MIFARE DESfire commands
+//-----------------------------------------------------------------------------
+
+#include "cmdhfdes.h"
+#include "proxmark3.h"
+#include "cmdmain.h"
+
+static int CmdHelp(const char *Cmd);
+
+int CmdHFDESReader(const char *Cmd)
+{
+    UsbCommand c  ={CMD_MIFARE_DES_READER, {3, 0x60, 0}};
+    SendCommand(&c);
+
+    UsbCommand resp;
+       WaitForResponseTimeout(CMD_ACK,&resp,2000);
+    return 0;
+}  
+
+int CmdHFDESDbg(const char *Cmd)
+{
+    int dbgMode = param_get32ex(Cmd, 0, 0, 10);
+    if (dbgMode > 4) {
+        PrintAndLog("Max debud mode parameter is 4 \n");
+    }
+
+    if (strlen(Cmd) < 1 || !param_getchar(Cmd, 0) || dbgMode > 4) {
+        PrintAndLog("Usage:  hf des dbg  <debug level>");
+        PrintAndLog(" 0 - no debug messages");
+        PrintAndLog(" 1 - error messages");
+        PrintAndLog(" 2 - all messages");
+        PrintAndLog(" 4 - extended debug mode");
+        return 0;
+    }
+
+  UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}};
+  SendCommand(&c);
+
+  return 0;
+}
+
+static command_t CommandTable[] = 
+{
+    {"help",    CmdHelp,    1,  "This help"},
+    {"dbg",     CmdHFDESDbg, 0, "Set default debug mode"},
+    {"reader",  CmdHFDESReader, 0, "Reader"},
+  {NULL, NULL, 0, NULL}
+};
+
+int CmdHFDES(const char *Cmd)
+{
+    //flush
+    WaitForResponseTimeout(CMD_ACK,NULL,100);
+    CmdsParse(CommandTable, Cmd);
+    return 0;
+}
+
+int CmdHelp(const char *Cmd)
+{
+    CmdsHelp(CommandTable);
+    return 0;
+}
diff --git a/client/cmdhfdes.h b/client/cmdhfdes.h
new file mode 100644 (file)
index 0000000..e51797c
--- /dev/null
@@ -0,0 +1,27 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2012 nuit
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// High frequency MIFARE DESfire commands
+//-----------------------------------------------------------------------------
+
+#ifndef CMDHFDES_H__
+#define CMDHFDES_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "proxmark3.h"
+#include "data.h"
+#include "ui.h"
+#include "cmdparser.h"
+#include "common.h"
+#include "util.h"
+int CmdHFDES(const char *Cmd);
+int CmdHFDESReader(const char *Cmd);
+int CmdHFDESDbg(const char *Cmd);
+#endif
index 3286ceb9cce45a2f9d9738219347044db63a303a..afcdb0fa040ae9b822376415c2167a0a07326eac 100644 (file)
@@ -13,7 +13,7 @@
 #include "proxmark3.h"
 #include "ui.h"
 #include "cmdparser.h"
-#include "common.h"
+#include "../include/common.h"
 #include "cmdmain.h"
 #include "sleep.h"
 #include "cmdhfepa.h"
index 824aaa3674cc1bd5cf84d38174968d0e3fbd468e..e8ba68f18467c2c221bd40cb24a63fc9b57a1a8c 100644 (file)
@@ -175,11 +175,11 @@ int HFiClassReader(const char *Cmd, bool loop, bool verbose)
        UsbCommand resp;
        while(!ukbhit()){
                if (WaitForResponseTimeout(CMD_ACK,&resp, 4500)) {
-                       uint8_t readStatus = resp.arg[0] & 0xff;
+                       uint8_t readStatus    = resp.arg[0] & 0xff;
                        uint8_t *data = resp.d.asBytes;
 
                        if (verbose)
-                               PrintAndLog("Readstatus:%02x", readStatus);
+                       PrintAndLog("Readstatus:%02x", readStatus);
                        if( readStatus == 0){
                                //Aborted
                                if (verbose) PrintAndLog("Quitting...");
index 5abda060d8e4e40ae83f71977e4d864ad39dfaff..809c623acff06c3d05fad362c48aa19503e25fdb 100644 (file)
@@ -9,6 +9,7 @@
 //-----------------------------------------------------------------------------\r
 \r
 #include "cmdhfmf.h"\r
+#include "nonce2key/nonce2key.h"\r
 \r
 static int CmdHelp(const char *Cmd);\r
 \r
@@ -781,8 +782,8 @@ int CmdHF14AMfChk(const char *Cmd)
                PrintAndLog("Usage:  hf mf chk <block number>|<*card memory> <key type (A/B/?)> [t|d] [<key (12 hex symbols)>] [<dic (*.dic)>]");\r
                PrintAndLog("          * - all sectors");\r
                PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");\r
-               PrintAndLog("d - write keys to binary file\n");\r
-               PrintAndLog("t - write keys to emulator memory");\r
+               PrintAndLog("d - write keys to binary file");\r
+               PrintAndLog("t - write keys to emulator memory\n");\r
                PrintAndLog("      sample: hf mf chk 0 A 1234567890ab keys.dic");\r
                PrintAndLog("              hf mf chk *1 ? t");\r
                PrintAndLog("              hf mf chk *1 ? d");\r
@@ -1011,8 +1012,10 @@ int CmdHF14AMf1kSim(const char *Cmd)
        uint8_t uid[7] = {0, 0, 0, 0, 0, 0, 0};\r
        uint8_t exitAfterNReads = 0;\r
        uint8_t flags = 0;\r
-\r
+       \r
        uint8_t cmdp = param_getchar(Cmd, 0);\r
+\r
+       clearCommandBuffer();\r
        \r
        if (cmdp == 'h' || cmdp == 'H') {\r
                PrintAndLog("Usage:  hf mf sim  u <uid (8 hex symbols)> n <numreads> i x");\r
@@ -1063,15 +1066,42 @@ int CmdHF14AMf1kSim(const char *Cmd)
        SendCommand(&c);\r
 \r
        if(flags & FLAG_INTERACTIVE)\r
-       {\r
-               UsbCommand resp;\r
+       {               \r
                PrintAndLog("Press pm3-button to abort simulation");\r
-               while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
-                       //We're waiting only 1.5 s at a time, otherwise we get the\r
-                       // annoying message about "Waiting for a response... "\r
+               \r
+               uint8_t data[40];\r
+               uint8_t key[6];\r
+\r
+               UsbCommand resp;                \r
+               while(!ukbhit() ){\r
+                       if ( WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {\r
+                               if ( (resp.arg[0] & 0xffff) == CMD_SIMULATE_MIFARE_CARD ){\r
+                                       memset(data, 0x00, sizeof(data));\r
+                                       memset(key, 0x00, sizeof(key));\r
+                                       int len = (resp.arg[1] > sizeof(data)) ? sizeof(data) : resp.arg[1];\r
+                                       \r
+                                       memcpy(data, resp.d.asBytes, len);\r
+                                       \r
+                                       uint64_t corr_uid = 0;\r
+                                       if ( memcmp(data, "\x00\x00\x00\x00", 4) == 0 ) {\r
+                                               corr_uid = (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0];\r
+                                       }\r
+                                       else {\r
+                                               corr_uid |= (uint64_t)data[2] << 48; \r
+                                               corr_uid |= (uint64_t)data[1] << 40; \r
+                                               corr_uid |= (uint64_t)data[0] << 32;\r
+                                               corr_uid |= data[7] << 24;\r
+                                               corr_uid |= data[6] << 16;\r
+                                               corr_uid |= data[5] << 8;\r
+                                               corr_uid |= data[4];\r
+                                       }\r
+                                       tryMfk32(corr_uid, data, key);\r
+                                       //tryMfk64(corr_uid, data, key);\r
+                                       PrintAndLog("--");\r
+                               }\r
+                       }\r
                }\r
        }\r
-       \r
        return 0;\r
 }\r
 \r
@@ -1752,8 +1782,7 @@ int CmdHF14AMfCSave(const char *Cmd) {
                                PrintAndLog("Cant get block: %d", 0);\r
                                len = sprintf(fnameptr, "dump");\r
                                fnameptr += len;\r
-                       }\r
-                       else {\r
+                       } else {\r
                                for (j = 0; j < 7; j++, fnameptr += 2)\r
                                        sprintf(fnameptr, "%02x", buf[j]); \r
                        }\r
index 22dfd4de5071b709d8f10f06ae3c36fd51030a28..45ba7cb1f261cfdf4d668ed20d5b80b64eedd1b6 100644 (file)
 #include <string.h>\r
 #include <ctype.h>\r
 #include "proxmark3.h"\r
-#include "iso14443crc.h"\r
+#include "../common/iso14443crc.h"\r
 #include "data.h"\r
 #include "ui.h"\r
 #include "cmdparser.h"\r
-#include "common.h"\r
+#include "../include/common.h"\r
 #include "util.h"\r
 #include "mifarehost.h"\r
 \r
@@ -53,5 +53,5 @@ int CmdHF14AMfCGetBlk(const char* cmd);
 int CmdHF14AMfCGetSc(const char* cmd);\r
 int CmdHF14AMfCLoad(const char* cmd);\r
 int CmdHF14AMfCSave(const char* cmd);\r
-\r
+int GetCardSize();\r
 #endif\r
diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c
new file mode 100644 (file)
index 0000000..516b41b
--- /dev/null
@@ -0,0 +1,665 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2014 Iceman
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// High frequency MIFARE Desfire commands
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+//#include <openssl/des.h>
+#include "loclass/des.h"
+#include "cmdmain.h"
+#include "proxmark3.h"
+#include "../include/common.h"
+#include "../include/mifare.h"
+#include "../common/iso14443crc.h"
+#include "data.h"
+#include "ui.h"
+#include "cmdparser.h"
+#include "util.h"
+#include "cmdhfmfdes.h"
+#include "cmdhf14a.h"
+
+
+uint8_t CMDPOS = 0;
+uint8_t LENPOS = 1;
+
+uint8_t key_zero_data[16] = { 0x00 };
+uint8_t key_ones_data[16] = { 0x01 };
+uint8_t key_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };
+uint8_t key_picc_data[16] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f };
+
+static int CmdHelp(const char *Cmd);
+
+int CmdHF14ADesWb(const char *Cmd)
+{
+/*     uint8_t blockNo = 0;
+       uint8_t keyType = 0;
+       uint8_t key[6] = {0, 0, 0, 0, 0, 0};
+       uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+       
+       char cmdp       = 0x00;
+
+       if (strlen(Cmd)<3) {
+               PrintAndLog("Usage:  hf mf wrbl    <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>");
+               PrintAndLog("        sample: hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F");
+               return 0;
+       }       
+
+       blockNo = param_get8(Cmd, 0);
+       cmdp = param_getchar(Cmd, 1);
+       if (cmdp == 0x00) {
+               PrintAndLog("Key type must be A or B");
+               return 1;
+       }
+       if (cmdp != 'A' && cmdp != 'a') keyType = 1;
+       if (param_gethex(Cmd, 2, key, 12)) {
+               PrintAndLog("Key must include 12 HEX symbols");
+               return 1;
+       }
+       if (param_gethex(Cmd, 3, bldata, 32)) {
+               PrintAndLog("Block data must include 32 HEX symbols");
+               return 1;
+       }
+       PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6));
+       PrintAndLog("--data: %s", sprint_hex(bldata, 16));
+       
+  UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}};
+       memcpy(c.d.asBytes, key, 6);
+       memcpy(c.d.asBytes + 10, bldata, 16);
+  SendCommand(&c);
+
+       UsbCommand resp;
+       if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+               uint8_t isOK  = resp.arg[0] & 0xff;
+               PrintAndLog("isOk:%02x", isOK);
+       } else {
+               PrintAndLog("Command execute timeout");
+       }
+ */
+       return 0;
+}
+
+int CmdHF14ADesRb(const char *Cmd)
+{
+       // uint8_t blockNo = 0;
+       // uint8_t keyType = 0;
+       // uint8_t key[6] = {0, 0, 0, 0, 0, 0};
+       
+       // char cmdp    = 0x00;
+
+
+       // if (strlen(Cmd)<3) {
+               // PrintAndLog("Usage:  hf mf rdbl    <block number> <key A/B> <key (12 hex symbols)>");
+               // PrintAndLog("        sample: hf mf rdbl 0 A FFFFFFFFFFFF ");
+               // return 0;
+       // }    
+       
+       // blockNo = param_get8(Cmd, 0);
+       // cmdp = param_getchar(Cmd, 1);
+       // if (cmdp == 0x00) {
+               // PrintAndLog("Key type must be A or B");
+               // return 1;
+       // }
+       // if (cmdp != 'A' && cmdp != 'a') keyType = 1;
+       // if (param_gethex(Cmd, 2, key, 12)) {
+               // PrintAndLog("Key must include 12 HEX symbols");
+               // return 1;
+       // }
+       // PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6));
+       
+  // UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}};
+       // memcpy(c.d.asBytes, key, 6);
+  // SendCommand(&c);
+
+       // UsbCommand resp;
+       // if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+               // uint8_t                isOK  = resp.arg[0] & 0xff;
+               // uint8_t              * data  = resp.d.asBytes;
+
+               // if (isOK)
+                       // PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16));
+               // else
+                       // PrintAndLog("isOk:%02x", isOK);
+       // } else {
+               // PrintAndLog("Command execute timeout");
+       // }
+
+  return 0;
+}
+
+int CmdHF14ADesInfo(const char *Cmd){
+
+       UsbCommand c = {CMD_MIFARE_DESFIRE_INFO};
+    SendCommand(&c);
+       UsbCommand resp;
+       
+       if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
+               PrintAndLog("Command execute timeout");
+               return 0;
+       }
+       uint8_t isOK  = resp.arg[0] & 0xff;
+       if ( !isOK ){
+               PrintAndLog("Command unsuccessful");
+               return 0;
+       }  
+       PrintAndLog("");
+       PrintAndLog("-- Desfire Information --------------------------------------");
+       PrintAndLog("-------------------------------------------------------------");
+       PrintAndLog("  UID                : %s",sprint_hex(resp.d.asBytes, 7));
+       PrintAndLog("  Batch number       : %s",sprint_hex(resp.d.asBytes+28,5));
+       PrintAndLog("  Production date    : week %02x, 20%02x",resp.d.asBytes[33], resp.d.asBytes[34]);
+       PrintAndLog("  -----------------------------------------------------------");
+       PrintAndLog("  Hardware Information");
+       PrintAndLog("      Vendor Id      : %s", getTagInfo(resp.d.asBytes[7]));
+       PrintAndLog("      Type           : 0x%02X",resp.d.asBytes[8]);
+       PrintAndLog("      Subtype        : 0x%02X",resp.d.asBytes[9]);
+       PrintAndLog("      Version        : %d.%d",resp.d.asBytes[10], resp.d.asBytes[11]);
+       PrintAndLog("      Storage size   : %s",GetCardSizeStr(resp.d.asBytes[12]));
+       PrintAndLog("      Protocol       : %s",GetProtocolStr(resp.d.asBytes[13]));
+       PrintAndLog("  -----------------------------------------------------------");
+       PrintAndLog("  Software Information");
+       PrintAndLog("      Vendor Id      : %s", getTagInfo(resp.d.asBytes[14]));
+       PrintAndLog("      Type           : 0x%02X",resp.d.asBytes[15]);
+       PrintAndLog("      Subtype        : 0x%02X",resp.d.asBytes[16]);
+       PrintAndLog("      Version        : %d.%d",resp.d.asBytes[17], resp.d.asBytes[18]);
+       PrintAndLog("      storage size   : %s", GetCardSizeStr(resp.d.asBytes[19]));
+       PrintAndLog("      Protocol       : %s", GetProtocolStr(resp.d.asBytes[20]));
+       PrintAndLog("-------------------------------------------------------------");
+       
+       // Master Key settings
+       GetKeySettings(NULL);
+       
+       // Free memory on card
+       c.cmd = CMD_MIFARE_DESFIRE;
+       c.arg[0] = (INIT | DISCONNECT);
+       c.arg[1] = 0x01;
+       c.d.asBytes[0] = GET_FREE_MEMORY;
+    SendCommand(&c);
+       if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+               return 0;
+       }  
+       
+       uint8_t tmp[3];
+       memcpy(tmp, resp.d.asBytes+3,3); 
+
+       PrintAndLog("   Available free memory on card       : %d bytes", le24toh( tmp ));
+       PrintAndLog("-------------------------------------------------------------");
+
+       /*
+               Card Master key (CMK)        0x00 AID = 00 00 00 (card level)
+               Application Master Key (AMK) 0x00 AID != 00 00 00
+               Application keys (APK)       0x01-0x0D
+               Application free             0x0E
+               Application never            0x0F
+               
+               ACCESS RIGHTS:
+               keys 0,1,2,3     C
+               keys 4,5,6,7     RW
+               keys 8,9,10,11   W
+               keys 12,13,14,15 R
+       
+       */
+       
+    return 1;
+}
+
+/*
+  The 7 MSBits (= n) code the storage size itself based on 2^n, 
+  the LSBit is set to '0' if the size is exactly 2^n
+       and set to '1' if the storage size is between 2^n and 2^(n+1). 
+       For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
+*/
+char * GetCardSizeStr( uint8_t fsize ){
+       static char buf[30];
+       char *retStr = buf;
+
+       uint16_t usize = 1 << ((fsize >>1) + 1);
+       uint16_t lsize = 1 << (fsize >>1);
+       
+       // is  LSB set?
+       if (  fsize & 1 )
+               sprintf(retStr, "0x%02X (%d - %d bytes)",fsize, usize, lsize);
+       else 
+               sprintf(retStr, "0x%02X (%d bytes)", fsize, lsize);             
+       return buf;
+}
+
+char * GetProtocolStr(uint8_t id){
+
+       static char buf[30];
+       char *retStr = buf;
+
+       if ( id == 0x05)
+               sprintf(retStr,"0x%02X (ISO 14443-3, 14443-4)", id);
+       else
+               sprintf(retStr,"0x%02X (Unknown)", id); 
+       return buf;
+}
+
+void GetKeySettings( uint8_t *aid){
+       
+       char messStr[512] = {0x00};
+       char *str = messStr;
+       uint8_t isOK = 0;
+       uint32_t options = NONE;
+       UsbCommand c;
+       UsbCommand resp;
+
+       //memset(messStr, 0x00, 512);
+       
+       c.cmd = CMD_MIFARE_DESFIRE;
+       
+       if ( aid == NULL ){
+               PrintAndLog(" CMK - PICC, Card Master Key settings ");
+               PrintAndLog("");
+               c.arg[CMDPOS] = (INIT | DISCONNECT);
+               c.arg[LENPOS] =  0x01;
+               c.d.asBytes[0] = GET_KEY_SETTINGS;  // 0x45
+               SendCommand(&c);
+               if ( !WaitForResponseTimeout(CMD_ACK,&resp,1000) ) {return;}  
+               isOK  = resp.arg[0] & 0xff;
+               if ( !isOK ){
+                       PrintAndLog("   Can't select master application");      
+                       return;
+               }       
+
+               str = (resp.d.asBytes[3] & (1 << 3 )) ? "YES":"NO";     
+               PrintAndLog("   [0x08] Configuration changeable       : %s", str);
+               str = (resp.d.asBytes[3] & (1 << 2 )) ? "NO":"YES";
+               PrintAndLog("   [0x04] CMK required for create/delete : %s",str);
+               str = (resp.d.asBytes[3] & (1 << 1 )) ? "NO":"YES";
+               PrintAndLog("   [0x02] Directory list access with CMK : %s",str);
+               str = (resp.d.asBytes[3] & (1 << 0 )) ? "YES" : "NO";
+               PrintAndLog("   [0x01] CMK is changeable              : %s", str);
+                       
+               c.arg[LENPOS] = 0x02; //LEN
+               c.d.asBytes[0] = GET_KEY_VERSION; //0x64
+               c.d.asBytes[1] = 0x00;
+               SendCommand(&c);
+               if ( !WaitForResponseTimeout(CMD_ACK,&resp,1000) ) {
+                       return;
+               }
+               isOK  = resp.arg[0] & 0xff;
+               if ( !isOK ){
+                       PrintAndLog("   Can't read key-version");
+                       return;
+               }
+               PrintAndLog("");
+               PrintAndLog("   Max number of keys       : %d", resp.d.asBytes[4]);
+               PrintAndLog("   Master key Version       : %d (0x%02x)", resp.d.asBytes[3], resp.d.asBytes[3]);
+               PrintAndLog("   ----------------------------------------------------------");
+               
+               c.arg[LENPOS] = 0x02; //LEN
+               c.d.asBytes[0] = AUTHENTICATE; //0x0A
+               c.d.asBytes[1] = 0x00; // KEY 0
+               SendCommand(&c);
+               if ( !WaitForResponseTimeout(CMD_ACK,&resp,1000) ) {return;}
+               isOK  = resp.d.asBytes[2] & 0xff;
+               PrintAndLog("   [0x0A] Authenticate      : %s", ( isOK==0xAE ) ? "NO":"YES");
+
+               c.d.asBytes[0] = AUTHENTICATE_ISO; //0x1A
+               SendCommand(&c);
+               if ( !WaitForResponseTimeout(CMD_ACK,&resp,1000) ) {return;}
+               isOK  = resp.d.asBytes[2] & 0xff;
+               PrintAndLog("   [0x1A] Authenticate ISO  : %s", ( isOK==0xAE ) ? "NO":"YES");
+               
+               c.d.asBytes[0] = AUTHENTICATE_AES; //0xAA
+               SendCommand(&c);
+               if ( !WaitForResponseTimeout(CMD_ACK,&resp,1000) ) {return;}
+               isOK  = resp.d.asBytes[2] & 0xff;
+               PrintAndLog("   [0xAA] Authenticate AES  : %s", ( isOK==0xAE ) ? "NO":"YES");
+               PrintAndLog("");
+               PrintAndLog("   ----------------------------------------------------------");
+               
+       } else {
+               PrintAndLog(" AMK - Application Master Key settings");
+               
+               // SELECT AID
+               c.arg[0] = (INIT | CLEARTRACE);
+               c.arg[LENPOS] = 0x04;
+               c.d.asBytes[0] = SELECT_APPLICATION;  // 0x5a
+               memcpy(c.d.asBytes+1, aid, 3);
+               SendCommand(&c);
+               
+               if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
+                       PrintAndLog("   Timed-out");
+                       return;
+               } 
+               isOK  = resp.arg[0] & 0xff;
+               if ( !isOK ){
+                       PrintAndLog("   Can't select AID: %s",sprint_hex(aid,3));       
+                       return;
+               }               
+               
+               // KEY SETTINGS
+               options = NONE;
+               c.arg[0] = options;
+               c.arg[LENPOS] = 0x01;
+               c.d.asBytes[0] = GET_KEY_SETTINGS; // 0x45              
+               SendCommand(&c);
+               if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
+                       return;
+               }
+               isOK  = resp.arg[0] & 0xff;
+               if ( !isOK ){
+                       PrintAndLog("   Can't read Application Master key settings");
+               } else {
+                       // Access rights.
+                       uint8_t rights = (resp.d.asBytes[3] >> 4 && 0xff);
+                       switch (rights){
+                               case 0x00:
+                                       str = "AMK authentication is necessary to change any key (default)";
+                                       break;
+                               case 0x0e:
+                                       str = "Authentication with the key to be changed (same KeyNo) is necessary to change a key";
+                                       break;
+                               case 0x0f:
+                                       str = "All keys (except AMK,see Bit0) within this application are frozen";
+                                       break;
+                               default:
+                                       str = "Authentication with the specified key is necessary to change any ley. A change key and a PICC master key (CMK) can only be changed after authentication with the master key. For keys other then the master or change key, an authentication with the same key is needed.";
+                                       break;
+                       }
+                       PrintAndLog("Changekey Access rights");
+                       PrintAndLog("-- %s",str);
+                       PrintAndLog("");        
+                       // same as CMK
+                       str = (resp.d.asBytes[3] & (1 << 3 )) ? "YES":"NO";     
+                       PrintAndLog("   0x08 Configuration changeable       : %s", str);
+                       str = (resp.d.asBytes[3] & (1 << 2 )) ? "NO":"YES";
+                       PrintAndLog("   0x04 AMK required for create/delete : %s",str);
+                       str = (resp.d.asBytes[3] & (1 << 1 )) ? "NO":"YES";
+                       PrintAndLog("   0x02 Directory list access with AMK : %s",str);
+                       str = (resp.d.asBytes[3] & (1 << 0 )) ? "YES" : "NO";
+                       PrintAndLog("   0x01 AMK is changeable              : %s", str);
+               }
+               
+               // KEY VERSION  - AMK 
+               c.arg[0] = NONE;
+               c.arg[LENPOS] = 0x02;
+               c.d.asBytes[0] = GET_KEY_VERSION; //0x64
+               c.d.asBytes[1] = 0x00;
+               SendCommand(&c);
+               if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
+                       PrintAndLog("   Timed-out");
+                       return;
+               }
+               
+               int numOfKeys;
+               
+               isOK  = resp.arg[0] & 0xff;
+               if ( !isOK ){
+                       PrintAndLog("   Can't read Application Master key version. Trying all keys");
+                       numOfKeys = MAX_NUM_KEYS;
+               }
+               else{
+                       numOfKeys = resp.d.asBytes[4];
+                       PrintAndLog("");
+                       PrintAndLog("     Max number of keys  : %d", numOfKeys );
+                       PrintAndLog("     Application Master key Version  : %d (0x%02x)", resp.d.asBytes[3], resp.d.asBytes[3]);
+                       PrintAndLog("-------------------------------------------------------------");                   
+               }
+               
+               // LOOP over numOfKeys that we got before. 
+               // From 0x01 to numOfKeys.  We already got 0x00. (AMK)
+               for(int i=0x01; i<=0x0f; ++i){
+                                       
+               }
+               
+               
+       }
+}
+
+int CmdHF14ADesEnumApplications(const char *Cmd){
+       
+       uint8_t isOK = 0x00;
+       uint8_t aid[3];
+       uint32_t options = (INIT | DISCONNECT);
+       
+       UsbCommand c = {CMD_MIFARE_DESFIRE, {options , 0x01 }};
+       c.d.asBytes[0] = GET_APPLICATION_IDS;  //0x6a
+       
+    SendCommand(&c);
+       UsbCommand resp;
+               
+       if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
+               return 0;
+       }  
+       isOK  = resp.arg[0] & 0xff;
+       if ( !isOK ){
+               PrintAndLog("Command unsuccessful");
+               return 0;
+       } 
+       PrintAndLog("");        
+       PrintAndLog("-- Desfire Enumerate Applications ---------------------------");
+       PrintAndLog("-------------------------------------------------------------");
+
+       UsbCommand respAid;
+       UsbCommand respFiles;
+       
+       uint8_t num = 0;
+       int max = resp.arg[1] -3 -2;
+       
+       for(int i=3; i<=max; i+=3){
+               PrintAndLog(" Aid %d : %02X %02X %02X ",num ,resp.d.asBytes[i],resp.d.asBytes[i+1],resp.d.asBytes[i+2]);
+               num++;
+               
+               aid[0] = resp.d.asBytes[i];
+               aid[1] = resp.d.asBytes[i+1];
+               aid[2] = resp.d.asBytes[i+2];
+               GetKeySettings(aid);
+               
+               // Select Application
+               c.arg[CMDPOS] = INIT;
+               c.arg[LENPOS] = 0x04; 
+               c.d.asBytes[0] = SELECT_APPLICATION;  // 0x5a
+               c.d.asBytes[1] = resp.d.asBytes[i];
+               c.d.asBytes[2] = resp.d.asBytes[i+1];           
+               c.d.asBytes[3] = resp.d.asBytes[i+2];
+               SendCommand(&c);
+               
+               if (!WaitForResponseTimeout(CMD_ACK,&respAid,1500) ) {
+                       PrintAndLog("   Timed-out");
+                       continue;
+               } 
+               isOK  = respAid.d.asBytes[2] & 0xff;
+               if ( isOK != 0x00 ){
+                       PrintAndLog("   Can't select AID: %s",sprint_hex(resp.d.asBytes+i,3));  
+                       continue;
+               }
+       
+               // Get File IDs
+               c.arg[CMDPOS] = NONE;
+               c.arg[LENPOS] = 0x01;
+               c.d.asBytes[0] = GET_FILE_IDS; // 0x6f
+               SendCommand(&c);
+               
+               if ( !WaitForResponseTimeout(CMD_ACK,&respFiles,1500) ) {
+                       PrintAndLog("   Timed-out");
+                       continue;
+               } else {
+                       isOK  = respFiles.d.asBytes[2] & 0xff;
+                       if ( !isOK ){
+                               PrintAndLog("   Can't get file ids ");
+                       } else {                        
+                               int respfileLen = resp.arg[1]-3-2;                      
+                               for (int j=0; j< respfileLen; ++j){
+                                       PrintAndLog("   Fileid %d :", resp.d.asBytes[j+3]);
+                               }
+                       }
+               }
+               
+               // Get ISO File IDs
+               c.arg[CMDPOS] = DISCONNECT;
+               c.arg[LENPOS] = 0x01;
+               c.d.asBytes[0] = GET_ISOFILE_IDS; // 0x61
+               SendCommand(&c);
+               
+               if ( !WaitForResponseTimeout(CMD_ACK,&respFiles,1500) ) {
+                       PrintAndLog("   Timed-out");
+                       continue;
+               } else {
+                       isOK  = respFiles.d.asBytes[2] & 0xff;
+                       if ( !isOK ){
+                               PrintAndLog("   Can't get ISO file ids ");
+                       } else {                        
+                               int respfileLen = resp.arg[1]-3-2;                      
+                               for (int j=0; j< respfileLen; ++j){
+                                       PrintAndLog(" ISO  Fileid %d :", resp.d.asBytes[j+3]);
+                               }
+                       }
+               }
+               
+               
+       }
+       PrintAndLog("-------------------------------------------------------------");
+       
+       
+       return 1;
+}
+
+// MIAFRE DesFire Authentication
+//
+#define BUFSIZE 256 
+int CmdHF14ADesAuth(const char *Cmd){
+    
+       // NR  DESC             KEYLENGHT
+       // ------------------------
+       // 1 = DES              8
+       // 2 = 3DES             16
+       // 3 = 3K 3DES  24
+       // 4 = AES              16
+
+       uint8_t keylength = 8;
+       unsigned char key[24];  
+       
+    if (strlen(Cmd)<3) {
+        PrintAndLog("Usage:  hf mfdes auth <1|2|3> <1|2|3|4> <keyno> <key> ");
+               PrintAndLog("               Auth modes");
+               PrintAndLog("                 1 = normal, 2 = iso, 3 = aes");
+               PrintAndLog("               Crypto");
+               PrintAndLog("                 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES");
+               PrintAndLog("");
+        PrintAndLog("        sample: hf mfdes auth 1 1 0 11223344");
+               PrintAndLog("        sample: hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f");
+        return 0;
+    } 
+       uint8_t cmdAuthMode     = param_get8(Cmd,0);
+       uint8_t cmdAuthAlgo     = param_get8(Cmd,1);
+       uint8_t cmdKeyNo        = param_get8(Cmd,2);
+       
+       switch (cmdAuthMode)
+       {
+               case 1: 
+                       if ( cmdAuthAlgo != 1 && cmdAuthAlgo != 2) {
+                               PrintAndLog("Crypto algo not valid for the auth mode");
+                               return 1;
+                       }
+                       break;
+               case 2:
+                       if ( cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) {
+                               PrintAndLog("Crypto algo not valid for the auth mode");
+                               return 1;
+                       }
+                       break;
+               case 3:
+                       if ( cmdAuthAlgo != 4) {
+                               PrintAndLog("Crypto algo not valid for the auth mode");
+                               return 1;
+                       }
+                       break;
+               default:
+                       PrintAndLog("Wrong Auth mode");
+                       return 1;
+                       break;
+       }
+       
+       switch (cmdAuthAlgo){
+               case 2: 
+                       keylength = 16;
+                       PrintAndLog("3DES selected");
+                       break;
+               case 3: 
+                       keylength = 24;
+                       PrintAndLog("3 key 3DES selected");
+                       break;
+               case 4:
+                       keylength = 16;
+                       PrintAndLog("AES selected");
+                       break;
+               default:
+                       cmdAuthAlgo = 1;
+                       keylength = 8;
+                       PrintAndLog("DES selected");
+                       break;
+       }
+
+       // key
+       if (param_gethex(Cmd, 3, key, keylength*2)) {
+               PrintAndLog("Key must include %d HEX symbols", keylength);
+               return 1;
+       }
+       // algo, nyckellängd, 
+       UsbCommand c = {CMD_MIFARE_DESFIRE_AUTH1, { cmdAuthMode, cmdAuthAlgo, cmdKeyNo }};
+       
+       c.d.asBytes[0] = keylength;
+       memcpy(c.d.asBytes+1, key, keylength);
+       
+    SendCommand(&c);
+       UsbCommand resp;
+       
+       if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) {
+               PrintAndLog("Client command execute timeout");
+               return 0;
+       }  
+
+       uint8_t isOK  = resp.arg[0] & 0xff;
+       if ( isOK) {
+               uint8_t * data= resp.d.asBytes;
+               
+               PrintAndLog("  Key        :%s",sprint_hex(key, keylength));
+               PrintAndLog("  SESSION    :%s",sprint_hex(data, keylength));
+               PrintAndLog("-------------------------------------------------------------");
+               //PrintAndLog("  Expected   :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56");
+       } else{
+               PrintAndLog("Client command failed.");
+       }
+       PrintAndLog("-------------------------------------------------------------");   
+    return 1;
+}
+
+
+static command_t CommandTable[] =
+{
+  {"help",             CmdHelp,                                        1, "This help"},
+  {"info",             CmdHF14ADesInfo,                        0, "Get MIFARE DesFire information"},
+  {"enum",             CmdHF14ADesEnumApplications,0, "Tries enumerate all applications"},
+  {"auth",             CmdHF14ADesAuth,                        0, "Tries a MIFARE DesFire Authentication"},
+  {"rdbl",             CmdHF14ADesRb,                          0, "Read MIFARE DesFire block"},
+  {"wrbl",             CmdHF14ADesWb,                          0, "write MIFARE DesFire block"},
+  {NULL, NULL, 0, NULL}
+};
+
+int CmdHFMFDes(const char *Cmd)
+{
+   // flush
+   WaitForResponseTimeout(CMD_ACK,NULL,100);
+   CmdsParse(CommandTable, Cmd);
+  return 0;
+}
+
+int CmdHelp(const char *Cmd)
+{
+  CmdsHelp(CommandTable);
+  return 0;
+}
+
+
diff --git a/client/cmdhfmfdes.h b/client/cmdhfmfdes.h
new file mode 100644 (file)
index 0000000..c05f15d
--- /dev/null
@@ -0,0 +1,74 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2014 Iceman
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// High frequency MIFARE Desfire commands
+//-----------------------------------------------------------------------------
+
+int CmdHFMFDes(const char *Cmd);
+int CmdHF14ADesAuth(const char* cmd);
+int CmdHF14ADesRb(const char* cmd);
+int CmdHF14ADesWb(const char* cmd);
+int CmdHF14ADesInfo(const char *Cmd);
+int CmdHF14ADesEnumApplications(const char *Cmd);
+
+char * GetCardSizeStr( uint8_t fsize );
+char * GetProtocolStr(uint8_t id);
+void GetKeySettings( uint8_t * aid);
+
+// Command options for Desfire behavior.
+enum  {
+ NONE          =       0x00,
+ INIT          =       0x01,
+ DISCONNECT =  0x02,
+ CLEARTRACE    =       0x04,
+ BAR           =       0x08,
+} CmdOptions ;
+
+
+#define  CREATE_APPLICATION                     0xca
+#define  DELETE_APPLICATION                     0xda
+#define  GET_APPLICATION_IDS                    0x6a
+#define      SELECT_APPLICATION                 0x5a
+#define      FORMAT_PICC                                0xfc
+#define      GET_VERSION                                0x60
+#define      READ_DATA                                          0xbd
+#define      WRITE_DATA                                         0x3d
+#define      GET_VALUE                                          0x6c
+#define      CREDIT                                     0x0c
+#define      DEBIT                                              0xdc
+#define      LIMITED_CREDIT                     0x1c
+#define      WRITE_RECORD                               0x3b
+#define      READ_RECORDS                               0xbb
+#define     CLEAR_RECORD_FILE                   0xeb
+#define      COMMIT_TRANSACTION                 0xc7
+#define      ABORT_TRANSACTION                          0xa7
+#define      GET_FREE_MEMORY             0x6e
+#define        GET_FILE_IDS                             0x6f
+#define        GET_ISOFILE_IDS                          0x61
+#define     GET_FILE_SETTINGS                   0xf5
+#define     CHANGE_FILE_SETTINGS                0x5f
+#define     CREATE_STD_DATA_FILE                0xcd
+#define     CREATE_BACKUP_DATA_FILE     0xcb
+#define     CREATE_VALUE_FILE                   0xcc
+#define     CREATE_LINEAR_RECORD_FILE   0xc1
+#define     CREATE_CYCLIC_RECORD_FILE   0xc0
+#define     DELETE_FILE                                 0xdf
+#define     AUTHENTICATE                                0x0a  // AUTHENTICATE_NATIVE
+#define        AUTHENTICATE_ISO                         0x1a  // AUTHENTICATE_STANDARD
+#define        AUTHENTICATE_AES                         0xaa
+#define     CHANGE_KEY_SETTINGS                 0x54
+#define     GET_KEY_SETTINGS                    0x45
+#define     CHANGE_KEY                                          0xc4
+#define     GET_KEY_VERSION                     0x64
+#define     AUTHENTICATION_FRAME                0xAF
+
+#define MAX_NUM_KEYS 0x0F
+#define MAX_APPLICATION_COUNT 28
+#define MAX_FILE_COUNT 32
+#define MAX_FRAME_SIZE 60
+#define NOT_YET_AUTHENTICATED 255
+#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5)
\ No newline at end of file
diff --git a/client/cmdhfmfdesfire.c b/client/cmdhfmfdesfire.c
new file mode 100644 (file)
index 0000000..f2c53db
--- /dev/null
@@ -0,0 +1,250 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2014 Andy Davies
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// High frequency MIFARE commands
+//-----------------------------------------------------------------------------
+
+#include "cmdhfmf.h"
+#include "util.h"
+#include <openssl/des.h>
+#include <openssl/aes.h>
+
+static int CmdHelp(const char *Cmd);
+
+//DESFIRE
+// Reader 2 Card : 020A, key (1 byte), CRC1 CRC2 ; auth (020a00)
+// Card 2 Reader : 02AF, 8 Bytes(b0), CRC1 CRC2
+// Reader 2 Card : 03AF, 8 Bytes(b1),8 bytes(b2), CRC1 CRC2
+// Card 2 Reader : 0300, 8 bytes(b3), CRC1 CRC2 ; success
+
+//send 020A00, receive enc(nc)
+
+//02AE = error
+//receive b3=enc(r4)
+//r5=dec(b3)
+//n'r=rol(r5)
+//verify n'r=nr
+
+int CmdHF14AMfDESAuth(const char *Cmd){
+        
+    uint8_t blockNo = 0;
+    //keyNo=0;
+    uint32_t cuid=0;
+    uint8_t reply[16];
+    //DES_cblock r1_b1;
+    uint8_t b1[8]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    uint8_t b2[8]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    DES_cblock nr,  b0, r1, r0;
+    
+    
+    uint8_t key[8]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    //DES_cblock iv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    DES_key_schedule ks1;
+    DES_cblock key1;
+
+    if (strlen(Cmd)<1) {
+        PrintAndLog("Usage:  hf desfire des-auth k <key number>");
+        PrintAndLog("        sample: hf desfire des-auth k 0");
+        return 0;
+    } 
+    
+    //Change key to user defined one
+    
+    memcpy(key1,key,8);
+    //memcpy(key2,key+8,8);
+    DES_set_key((DES_cblock *)key1,&ks1);
+    //DES_set_key((DES_cblock *)key2,&ks2);
+        
+    //Auth1
+    UsbCommand c = {CMD_MIFARE_DES_AUTH1, {blockNo}};
+    SendCommand(&c);
+    UsbCommand resp;
+    if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+        uint8_t isOK  = resp.arg[0] & 0xff;
+               cuid  = resp.arg[1];
+        uint8_t * data= resp.d.asBytes;
+
+         if (isOK){
+             PrintAndLog("enc(nc)/b0:%s", sprint_hex(data+2,8));
+             memcpy(b0,data+2,8);
+       }
+    } else {
+        PrintAndLog("Command execute timeout");
+    }
+       
+    //Do crypto magic
+    DES_random_key(&nr);
+    //b1=dec(nr)
+    //r0=dec(b0)
+    DES_ecb_encrypt(&nr,&b1,&ks1,0);
+    DES_ecb_encrypt(&b0,&r0,&ks1,0);
+    //PrintAndLog("b1:%s",sprint_hex(b1, 8));
+    PrintAndLog("r0:%s",sprint_hex(r0, 8));
+    //r1=rol(r0)
+    memcpy(r1,r0,8);
+    rol(r1,8);
+    PrintAndLog("r1:%s",sprint_hex(r1, 8));
+    for(int i=0;i<8;i++){   
+      b2[i]=(r1[i] ^ b1[i]);
+    }
+    DES_ecb_encrypt(&b2,&b2,&ks1,0);
+    //PrintAndLog("b1:%s",sprint_hex(b1, 8));
+    PrintAndLog("b2:%s",sprint_hex(b2, 8));
+
+    //Auth2
+    UsbCommand d = {CMD_MIFARE_DES_AUTH2, {cuid}};
+    memcpy(reply,b1,8);
+    memcpy(reply+8,b2,8);
+    memcpy(d.d.asBytes,reply, 16);
+    SendCommand(&d);
+
+    UsbCommand respb;
+    if (WaitForResponseTimeout(CMD_ACK,&respb,1500)) {
+        uint8_t  isOK  = respb.arg[0] & 0xff;
+        uint8_t * data2= respb.d.asBytes;
+
+        if (isOK){
+            PrintAndLog("b3:%s", sprint_hex(data2+2, 8));
+       }
+                 
+    } else {
+        PrintAndLog("Command execute timeout");
+    } 
+    return 1;
+}
+
+//EV1
+// Reader 2 Card : 02AA, key (1 byte), CRC1 CRC2 ; auth
+// Card 2 Reader : 02AF, 16 Bytes(b0), CRC1 CRC2
+// Reader 2 Card : 03AF, 16 Bytes(b1),16Bytes(b2) CRC1 CRC2
+// Card 2 Reader : 0300, 16 bytes(b3), CRC1 CRC2 ; success
+int CmdHF14AMfAESAuth(const char *Cmd){
+        
+    uint8_t blockNo = 0;
+    //keyNo=0;
+    uint32_t cuid=0;
+    uint8_t reply[32];
+    //DES_cblock r1_b1;
+    //unsigned char * b1, b2, nr, b0, r0, r1;
+    
+    uint8_t b1[16]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    uint8_t b2[16]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    uint8_t nr[16]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    uint8_t b0[16]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    uint8_t r0[16]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    uint8_t r1[16]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    //
+    uint8_t key[16]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    uint8_t iv[16]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+    AES_KEY key_e;
+    AES_KEY key_d;
+
+    if (strlen(Cmd)<1) {
+        PrintAndLog("Usage:  hf desfire aes-auth k <key number>");
+        PrintAndLog("        sample: hf desfire aes-auth k 0");
+        return 0;
+    } 
+    
+    //Change key to user defined one
+    //
+    // int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits,AES_KEY *key);
+     //int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits,AES_KEY *key);
+       //
+    //memcpy(key1,key,16);
+    //memcpy(key2,key+8,8);
+    AES_set_encrypt_key(key,128,&key_e);
+    AES_set_decrypt_key(key,128,&key_d);
+        
+    //Auth1
+    UsbCommand c = {CMD_MIFARE_DES_AUTH1, {blockNo}};
+    SendCommand(&c);
+    UsbCommand resp;
+    if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+        uint8_t isOK  = resp.arg[0] & 0xff;
+               cuid  = resp.arg[1];
+        uint8_t * data= resp.d.asBytes;
+
+         if (isOK){
+             PrintAndLog("enc(nc)/b0:%s", sprint_hex(data+2,16));
+             memcpy(b0,data+2,16);
+       }
+    } else {
+        PrintAndLog("Command execute timeout");
+    }
+    //
+    // void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+       //size_t length, const AES_KEY *key,
+       //unsigned char *ivec, const int enc);
+    
+   //Do crypto magic
+    //DES_random_key(&nr);
+    //b1=dec(nr)
+    //r0=dec(b0)
+    //AES_cbc_encrypt(&nr,&b1,16,&key,0);
+    AES_cbc_encrypt(&b0,&r0,16,&key_d,iv,0);
+    //PrintAndLog("b1:%s",sprint_hex(b1, 8));
+    PrintAndLog("r0:%s",sprint_hex(r0, 16));
+    //r1=rol(r0)
+    memcpy(r1,r0,16);
+    rol(r1,8);
+    PrintAndLog("r1:%s",sprint_hex(r1, 16));
+    for(int i=0;i<16;i++){
+      b1[i]=(nr[i] ^ b0[i]);
+      b2[i]=(r1[i] ^ b1[i]);
+    }
+    PrintAndLog("nr:%s",sprint_hex(nr, 16));
+    AES_cbc_encrypt(&b1,&b1,16,&key_e,iv,1);
+    AES_cbc_encrypt(&b2,&b2,16,&key_e,iv,1);
+    PrintAndLog("b1:%s",sprint_hex(b1, 16));
+    PrintAndLog("b2:%s",sprint_hex(b2, 16));
+
+    //Auth2
+    UsbCommand d = {CMD_MIFARE_DES_AUTH2, {cuid}};
+    memcpy(reply,b1,16);
+    memcpy(reply+16,b2,16);
+    memcpy(d.d.asBytes,reply, 32);
+    SendCommand(&d);
+
+    UsbCommand respb;
+    if (WaitForResponseTimeout(CMD_ACK,&respb,1500)) {
+        uint8_t  isOK  = respb.arg[0] & 0xff;
+        uint8_t * data2= respb.d.asBytes;
+
+        if (isOK){
+            PrintAndLog("b3:%s", sprint_hex(data2+2, 16));
+       }
+                 
+    } else {
+        PrintAndLog("Command execute timeout");
+    } 
+    return 1;
+}
+
+
+//------------------------------------
+// Menu Stuff
+//------------------------------------
+static command_t CommandTable[] =
+{
+    {"help",    CmdHelp,               1,"This help"},
+    {"dbg",     CmdHF14AMfDbg,         0,"Set default debug mode"},
+    {"des-auth",CmdHF14AMfDESAuth,     0,"Desfire Authentication"},
+    {"ev1-auth",CmdHF14AMfAESAuth,     0,"EV1 Authentication"},
+    {NULL, NULL, 0, NULL}
+};
+
+int CmdHFMFDesfire(const char *Cmd){
+    // flush
+    WaitForResponseTimeout(CMD_ACK,NULL,100);
+    CmdsParse(CommandTable, Cmd);
+    return 0;
+}
+
+int CmdHelp(const char *Cmd){
+    CmdsHelp(CommandTable);
+    return 0;
+}
diff --git a/client/cmdhfmfdesfire.h b/client/cmdhfmfdesfire.h
new file mode 100644 (file)
index 0000000..c29fd26
--- /dev/null
@@ -0,0 +1,5 @@
+
+static int CmdHelp(const char *Cmd);
+int CmdHF14AMfDESAuth(const char *Cmd);
+int CmdHFMFDesfire(const char *Cmd);
+int CmdHelp(const char *Cmd);
\ No newline at end of file
index 48f549ba8334f4ecbd0fb97180c120ace6a73993..8b5dca829efb4c48236994fda5bd474552821872 100644 (file)
 #include "protocols.h"
 #include "data.h"
 
-#define MAX_UL_BLOCKS      0x0f
-#define MAX_ULC_BLOCKS     0x2b
-#define MAX_ULEV1a_BLOCKS  0x13
-#define MAX_ULEV1b_BLOCKS  0x28
-#define MAX_NTAG_203       0x29
-#define MAX_NTAG_210       0x13
-#define MAX_NTAG_212       0x28
-#define MAX_NTAG_213       0x2c
-#define MAX_NTAG_215       0x86
-#define MAX_NTAG_216       0xe6
+#define MAX_UL_BLOCKS     0x0f
+#define MAX_ULC_BLOCKS    0x2b
+#define MAX_ULEV1a_BLOCKS 0x13
+#define MAX_ULEV1b_BLOCKS 0x28
+#define MAX_NTAG_203      0x29
+#define MAX_NTAG_210      0x13
+#define MAX_NTAG_212      0x28
+#define MAX_NTAG_213      0x2c
+#define MAX_NTAG_215      0x86
+#define MAX_NTAG_216      0xe6
 #define MAX_MY_D_NFC       0xff
 #define MAX_MY_D_MOVE      0x25
 #define MAX_MY_D_MOVE_LEAN 0x0f
@@ -129,24 +129,7 @@ static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uin
        memcpy(response, resp.d.asBytes, resplen);
        return resplen;
 }
-/*
-static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength, bool append_crc ) {
-       UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT , cmdlen, 0}};
-       if (append_crc)
-               c.arg[0] |= ISO14A_APPEND_CRC;
 
-       memcpy(c.d.asBytes, cmd, cmdlen);       
-       clearCommandBuffer();
-       SendCommand(&c);
-       UsbCommand resp;
-       if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1;
-       if (!resp.arg[0] && responseLength) return -1;
-
-       uint16_t resplen = (resp.arg[0] < responseLength) ? resp.arg[0] : responseLength;
-       memcpy(response, resp.d.asBytes, resplen);
-       return resplen;
-}
-*/
 static int ul_select( iso14a_card_select_t *card ){
 
        ul_switch_on_field();
@@ -335,7 +318,9 @@ static int ndef_print_CC(uint8_t *data) {
        PrintAndLog("  %02X : NDEF Magic Number", data[0]); 
        PrintAndLog("  %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
        PrintAndLog("  %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8);
-       if ( data[2] == 0x12 )
+       if ( data[2] == 0x96 )
+               PrintAndLog("  %02X : NDEF Memory Size: %d bytes", data[2], 48);
+       else if ( data[2] == 0x12 )
                PrintAndLog("  %02X : NDEF Memory Size: %d bytes", data[2], 144);
        else if ( data[2] == 0x3e )
                PrintAndLog("  %02X : NDEF Memory Size: %d bytes", data[2], 496);
@@ -380,13 +365,13 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces){
        else if ( tagtype & NTAG_I2C_2K )       
                PrintAndLog("%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD");
        else if ( tagtype & MY_D )
-               PrintAndLog("%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer);
+               PrintAndLog("%sTYPE : INFINEON my-d\0153 (SLE 66RxxS)", spacer);
        else if ( tagtype & MY_D_NFC )
-               PrintAndLog("%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer);
+               PrintAndLog("%sTYPE : INFINEON my-d\0153 NFC (SLE 66RxxP)", spacer);
        else if ( tagtype & MY_D_MOVE )
-               PrintAndLog("%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer);
+               PrintAndLog("%sTYPE : INFINEON my-d\0153 move (SLE 66R01P)", spacer);
        else if ( tagtype & MY_D_MOVE_NFC )
-               PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer);
+               PrintAndLog("%sTYPE : INFINEON my-d\0153 move NFC (SLE 66R01P)", spacer);
        else if ( tagtype & MY_D_MOVE_LEAN )
                PrintAndLog("%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer);
        else
@@ -857,7 +842,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
 //
 int CmdHF14AMfUWrBl(const char *Cmd){
 
-       int blockNo = -1;
+       int blockNo = -1;       
        bool errors = false;
        bool hasAuthKey = false;
        bool hasPwdKey = false;
@@ -869,11 +854,11 @@ int CmdHF14AMfUWrBl(const char *Cmd){
        uint8_t data[16] = {0x00};
        uint8_t authenticationkey[16] = {0x00};
        uint8_t *authKeyPtr = authenticationkey;
-
+       
        // starting with getting tagtype
        TagTypeUL_t tagtype = GetHF14AMfU_Type();
        if (tagtype == UL_ERROR) return -1;
-
+       
        while(param_getchar(Cmd, cmdp) != 0x00)
        {
                switch(param_getchar(Cmd, cmdp))
@@ -914,11 +899,11 @@ int CmdHF14AMfUWrBl(const char *Cmd){
                
                                if (blockNo < 0) {
                                        PrintAndLog("Wrong block number");
-                                       errors = true;
+                                       errors = true;                                  
                                }
                                if (blockNo > maxblockno){
                                        PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
-                                       errors = true;
+                                       errors = true;                                                                  
                                }
                                cmdp += 2;
                                break;
@@ -946,21 +931,21 @@ int CmdHF14AMfUWrBl(const char *Cmd){
        }
 
        if ( blockNo == -1 ) return usage_hf_mfu_wrbl();
-
+       
        // Swap endianness 
        if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8);
        if (swapEndian && hasPwdKey)  authKeyPtr = SwapEndian64(authenticationkey, 4, 4);
 
-       if ( blockNo <= 3)
+       if ( blockNo <= 3)              
                PrintAndLog("Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4));
        else
                PrintAndLog("Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4));
-
+       
        //Send write Block
        UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}};
        memcpy(c.d.asBytes,blockdata,4);
 
-       if ( hasAuthKey ) {
+       if ( hasAuthKey ){
                c.arg[1] = 1;
                memcpy(c.d.asBytes+4,authKeyPtr,16);
        }
@@ -968,7 +953,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){
                c.arg[1] = 2;
                memcpy(c.d.asBytes+4,authKeyPtr,4);
        }
-
+       
        clearCommandBuffer();
        SendCommand(&c);
        UsbCommand resp;
@@ -978,7 +963,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){
        } else {
                PrintAndLog("Command execute timeout");
        }
-
+       
        return 0;
 }
 //
@@ -1000,7 +985,7 @@ int CmdHF14AMfURdBl(const char *Cmd){
        // starting with getting tagtype
        TagTypeUL_t tagtype = GetHF14AMfU_Type();
        if (tagtype == UL_ERROR) return -1;
-
+       
        while(param_getchar(Cmd, cmdp) != 0x00)
        {
                switch(param_getchar(Cmd, cmdp))
@@ -1032,28 +1017,28 @@ int CmdHF14AMfURdBl(const char *Cmd){
                        case 'b':
                        case 'B':
                                blockNo = param_get8(Cmd, cmdp+1);
-
+                               
                                uint8_t maxblockno = 0;
                                for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){
                                        if (tagtype & UL_TYPES_ARRAY[idx])
                                                maxblockno = UL_MEMORY_ARRAY[idx];
                                }
-
+               
                                if (blockNo < 0) {
                                        PrintAndLog("Wrong block number");
-                                       errors = true;
+                                       errors = true;                                  
                                }
                                if (blockNo > maxblockno){
                                        PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
-                                       errors = true;
+                                       errors = true;                                                                  
                                }
                                cmdp += 2;
                                break;
                        case 'l':
                        case 'L':
                                swapEndian = true;
-                               cmdp++;
-                               break;
+                               cmdp++; 
+                               break;                          
                        default:
                                PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
                                errors = true;
@@ -1064,11 +1049,11 @@ int CmdHF14AMfURdBl(const char *Cmd){
        }
 
        if ( blockNo == -1 ) return usage_hf_mfu_rdbl();
-
+       
        // Swap endianness 
        if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8);
        if (swapEndian && hasPwdKey)  authKeyPtr = SwapEndian64(authenticationkey, 4, 4);
-
+       
        //Read Block
        UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}};
        if ( hasAuthKey ){
@@ -1079,7 +1064,7 @@ int CmdHF14AMfURdBl(const char *Cmd){
                c.arg[1] = 2;
                memcpy(c.d.asBytes,authKeyPtr,4);
        }
-
+       
        clearCommandBuffer();
        SendCommand(&c);
        UsbCommand resp;
@@ -1156,7 +1141,7 @@ int usage_hf_mfu_rdbl(void) {
 int usage_hf_mfu_wrbl(void) {
        PrintAndLog("Write a block. It autodetects card type.\n");              
        PrintAndLog("Usage:  hf mfu wrbl b <block number> d <data> k <key> l\n");
-       PrintAndLog("  Options:");
+       PrintAndLog("  Options:");      
        PrintAndLog("  b <no>   : block to write");
        PrintAndLog("  d <data> : block data - (8 hex symbols)");
        PrintAndLog("  k <key>  : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]");
@@ -1343,11 +1328,11 @@ int CmdHF14AMfUDump(const char *Cmd){
                }
                switch(i){
                        case 3: tmplockbit = bit[4]; break;
-                       case 4: tmplockbit = bit[3]; break;
-                       case 5: tmplockbit = bit[2]; break;
-                       case 6: tmplockbit = bit[1]; break;
-                       case 7: tmplockbit = bit[0]; break;
-                       case 8: tmplockbit = bit[15]; break;
+                       case 4: tmplockbit = bit[3]; break;
+                       case 5: tmplockbit = bit[2]; break;
+                       case 6: tmplockbit = bit[1]; break;
+                       case 7: tmplockbit = bit[0]; break;
+                       case 8: tmplockbit = bit[15]; break;
                        case 9: tmplockbit = bit[14]; break;
                        case 10: tmplockbit = bit[13]; break;
                        case 11: tmplockbit = bit[12]; break;
@@ -1558,10 +1543,10 @@ int CmdTestDES(const char * cmd)
 //
 int CmdHF14AMfucSetPwd(const char *Cmd){
 
-       uint8_t pwd[16] = {0x00};
+       uint8_t pwd[16] = {0x00};       
        
        char cmdp = param_getchar(Cmd, 0);
-       
+
        if (strlen(Cmd) == 0  || cmdp == 'h' || cmdp == 'H') {  
                PrintAndLog("Usage:  hf mfu setpwd <password (32 hex symbols)>");
                PrintAndLog("       [password] - (32 hex symbols)");
@@ -1633,7 +1618,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){
                PrintAndLog("Command execute timeout");
                return 2;
        }
-       
+
        // save old block2.
        uint8_t oldblock2[4] = {0x00};
        memcpy(resp.d.asBytes, oldblock2, 4);
@@ -1651,7 +1636,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){
                PrintAndLog("Command execute timeout");
                return 3;
        }
-       
+
        // block 1.
        c.arg[0] = 1;
        c.d.asBytes[0] = uid[3];
@@ -1682,10 +1667,10 @@ int CmdHF14AMfucSetUid(const char *Cmd){
 }
 
 int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
-
+       
        uint8_t iv[8] = { 0x00 };
        uint8_t block = 0x07;
-
+       
        // UL-EV1
        //04 57 b6 e2 05 3f 80 UID
        //4a f8 4b 19   PWD
@@ -1699,14 +1684,14 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
        
        uint8_t mix[8] = { 0x00 };
        uint8_t divkey[8] = { 0x00 };
-
+       
        memcpy(mix, mifarekeyA, 4);
-
+       
        mix[4] = mifarekeyA[4] ^ uid[0];
        mix[5] = mifarekeyA[5] ^ uid[1];
        mix[6] = block ^ uid[2];
        mix[7] = uid[3];
-
+       
        des3_context ctx = { 0x00 };
        des3_set2key_enc(&ctx, masterkey);
 
@@ -1725,9 +1710,9 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
        PrintAndLog("Mifare key   :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA)));
        PrintAndLog("Message      :\t %s", sprint_hex(mix, sizeof(mix)));
        PrintAndLog("Diversified key: %s", sprint_hex(divkey+1, 6));
-
+               
        PrintAndLog("\n DES version");
-
+       
        for (int i=0; i < sizeof(mifarekeyA); ++i){
                dkeyA[i] = (mifarekeyA[i] << 1) & 0xff;
                dkeyA[6] |=  ((mifarekeyA[i] >> 7) & 1) << (i+1);
@@ -1745,7 +1730,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
        memcpy(dmkey+8, dkeyB, 8);
        memcpy(dmkey+16, dkeyA, 8);
        memset(iv, 0x00, 8);
-
+       
        des3_set3key_enc(&ctx, dmkey);
 
        des3_crypt_cbc(&ctx  // des3_context
@@ -1790,7 +1775,7 @@ static command_t CommandTable[] =
        {"info",        CmdHF14AMfUInfo,        0, "Tag information"},
        {"dump",        CmdHF14AMfUDump,        0, "Dump Ultralight / Ultralight-C / NTAG tag to binary file"},
        {"rdbl",        CmdHF14AMfURdBl,        0, "Read block"},
-       {"wrbl",        CmdHF14AMfUWrBl,        0, "Write block"},
+       {"wrbl",        CmdHF14AMfUWrBl,        0, "Write block"},    
        {"cauth",       CmdHF14AMfucAuth,       0, "Authentication    - Ultralight C"},
        {"setpwd",      CmdHF14AMfucSetPwd, 1, "Set 3des password - Ultralight-C"},
        {"setuid",      CmdHF14AMfucSetUid, 1, "Set UID - MAGIC tags only"},
diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c
new file mode 100644 (file)
index 0000000..4e9d538
--- /dev/null
@@ -0,0 +1,414 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2015 Piwi
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// High frequency Topaz (NFC Type 1) commands
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "cmdmain.h"
+#include "cmdparser.h"
+#include "cmdhftopaz.h"
+#include "cmdhf14a.h"
+#include "ui.h"
+#include "mifare.h"
+#include "proxmark3.h"
+#include "iso14443crc.h"
+#include "protocols.h"
+
+#define TOPAZ_MAX_MEMORY       2048
+
+static struct {
+       uint8_t HR01[2];
+       uint8_t uid[7];
+       uint8_t size;
+       uint8_t data_blocks[TOPAZ_MAX_MEMORY/8][8];
+       uint8_t *dynamic_lock_areas;
+       uint8_t *dynamic_reserved_areas;
+} topaz_tag;
+
+
+static void topaz_switch_on_field(void)
+{
+       UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_SELECT | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, 0, 0}};
+       SendCommand(&c);
+}
+
+
+static void topaz_switch_off_field(void)
+{
+       UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
+       SendCommand(&c);
+}
+
+
+static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response)
+{
+       UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_TOPAZMODE, len, 0}};
+       memcpy(c.d.asBytes, cmd, len);
+       SendCommand(&c);
+
+       UsbCommand resp;
+       WaitForResponse(CMD_ACK, &resp);
+
+       if (resp.arg[0] > 0) {
+               memcpy(response, resp.d.asBytes, resp.arg[0]);
+       }
+       
+       return resp.arg[0];
+}
+
+
+static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response)
+{
+       if (len > 1) {
+        uint8_t first, second;
+               ComputeCrc14443(CRC_14443_B, cmd, len-2, &first, &second);
+        cmd[len-2] = first;
+        cmd[len-1] = second;
+       }
+
+       return topaz_send_cmd_raw(cmd, len, response);
+}
+
+
+static int topaz_select(uint8_t *atqa, uint8_t *rid_response)
+{
+       // ToDo: implement anticollision
+
+       uint8_t wupa_cmd[] = {TOPAZ_WUPA};
+       uint8_t rid_cmd[] = {TOPAZ_RID, 0, 0, 0, 0, 0, 0, 0, 0};
+
+       topaz_switch_on_field();
+
+       if (!topaz_send_cmd(wupa_cmd, sizeof(wupa_cmd), atqa)) {
+               topaz_switch_off_field();
+               return -1;              // WUPA failed
+       }
+
+       if (!topaz_send_cmd(rid_cmd, sizeof(rid_cmd), rid_response)) {
+               topaz_switch_off_field();
+               return -2;              // RID failed
+       }
+       
+       return 0;               // OK
+}
+
+
+static int topaz_rall(uint8_t *uid, uint8_t *response)
+{
+       uint8_t rall_cmd[] = {TOPAZ_RALL, 0, 0, 0, 0, 0, 0, 0, 0};
+
+       memcpy(&rall_cmd[3], uid, 4);
+       if (!topaz_send_cmd(rall_cmd, sizeof(rall_cmd), response)) {
+               topaz_switch_off_field();
+               return -1;              // RALL failed
+       }
+       
+       return 0;
+}
+
+
+static bool topaz_block_is_locked(uint8_t blockno, uint8_t *lockbits)
+{
+       if(lockbits[blockno/8] >> (blockno % 8) & 0x01) {
+               return true;
+       } else {
+               return false;
+       }
+}
+
+
+static int topaz_print_CC(uint8_t *data)
+{
+       if(data[0] != 0xe1) {
+               return -1;              // no NDEF message
+       }
+
+       PrintAndLog("Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
+       PrintAndLog("  %02x: NDEF Magic Number", data[0]); 
+       PrintAndLog("  %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
+       PrintAndLog("  %02x: Physical Memory Size of this tag: %d bytes", data[2], (data[2] + 1) * 8);
+       PrintAndLog("  %02x: %s / %s", data[3], 
+                               (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", 
+                               (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)");
+       return 0;                               
+}
+
+
+static void get_TLV(uint8_t **TLV_ptr, uint8_t *tag, uint16_t *length, uint8_t **value)
+{
+       *length = 0;
+       *value = NULL;
+
+       *tag = **TLV_ptr;
+       *TLV_ptr += 1;
+       switch (*tag) {
+               case 0x00:                      // NULL TLV.
+               case 0xFE:                      // Terminator TLV.
+                       break;
+               case 0x01:                      // Lock Control TLV
+               case 0x02:                      // Reserved Memory TLV
+               case 0x03:                      // NDEF message TLV
+               case 0xFD:                      // proprietary TLV
+                       *length = **TLV_ptr;
+                       *TLV_ptr += 1;
+                       if (*length == 0xff) {
+                               *length = **TLV_ptr << 8;
+                               *TLV_ptr += 1;
+                               *length |= **TLV_ptr;
+                               *TLV_ptr += 1;
+                       }
+                       *value = *TLV_ptr;
+                       *TLV_ptr += *length;
+                       break;
+               default:                        // RFU
+                       break;
+       }
+}
+
+
+static bool topaz_print_lock_control_TLVs(uint8_t *memory)
+{
+       uint8_t *TLV_ptr = memory;
+       uint8_t tag = 0;
+       uint16_t length;
+       uint8_t *value;
+       bool lock_TLV_present = false;
+       
+       while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) {       
+               // all Lock Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV)
+               get_TLV(&TLV_ptr, &tag, &length, &value);
+               if (tag == 0x01) {                      // the Lock Control TLV
+                       uint8_t pages_addr = value[0] >> 4;
+                       uint8_t byte_offset = value[0] & 0x0f;
+                       uint8_t size_in_bits = value[1] ? value[1] : 256;
+                       uint8_t bytes_per_page = 1 << (value[2] & 0x0f);
+                       uint8_t bytes_locked_per_bit = 1 << (value[2] >> 4);
+                       PrintAndLog("Lock Area of %d bits at byte offset 0x%02x. Each Lock Bit locks %d bytes.", 
+                                               size_in_bits,
+                                               pages_addr * bytes_per_page + byte_offset,
+                                               bytes_locked_per_bit);
+                       lock_TLV_present = true;
+               }
+       }
+       
+       if (!lock_TLV_present) {
+               PrintAndLog("(No Lock Control TLV present)");
+               return -1;
+       } else {
+               return 0;
+       }
+}
+
+
+static int topaz_print_reserved_memory_control_TLVs(uint8_t *memory)
+{
+       uint8_t *TLV_ptr = memory;
+       uint8_t tag = 0;
+       uint16_t length;
+       uint8_t *value;
+       bool reserved_memory_control_TLV_present = false;
+       
+       while(*TLV_ptr != 0x03 && *TLV_ptr != 0xFD && *TLV_ptr != 0xFE) {       
+               // all Reserved Memory Control TLVs shall be present before the NDEF message TLV, the proprietary TLV (and the Terminator TLV)
+               get_TLV(&TLV_ptr, &tag, &length, &value);
+               if (tag == 0x02) {                      // the Reserved Memory Control TLV
+                       uint8_t pages_addr = value[0] >> 4;
+                       uint8_t byte_offset = value[0] & 0x0f;
+                       uint8_t size_in_bytes = value[1] ? value[1] : 256;
+                       uint8_t bytes_per_page = 1 << (value[2] & 0x0f);
+                       PrintAndLog("Reserved Memory of %d bytes at byte offset 0x%02x.", 
+                                               size_in_bytes,
+                                               pages_addr * bytes_per_page + byte_offset);
+                       reserved_memory_control_TLV_present = true;
+               }
+       }
+       
+       if (!reserved_memory_control_TLV_present) {
+               PrintAndLog("(No Reserved Memory Control TLV present)");
+               return -1;
+       } else {
+               return 0;
+       }
+}
+
+
+static void topaz_print_lifecycle_state(uint8_t *data)
+{
+
+}
+
+
+static void topaz_print_NDEF(uint8_t *data)
+{
+
+}
+
+       
+int CmdHFTopazReader(const char *Cmd)
+{
+       int status;
+       uint8_t atqa[2];
+       uint8_t rid_response[8];
+       uint8_t *uid_echo = &rid_response[2];
+       uint8_t rall_response[124];
+       
+       status = topaz_select(atqa, rid_response);
+       
+       if (status == -1) {
+               PrintAndLog("Error: couldn't receive ATQA");
+               return -1;
+       }
+
+       PrintAndLog("ATQA : %02x %02x", atqa[1], atqa[0]);
+       if (atqa[1] != 0x0c && atqa[0] != 0x00) {
+               PrintAndLog("Tag doesn't support the Topaz protocol.");
+               topaz_switch_off_field();
+               return -1;
+       }
+       
+       if (status == -2) {
+               PrintAndLog("Error: tag didn't answer to RID");
+               topaz_switch_off_field();
+               return -1;
+       }
+
+       topaz_tag.HR01[0] = rid_response[0];
+       topaz_tag.HR01[1] = rid_response[1];
+       
+       // ToDo: CRC check
+       PrintAndLog("HR0  : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", rid_response[0], 
+                                               (rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
+                                               (rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
+                                               (rid_response[0] & 0x0F) == 0x10 ? "static" : "dynamic");
+       PrintAndLog("HR1  : %02x", rid_response[1]);
+       
+       status = topaz_rall(uid_echo, rall_response);
+
+       if(status == -1) {
+               PrintAndLog("Error: tag didn't answer to RALL");
+               topaz_switch_off_field();
+               return -1;
+       }
+
+       memcpy(topaz_tag.uid, rall_response+2, 7);
+       PrintAndLog("UID  : %02x %02x %02x %02x %02x %02x %02x", 
+                       topaz_tag.uid[6], 
+                       topaz_tag.uid[5], 
+                       topaz_tag.uid[4], 
+                       topaz_tag.uid[3], 
+                       topaz_tag.uid[2], 
+                       topaz_tag.uid[1], 
+                       topaz_tag.uid[0]);
+       PrintAndLog("       UID[6] (Manufacturer Byte) = %02x, Manufacturer: %s", 
+                       topaz_tag.uid[6], 
+                       getTagInfo(topaz_tag.uid[6]));
+       
+       memcpy(topaz_tag.data_blocks, rall_response+2, 0x10*8);
+       PrintAndLog("");
+       PrintAndLog("Static Data blocks 00 to 0c:");
+       PrintAndLog("block# | offset | Data                    | Locked?");
+       char line[80];
+       for (uint16_t i = 0; i <= 0x0c; i++) {
+               for (uint16_t j = 0; j < 8; j++) {
+                       sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[i][j] /*rall_response[2 + 8*i + j]*/);
+               }
+               PrintAndLog("  0x%02x |  0x%02x  | %s|   %-3s", i, i*8, line, topaz_block_is_locked(i, &topaz_tag.data_blocks[0x0e][0]) ? "yes" : "no");
+       }
+       
+       PrintAndLog("");
+       PrintAndLog("Static Reserved block 0d:");
+       for (uint16_t j = 0; j < 8; j++) {
+               sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[0x0d][j]);
+       }
+       PrintAndLog("  0x%02x |  0x%02x  | %s|   %-3s", 0x0d, 0x0d*8, line, "n/a");
+       
+       PrintAndLog("");
+       PrintAndLog("Static Lockbits and OTP Bytes:");
+       for (uint16_t j = 0; j < 8; j++) {
+               sprintf(&line[3*j], "%02x ", topaz_tag.data_blocks[0x0e][j]);
+       }
+       PrintAndLog("  0x%02x |  0x%02x  | %s|   %-3s", 0x0e, 0x0e*8, line, "n/a");
+
+       PrintAndLog("");
+
+       status = topaz_print_CC(&topaz_tag.data_blocks[1][0]);
+       
+       if (status == -1) {
+               PrintAndLog("No NDEF message present");
+               topaz_switch_off_field();
+               return 0;
+       }
+
+       PrintAndLog("");
+       bool lock_TLV_present = topaz_print_lock_control_TLVs(&topaz_tag.data_blocks[1][4]);
+       if ( lock_TLV_present ) {
+               PrintAndLog("");        
+       }
+       
+       PrintAndLog("");
+       bool reserved_mem_present = topaz_print_reserved_memory_control_TLVs(&topaz_tag.data_blocks[1][4]);
+       if (reserved_mem_present) {
+               PrintAndLog("");        
+       }
+       
+       topaz_print_lifecycle_state(&topaz_tag.data_blocks[1][0]);
+
+       topaz_print_NDEF(&topaz_tag.data_blocks[1][0]);
+       
+       topaz_switch_off_field();
+       return 0;
+}
+
+
+int CmdHFTopazSim(const char *Cmd)
+{
+       PrintAndLog("not yet implemented");
+       return 0;
+}
+
+
+int CmdHFTopazCmdRaw(const char *Cmd)
+{
+       PrintAndLog("not yet implemented");
+       return 0;
+}
+
+
+static int CmdHelp(const char *Cmd);
+
+
+static command_t CommandTable[] = 
+{
+       {"help",        CmdHelp,                        1, "This help"},
+       {"reader",      CmdHFTopazReader,       0, "Act like a Topaz reader"},
+       {"sim",         CmdHFTopazSim,          0, "<UID> -- Simulate Topaz tag"},
+       {"sniff",       CmdHF14ASniff,          0, "Sniff Topaz reader-tag communication"},
+       {"raw",         CmdHFTopazCmdRaw,       0, "Send raw hex data to tag"},
+       {NULL,          NULL,                           0, NULL}
+};
+
+
+int CmdHFTopaz(const char *Cmd) {
+       // flush
+       WaitForResponseTimeout(CMD_ACK,NULL,100);
+
+       // parse
+       CmdsParse(CommandTable, Cmd);
+       return 0;
+}
+
+static int CmdHelp(const char *Cmd)
+{
+       CmdsHelp(CommandTable);
+       return 0;
+}
+
+
diff --git a/client/cmdhftopaz.h b/client/cmdhftopaz.h
new file mode 100644 (file)
index 0000000..8d5428d
--- /dev/null
@@ -0,0 +1,16 @@
+//-----------------------------------------------------------------------------
+// Copyright (C) 2015 Piwi
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// High frequency Topaz (NFC Type 1) commands
+//-----------------------------------------------------------------------------
+
+#ifndef CMDHFTOPAZ_H__
+#define CMDHFTOPAZ_H__
+
+int CmdHFTopaz(const char *Cmd);
+
+#endif
index edf029325ddbe8e353197cdbc667681e14acadc2..aa7f63a9c0830fc6bdfcab57296fc5250529f30a 100644 (file)
@@ -35,326 +35,326 @@ static int CmdHelp(const char *Cmd);
 /* send a command before reading */
 int CmdLFCommandRead(const char *Cmd)
 {
-       static char dummy[3];
+  static char dummy[3];
 
-       dummy[0]= ' ';
+  dummy[0]= ' ';
 
-       UsbCommand c = {CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K};
-       sscanf(Cmd, "%"lli" %"lli" %"lli" %s %s", &c.arg[0], &c.arg[1], &c.arg[2],(char*)(&c.d.asBytes),(char*)(&dummy+1));
-       // in case they specified 'h'
-       strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);
-       SendCommand(&c);
-       return 0;
+  UsbCommand c = {CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K};
+  sscanf(Cmd, "%"lli" %"lli" %"lli" %s %s", &c.arg[0], &c.arg[1], &c.arg[2],(char*)(&c.d.asBytes),(char*)(&dummy+1));
+  // in case they specified 'h'
+  strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);
+  SendCommand(&c);
+  return 0;
 }
 
 int CmdFlexdemod(const char *Cmd)
 {
-       int i;
-       for (i = 0; i < GraphTraceLen; ++i) {
-               if (GraphBuffer[i] < 0) {
-                       GraphBuffer[i] = -1;
-               } else {
-                       GraphBuffer[i] = 1;
-               }
-       }
+  int i;
+  for (i = 0; i < GraphTraceLen; ++i) {
+    if (GraphBuffer[i] < 0) {
+      GraphBuffer[i] = -1;
+    } else {
+      GraphBuffer[i] = 1;
+    }
+  }
 
 #define LONG_WAIT 100
-       int start;
-       for (start = 0; start < GraphTraceLen - LONG_WAIT; start++) {
-               int first = GraphBuffer[start];
-               for (i = start; i < start + LONG_WAIT; i++) {
-                       if (GraphBuffer[i] != first) {
-                               break;
-                       }
-               }
-               if (i == (start + LONG_WAIT)) {
-                       break;
-               }
-       }
-       if (start == GraphTraceLen - LONG_WAIT) {
-               PrintAndLog("nothing to wait for");
-               return 0;
-       }
-
-       GraphBuffer[start] = 2;
-       GraphBuffer[start+1] = -2;
+  int start;
+  for (start = 0; start < GraphTraceLen - LONG_WAIT; start++) {
+    int first = GraphBuffer[start];
+    for (i = start; i < start + LONG_WAIT; i++) {
+      if (GraphBuffer[i] != first) {
+        break;
+      }
+    }
+    if (i == (start + LONG_WAIT)) {
+      break;
+    }
+  }
+  if (start == GraphTraceLen - LONG_WAIT) {
+    PrintAndLog("nothing to wait for");
+    return 0;
+  }
+
+  GraphBuffer[start] = 2;
+  GraphBuffer[start+1] = -2;
        uint8_t bits[64] = {0x00};
 
        int bit, sum;
-       i = start;
-       for (bit = 0; bit < 64; bit++) {
+  i = start;
+  for (bit = 0; bit < 64; bit++) {
                sum = 0;
                for (int j = 0; j < 16; j++) {
-                       sum += GraphBuffer[i++];
-               }
+      sum += GraphBuffer[i++];
+    }
 
                bits[bit] = (sum > 0) ? 1 : 0;
 
-               PrintAndLog("bit %d sum %d", bit, sum);
-       }
-
-       for (bit = 0; bit < 64; bit++) {
-               int j;
-               int sum = 0;
-               for (j = 0; j < 16; j++) {
-                       sum += GraphBuffer[i++];
-               }
-               if (sum > 0 && bits[bit] != 1) {
-                       PrintAndLog("oops1 at %d", bit);
-               }
-               if (sum < 0 && bits[bit] != 0) {
-                       PrintAndLog("oops2 at %d", bit);
-               }
-       }
+    PrintAndLog("bit %d sum %d", bit, sum);
+  }
+
+  for (bit = 0; bit < 64; bit++) {
+    int j;
+    int sum = 0;
+    for (j = 0; j < 16; j++) {
+      sum += GraphBuffer[i++];
+    }
+    if (sum > 0 && bits[bit] != 1) {
+      PrintAndLog("oops1 at %d", bit);
+    }
+    if (sum < 0 && bits[bit] != 0) {
+      PrintAndLog("oops2 at %d", bit);
+    }
+  }
 
        // HACK writing back to graphbuffer.
-       GraphTraceLen = 32*64;
-       i = 0;
-       int phase = 0;
-       for (bit = 0; bit < 64; bit++) {
+  GraphTraceLen = 32*64;
+  i = 0;
+  int phase = 0;
+  for (bit = 0; bit < 64; bit++) {
        
                phase = (bits[bit] == 0) ? 0 : 1;
                
-               int j;
-               for (j = 0; j < 32; j++) {
-                       GraphBuffer[i++] = phase;
-                       phase = !phase;
-               }
-       }
-
-       RepaintGraphWindow();
-       return 0;
+    int j;
+    for (j = 0; j < 32; j++) {
+      GraphBuffer[i++] = phase;
+      phase = !phase;
+    }
+  }
+
+  RepaintGraphWindow();
+  return 0;
 }
-       
+  
 int CmdIndalaDemod(const char *Cmd)
 {
-       // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
+  // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
 
-       int state = -1;
-       int count = 0;
-       int i, j;
+  int state = -1;
+  int count = 0;
+  int i, j;
 
-       // worst case with GraphTraceLen=64000 is < 4096
-       // under normal conditions it's < 2048
+  // worst case with GraphTraceLen=64000 is < 4096
+  // under normal conditions it's < 2048
 
-       uint8_t rawbits[4096];
-       int rawbit = 0;
-       int worst = 0, worstPos = 0;
+  uint8_t rawbits[4096];
+  int rawbit = 0;
+  int worst = 0, worstPos = 0;
  // PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32);
-       for (i = 0; i < GraphTraceLen-1; i += 2) {
-               count += 1;
-               if ((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {
-                       if (state == 0) {
-                               for (j = 0; j <  count - 8; j += 16) {
-                                       rawbits[rawbit++] = 0;
-                               }
-                               if ((abs(count - j)) > worst) {
-                                       worst = abs(count - j);
-                                       worstPos = i;
-                               }
-                       }
-                       state = 1;
-                       count = 0;
-               } else if ((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {
-                       if (state == 1) {
-                               for (j = 0; j <  count - 8; j += 16) {
-                                       rawbits[rawbit++] = 1;
-                               }
-                               if ((abs(count - j)) > worst) {
-                                       worst = abs(count - j);
-                                       worstPos = i;
-                               }
-                       }
-                       state = 0;
-                       count = 0;
-               }
-       }
-       
-       if (rawbit>0){
-               PrintAndLog("Recovered %d raw bits, expected: %d", rawbit, GraphTraceLen/32);
-               PrintAndLog("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
+  for (i = 0; i < GraphTraceLen-1; i += 2) {
+    count += 1;
+    if ((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {
+      if (state == 0) {
+        for (j = 0; j <  count - 8; j += 16) {
+          rawbits[rawbit++] = 0;
+        }
+        if ((abs(count - j)) > worst) {
+          worst = abs(count - j);
+          worstPos = i;
+        }
+      }
+      state = 1;
+      count = 0;
+    } else if ((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {
+      if (state == 1) {
+        for (j = 0; j <  count - 8; j += 16) {
+          rawbits[rawbit++] = 1;
+        }
+        if ((abs(count - j)) > worst) {
+          worst = abs(count - j);
+          worstPos = i;
+        }
+      }
+      state = 0;
+      count = 0;
+    }
+  }
+  
+  if (rawbit>0){
+    PrintAndLog("Recovered %d raw bits, expected: %d", rawbit, GraphTraceLen/32);
+    PrintAndLog("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
        } else {
                return 0;
        }
 
-       // Finding the start of a UID
-       int uidlen, long_wait;
-       if (strcmp(Cmd, "224") == 0) {
-               uidlen = 224;
-               long_wait = 30;
-       } else {
-               uidlen = 64;
-               long_wait = 29;
-       }
-
-       int start;
-       int first = 0;
-       for (start = 0; start <= rawbit - uidlen; start++) {
-               first = rawbits[start];
-               for (i = start; i < start + long_wait; i++) {
-                       if (rawbits[i] != first) {
-                               break;
-                       }
-               }
-               if (i == (start + long_wait)) {
-                       break;
-               }
-       }
-       
-       if (start == rawbit - uidlen + 1) {
-               PrintAndLog("nothing to wait for");
-               return 0;
-       }
-
-       // Inverting signal if needed
-       if (first == 1) {
-               for (i = start; i < rawbit; i++) {
-                       rawbits[i] = !rawbits[i];
-               }
-       }
-
-       // Dumping UID
+  // Finding the start of a UID
+  int uidlen, long_wait;
+  if (strcmp(Cmd, "224") == 0) {
+    uidlen = 224;
+    long_wait = 30;
+  } else {
+    uidlen = 64;
+    long_wait = 29;
+  }
+
+  int start;
+  int first = 0;
+  for (start = 0; start <= rawbit - uidlen; start++) {
+    first = rawbits[start];
+    for (i = start; i < start + long_wait; i++) {
+      if (rawbits[i] != first) {
+        break;
+      }
+    }
+    if (i == (start + long_wait)) {
+      break;
+    }
+  }
+  
+  if (start == rawbit - uidlen + 1) {
+    PrintAndLog("nothing to wait for");
+    return 0;
+  }
+
+  // Inverting signal if needed
+  if (first == 1) {
+    for (i = start; i < rawbit; i++) {
+      rawbits[i] = !rawbits[i];
+    }
+  }
+
+  // Dumping UID
        uint8_t bits[224] = {0x00};
        char showbits[225] = {0x00};
-       int bit;
-       i = start;
-       int times = 0;
-       
-       if (uidlen > rawbit) {
-               PrintAndLog("Warning: not enough raw bits to get a full UID");
-               for (bit = 0; bit < rawbit; bit++) {
-                       bits[bit] = rawbits[i++];
-                       // As we cannot know the parity, let's use "." and "/"
-                       showbits[bit] = '.' + bits[bit];
-               }
-               showbits[bit+1]='\0';
-               PrintAndLog("Partial UID=%s", showbits);
-               return 0;
-       } else {
-               for (bit = 0; bit < uidlen; bit++) {
-                       bits[bit] = rawbits[i++];
-                       showbits[bit] = '0' + bits[bit];
-               }
-               times = 1;
-       }
+  int bit;
+  i = start;
+  int times = 0;
        
-       //convert UID to HEX
-       uint32_t uid1, uid2, uid3, uid4, uid5, uid6, uid7;
-       int idx;
+  if (uidlen > rawbit) {
+    PrintAndLog("Warning: not enough raw bits to get a full UID");
+    for (bit = 0; bit < rawbit; bit++) {
+      bits[bit] = rawbits[i++];
+      // As we cannot know the parity, let's use "." and "/"
+      showbits[bit] = '.' + bits[bit];
+    }
+    showbits[bit+1]='\0';
+    PrintAndLog("Partial UID=%s", showbits);
+    return 0;
+  } else {
+    for (bit = 0; bit < uidlen; bit++) {
+      bits[bit] = rawbits[i++];
+      showbits[bit] = '0' + bits[bit];
+    }
+    times = 1;
+  }
+  
+  //convert UID to HEX
+  uint32_t uid1, uid2, uid3, uid4, uid5, uid6, uid7;
+  int idx;
        uid1 = uid2 = 0;
        
-       if (uidlen==64){
-               for( idx=0; idx<64; idx++) {
-                               if (showbits[idx] == '0') {
-                               uid1=(uid1<<1)|(uid2>>31);
-                               uid2=(uid2<<1)|0;
-                               } else {
-                               uid1=(uid1<<1)|(uid2>>31);
-                               uid2=(uid2<<1)|1;
-                               
-                       }
-               PrintAndLog("UID=%s (%x%08x)", showbits, uid1, uid2);
-       }
-       else {
+  if (uidlen==64){
+    for( idx=0; idx<64; idx++) {
+        if (showbits[idx] == '0') {
+        uid1=(uid1<<1)|(uid2>>31);
+        uid2=(uid2<<1)|0;
+        } else {
+        uid1=(uid1<<1)|(uid2>>31);
+        uid2=(uid2<<1)|1;
+        } 
+      }
+    PrintAndLog("UID=%s (%x%08x)", showbits, uid1, uid2);
+  }
+  else {
                uid3 = uid4 = uid5 = uid6 = uid7 = 0;
 
-               for( idx=0; idx<224; idx++) {
-                               uid1=(uid1<<1)|(uid2>>31);
-                               uid2=(uid2<<1)|(uid3>>31);
-                               uid3=(uid3<<1)|(uid4>>31);
-                               uid4=(uid4<<1)|(uid5>>31);
-                               uid5=(uid5<<1)|(uid6>>31);
-                               uid6=(uid6<<1)|(uid7>>31);
+    for( idx=0; idx<224; idx++) {
+        uid1=(uid1<<1)|(uid2>>31);
+        uid2=(uid2<<1)|(uid3>>31);
+        uid3=(uid3<<1)|(uid4>>31);
+        uid4=(uid4<<1)|(uid5>>31);
+        uid5=(uid5<<1)|(uid6>>31);
+        uid6=(uid6<<1)|(uid7>>31);
                        
                        if (showbits[idx] == '0') 
                                uid7 = (uid7<<1) | 0;
                        else 
                                uid7 = (uid7<<1) | 1;
-                       }
-               PrintAndLog("UID=%s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
-       }
+      }
+    PrintAndLog("UID=%s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
+  }
 
-       // Checking UID against next occurrences
-               int failed = 0;
+  // Checking UID against next occurrences
+    int failed = 0;
        for (; i + uidlen <= rawbit;) {
                failed = 0;
-               for (bit = 0; bit < uidlen; bit++) {
-                       if (bits[bit] != rawbits[i++]) {
-                               failed = 1;
-                               break;
-                       }
-               }
-               if (failed == 1) {
-                       break;
-               }
-               times += 1;
-       }
-
-       PrintAndLog("Occurrences: %d (expected %d)", times, (rawbit - start) / uidlen);
-
-       // Remodulating for tag cloning
+    for (bit = 0; bit < uidlen; bit++) {
+      if (bits[bit] != rawbits[i++]) {
+        failed = 1;
+        break;
+      }
+    }
+    if (failed == 1) {
+      break;
+    }
+    times += 1;
+  }
+
+  PrintAndLog("Occurrences: %d (expected %d)", times, (rawbit - start) / uidlen);
+
+  // Remodulating for tag cloning
        // HACK: 2015-01-04 this will have an impact on our new way of seening lf commands (demod) 
        // since this changes graphbuffer data.
-       GraphTraceLen = 32*uidlen;
-       i = 0;
-       int phase = 0;
-       for (bit = 0; bit < uidlen; bit++) {
-               if (bits[bit] == 0) {
-                       phase = 0;
-               } else {
-                       phase = 1;
-               }
-               int j;
-               for (j = 0; j < 32; j++) {
-                       GraphBuffer[i++] = phase;
-                       phase = !phase;
-               }
-       }
-
-       RepaintGraphWindow();
-       return 1;
+  GraphTraceLen = 32*uidlen;
+  i = 0;
+  int phase = 0;
+  for (bit = 0; bit < uidlen; bit++) {
+    if (bits[bit] == 0) {
+      phase = 0;
+    } else {
+      phase = 1;
+    }
+    int j;
+    for (j = 0; j < 32; j++) {
+      GraphBuffer[i++] = phase;
+      phase = !phase;
+    }
+  }
+
+  RepaintGraphWindow();
+  return 1;
 }
 
 int CmdIndalaClone(const char *Cmd)
 {
-       UsbCommand c;
+  UsbCommand c;
        unsigned int uid1, uid2, uid3, uid4, uid5, uid6, uid7;
 
        uid1 =  uid2 = uid3 = uid4 = uid5 = uid6 = uid7 = 0;
-       int n = 0, i = 0;
-
-       if (strchr(Cmd,'l') != 0) {
-               while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
-                       uid1 = (uid1 << 4) | (uid2 >> 28);
-                       uid2 = (uid2 << 4) | (uid3 >> 28);
-                       uid3 = (uid3 << 4) | (uid4 >> 28);
-                       uid4 = (uid4 << 4) | (uid5 >> 28);
-                       uid5 = (uid5 << 4) | (uid6 >> 28);
-                       uid6 = (uid6 << 4) | (uid7 >> 28);
-                       uid7 = (uid7 << 4) | (n & 0xf);
-               }
-               PrintAndLog("Cloning 224bit tag with UID %x%08x%08x%08x%08x%08x%08x", uid1, uid2, uid3, uid4, uid5, uid6, uid7);
-               c.cmd = CMD_INDALA_CLONE_TAG_L;
-               c.d.asDwords[0] = uid1;
-               c.d.asDwords[1] = uid2;
-               c.d.asDwords[2] = uid3;
-               c.d.asDwords[3] = uid4;
-               c.d.asDwords[4] = uid5;
-               c.d.asDwords[5] = uid6;
-               c.d.asDwords[6] = uid7;
+  int n = 0, i = 0;
+
+  if (strchr(Cmd,'l') != 0) {
+    while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
+      uid1 = (uid1 << 4) | (uid2 >> 28);
+      uid2 = (uid2 << 4) | (uid3 >> 28);
+      uid3 = (uid3 << 4) | (uid4 >> 28);
+      uid4 = (uid4 << 4) | (uid5 >> 28);
+      uid5 = (uid5 << 4) | (uid6 >> 28);
+      uid6 = (uid6 << 4) | (uid7 >> 28);
+       uid7 = (uid7 << 4) | (n & 0xf);
+    }
+    PrintAndLog("Cloning 224bit tag with UID %x%08x%08x%08x%08x%08x%08x", uid1, uid2, uid3, uid4, uid5, uid6, uid7);
+    c.cmd = CMD_INDALA_CLONE_TAG_L;
+    c.d.asDwords[0] = uid1;
+    c.d.asDwords[1] = uid2;
+    c.d.asDwords[2] = uid3;
+    c.d.asDwords[3] = uid4;
+    c.d.asDwords[4] = uid5;
+    c.d.asDwords[5] = uid6;
+    c.d.asDwords[6] = uid7;
        } else {
-               while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
-                       uid1 = (uid1 << 4) | (uid2 >> 28);
-                       uid2 = (uid2 << 4) | (n & 0xf);
-               }
-               PrintAndLog("Cloning 64bit tag with UID %x%08x", uid1, uid2);
-               c.cmd = CMD_INDALA_CLONE_TAG;
-               c.arg[0] = uid1;
-               c.arg[1] = uid2;
-       }
-
-       SendCommand(&c);
-       return 0;
+    while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
+      uid1 = (uid1 << 4) | (uid2 >> 28);
+      uid2 = (uid2 << 4) | (n & 0xf);
+    }
+    PrintAndLog("Cloning 64bit tag with UID %x%08x", uid1, uid2);
+    c.cmd = CMD_INDALA_CLONE_TAG;
+    c.arg[0] = uid1;
+    c.arg[1] = uid2;
+  }
+
+  SendCommand(&c);
+  return 0;
 }
 
 int usage_lf_read()
@@ -492,7 +492,12 @@ int CmdLFRead(const char *Cmd)
        //And ship it to device
        UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K, {arg1,0,0}};
        SendCommand(&c);
-       WaitForResponse(CMD_ACK,NULL);
+       //WaitForResponse(CMD_ACK,NULL);        
+       if ( !WaitForResponseTimeout(CMD_ACK,NULL,2500) ) {
+               PrintAndLog("command execution time out");
+               return 1;
+       }
+
        return 0;
 }
 
@@ -512,95 +517,95 @@ int CmdLFSnoop(const char *Cmd)
 
 static void ChkBitstream(const char *str)
 {
-       int i;
+  int i;
  
-       /* convert to bitstream if necessary */
+  /* convert to bitstream if necessary */
        for (i = 0; i < (int)(GraphTraceLen / 2); i++){
                if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) {
-                       CmdGetBitStream("");
-                       break;
-               }
-       }
+      CmdGetBitStream("");
+      break;
+    }
+  }
 }
 //Attempt to simulate any wave in buffer (one bit per output sample)
 // converts GraphBuffer to bitstream (based on zero crossings) if needed.
 int CmdLFSim(const char *Cmd)
 {
-       int i,j;
-       static int gap;
+  int i,j;
+  static int gap;
 
-       sscanf(Cmd, "%i", &gap);
+  sscanf(Cmd, "%i", &gap);
 
        // convert to bitstream if necessary 
 
-       ChkBitstream(Cmd);
+  ChkBitstream(Cmd);
 
        //can send only 512 bits at a time (1 byte sent per bit...)
-       printf("Sending [%d bytes]", GraphTraceLen);
-       for (i = 0; i < GraphTraceLen; i += USB_CMD_DATA_SIZE) {
-               UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}};
-
-               for (j = 0; j < USB_CMD_DATA_SIZE; j++) {
-                       c.d.asBytes[j] = GraphBuffer[i+j];
-               }
-               SendCommand(&c);
-               WaitForResponse(CMD_ACK,NULL);
-               printf(".");
-       }
-
-       printf("\n");
-       PrintAndLog("Starting to simulate");
-       UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}};
-       SendCommand(&c);
-       return 0;
+  printf("Sending [%d bytes]", GraphTraceLen);
+  for (i = 0; i < GraphTraceLen; i += USB_CMD_DATA_SIZE) {
+    UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}};
+
+    for (j = 0; j < USB_CMD_DATA_SIZE; j++) {
+      c.d.asBytes[j] = GraphBuffer[i+j];
+    }
+    SendCommand(&c);
+    WaitForResponse(CMD_ACK,NULL);
+    printf(".");
+  }
+
+  printf("\n");
+  PrintAndLog("Starting to simulate");
+  UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}};
+  SendCommand(&c);
+  return 0;
 }
 
 int usage_lf_simfsk(void)
 {
-       //print help
-       PrintAndLog("Usage: lf simfsk [c <clock>] [i] [H <fcHigh>] [L <fcLow>] [d <hexdata>]");
-       PrintAndLog("Options:        ");
-       PrintAndLog("       h              This help");
-       PrintAndLog("       c <clock>      Manually set clock - can autodetect if using DemodBuffer");
-       PrintAndLog("       i              invert data");
-       PrintAndLog("       H <fcHigh>     Manually set the larger Field Clock");
-       PrintAndLog("       L <fcLow>      Manually set the smaller Field Clock");
-       //PrintAndLog("       s              TBD- -to enable a gap between playback repetitions - default: no gap");
-       PrintAndLog("       d <hexdata>    Data to sim as hex - omit to sim from DemodBuffer");
-       PrintAndLog("\n  NOTE: if you set one clock manually set them all manually");
-       return 0;
+  //print help
+  PrintAndLog("Usage: lf simfsk [c <clock>] [i] [H <fcHigh>] [L <fcLow>] [d <hexdata>]");
+  PrintAndLog("Options:        ");
+  PrintAndLog("       h              This help");
+  PrintAndLog("       c <clock>      Manually set clock - can autodetect if using DemodBuffer");
+  PrintAndLog("       i              invert data");
+  PrintAndLog("       H <fcHigh>     Manually set the larger Field Clock");
+  PrintAndLog("       L <fcLow>      Manually set the smaller Field Clock");
+  //PrintAndLog("       s              TBD- -to enable a gap between playback repetitions - default: no gap");
+  PrintAndLog("       d <hexdata>    Data to sim as hex - omit to sim from DemodBuffer");
+  PrintAndLog("\n  NOTE: if you set one clock manually set them all manually");
+  return 0;
 }
 
 int usage_lf_simask(void)
 {
-       //print help
-       PrintAndLog("Usage: lf simask [c <clock>] [i] [b|m|r] [s] [d <raw hex to sim>]");
-       PrintAndLog("Options:        ");
-       PrintAndLog("       h              This help");
-       PrintAndLog("       c <clock>      Manually set clock - can autodetect if using DemodBuffer");
-       PrintAndLog("       i              invert data");
-       PrintAndLog("       b              sim ask/biphase");
-       PrintAndLog("       m              sim ask/manchester - Default");
-       PrintAndLog("       r              sim ask/raw");
-       PrintAndLog("       s              TBD- -to enable a gap between playback repetitions - default: no gap");
-       PrintAndLog("       d <hexdata>    Data to sim as hex - omit to sim from DemodBuffer");
-       return 0;
+  //print help
+  PrintAndLog("Usage: lf simask [c <clock>] [i] [b|m|r] [s] [d <raw hex to sim>]");
+  PrintAndLog("Options:        ");
+  PrintAndLog("       h              This help");
+  PrintAndLog("       c <clock>      Manually set clock - can autodetect if using DemodBuffer");
+  PrintAndLog("       i              invert data");
+  PrintAndLog("       b              sim ask/biphase");
+  PrintAndLog("       m              sim ask/manchester - Default");
+  PrintAndLog("       r              sim ask/raw");
+  PrintAndLog("       s              TBD- -to enable a gap between playback repetitions - default: no gap");
+  PrintAndLog("       d <hexdata>    Data to sim as hex - omit to sim from DemodBuffer");
+  return 0;
 }
 
 int usage_lf_simpsk(void)
 {
-       //print help
-       PrintAndLog("Usage: lf simpsk [1|2|3] [c <clock>] [i] [r <carrier>] [d <raw hex to sim>]");
-       PrintAndLog("Options:        ");
-       PrintAndLog("       h              This help");
-       PrintAndLog("       c <clock>      Manually set clock - can autodetect if using DemodBuffer");
-       PrintAndLog("       i              invert data");
-       PrintAndLog("       1              set PSK1 (default)");
-       PrintAndLog("       2              set PSK2");
-       PrintAndLog("       3              set PSK3");
-       PrintAndLog("       r <carrier>    2|4|8 are valid carriers: default = 2");
-       PrintAndLog("       d <hexdata>    Data to sim as hex - omit to sim from DemodBuffer");
-       return 0;
+  //print help
+  PrintAndLog("Usage: lf simpsk [1|2|3] [c <clock>] [i] [r <carrier>] [d <raw hex to sim>]");
+  PrintAndLog("Options:        ");
+  PrintAndLog("       h              This help");
+  PrintAndLog("       c <clock>      Manually set clock - can autodetect if using DemodBuffer");
+  PrintAndLog("       i              invert data");
+  PrintAndLog("       1              set PSK1 (default)");
+  PrintAndLog("       2              set PSK2");
+  PrintAndLog("       3              set PSK3");
+  PrintAndLog("       r <carrier>    2|4|8 are valid carriers: default = 2");
+  PrintAndLog("       d <hexdata>    Data to sim as hex - omit to sim from DemodBuffer");
+  return 0;
 }
 
 // by marshmellow - sim ask data given clock, fcHigh, fcLow, invert 
@@ -609,468 +614,468 @@ int CmdLFfskSim(const char *Cmd)
 {
        //might be able to autodetect FCs and clock from Graphbuffer if using demod buffer
        // otherwise will need FChigh, FClow, Clock, and bitstream
-       uint8_t fcHigh=0, fcLow=0, clk=0;
-       uint8_t invert=0;
-       bool errors = FALSE;
-       char hexData[32] = {0x00}; // store entered hex data
-       uint8_t data[255] = {0x00}; 
-       int dataLen = 0;
-       uint8_t cmdp = 0;
-       while(param_getchar(Cmd, cmdp) != 0x00)
-       {
-               switch(param_getchar(Cmd, cmdp))
-               {
-               case 'h':
-                       return usage_lf_simfsk();
-               case 'i':
-                       invert = 1;
-                       cmdp++;
-                       break;
-               case 'c':
-                       errors |= param_getdec(Cmd,cmdp+1,&clk);
-                       cmdp+=2;
-                       break;
-               case 'H':
-                       errors |= param_getdec(Cmd,cmdp+1,&fcHigh);
-                       cmdp+=2;
-                       break;
-               case 'L':
-                       errors |= param_getdec(Cmd,cmdp+1,&fcLow);
-                       cmdp+=2;
-                       break;
-               //case 's':
-               //  separator=1;
-               //  cmdp++;
-               //  break;
-               case 'd':
-                       dataLen = param_getstr(Cmd, cmdp+1, hexData);
-                       if (dataLen==0) {
-                               errors=TRUE; 
-                       } else {
-                               dataLen = hextobinarray((char *)data, hexData);
-                       }   
-                       if (dataLen==0) errors=TRUE; 
-                       if (errors) PrintAndLog ("Error getting hex data");
-                       cmdp+=2;
-                       break;
-               default:
-                       PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
-                       errors = TRUE;
-                       break;
-               }
-               if(errors) break;
-       }
-       if(cmdp == 0 && DemodBufferLen == 0)
-       {
-               errors = TRUE;// No args
-       }
-
-       //Validations
-       if(errors)
-       {
-               return usage_lf_simfsk();
-       }
-
-       if (dataLen == 0){ //using DemodBuffer 
-               if (clk==0 || fcHigh==0 || fcLow==0){ //manual settings must set them all
-                       uint8_t ans = fskClocks(&fcHigh, &fcLow, &clk, 0);
-                       if (ans==0){
-                               if (!fcHigh) fcHigh=10;
-                               if (!fcLow) fcLow=8;
-                               if (!clk) clk=50;
-                       }
-               }
-       } else {
-               setDemodBuf(data, dataLen, 0);
-       }
+  uint8_t fcHigh=0, fcLow=0, clk=0;
+  uint8_t invert=0;
+  bool errors = FALSE;
+  char hexData[32] = {0x00}; // store entered hex data
+  uint8_t data[255] = {0x00}; 
+  int dataLen = 0;
+  uint8_t cmdp = 0;
+  while(param_getchar(Cmd, cmdp) != 0x00)
+  {
+    switch(param_getchar(Cmd, cmdp))
+    {
+    case 'h':
+      return usage_lf_simfsk();
+    case 'i':
+      invert = 1;
+      cmdp++;
+      break;
+    case 'c':
+      errors |= param_getdec(Cmd,cmdp+1,&clk);
+      cmdp+=2;
+      break;
+    case 'H':
+      errors |= param_getdec(Cmd,cmdp+1,&fcHigh);
+      cmdp+=2;
+      break;
+    case 'L':
+      errors |= param_getdec(Cmd,cmdp+1,&fcLow);
+      cmdp+=2;
+      break;
+    //case 's':
+    //  separator=1;
+    //  cmdp++;
+    //  break;
+    case 'd':
+      dataLen = param_getstr(Cmd, cmdp+1, hexData);
+      if (dataLen==0) {
+        errors=TRUE; 
+      } else {
+        dataLen = hextobinarray((char *)data, hexData);
+      }   
+      if (dataLen==0) errors=TRUE; 
+      if (errors) PrintAndLog ("Error getting hex data");
+      cmdp+=2;
+      break;
+    default:
+      PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+      errors = TRUE;
+      break;
+    }
+    if(errors) break;
+  }
+  if(cmdp == 0 && DemodBufferLen == 0)
+  {
+    errors = TRUE;// No args
+  }
+
+  //Validations
+  if(errors)
+  {
+    return usage_lf_simfsk();
+  }
+
+  if (dataLen == 0){ //using DemodBuffer 
+    if (clk==0 || fcHigh==0 || fcLow==0){ //manual settings must set them all
+      uint8_t ans = fskClocks(&fcHigh, &fcLow, &clk, 0);
+      if (ans==0){
+        if (!fcHigh) fcHigh=10;
+        if (!fcLow) fcLow=8;
+        if (!clk) clk=50;
+      }
+    }
+  } else {
+    setDemodBuf(data, dataLen, 0);
+  }
 
        //default if not found
-       if (clk == 0) clk = 50;
-       if (fcHigh == 0) fcHigh = 10;
-       if (fcLow == 0) fcLow = 8;
-
-       uint16_t arg1, arg2;
-       arg1 = fcHigh << 8 | fcLow;
-       arg2 = invert << 8 | clk;
-       size_t size = DemodBufferLen;
-       if (size > USB_CMD_DATA_SIZE) {
-               PrintAndLog("DemodBuffer too long for current implementation - length: %d - max: %d", size, USB_CMD_DATA_SIZE);
-               size = USB_CMD_DATA_SIZE;
-       
-       UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}};
-
-       memcpy(c.d.asBytes, DemodBuffer, size);
-       SendCommand(&c);
-       return 0;
+  if (clk == 0) clk = 50;
+  if (fcHigh == 0) fcHigh = 10;
+  if (fcLow == 0) fcLow = 8;
+
+  uint16_t arg1, arg2;
+  arg1 = fcHigh << 8 | fcLow;
+  arg2 = invert << 8 | clk;
+  size_t size = DemodBufferLen;
+  if (size > USB_CMD_DATA_SIZE) {
+    PrintAndLog("DemodBuffer too long for current implementation - length: %d - max: %d", size, USB_CMD_DATA_SIZE);
+    size = USB_CMD_DATA_SIZE;
+  } 
+  UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}};
+
+  memcpy(c.d.asBytes, DemodBuffer, size);
+  SendCommand(&c);
+  return 0;
 }
 
 // by marshmellow - sim ask data given clock, invert, manchester or raw, separator 
 // - allow pull data from DemodBuffer
 int CmdLFaskSim(const char *Cmd)
 {
-       //autodetect clock from Graphbuffer if using demod buffer
+  //autodetect clock from Graphbuffer if using demod buffer
        // needs clock, invert, manchester/raw as m or r, separator as s, and bitstream
-       uint8_t encoding = 1, separator = 0;
-       uint8_t clk=0, invert=0;
-       bool errors = FALSE;
-       char hexData[32] = {0x00}; 
-       uint8_t data[255]= {0x00}; // store entered hex data
-       int dataLen = 0;
-       uint8_t cmdp = 0;
-       while(param_getchar(Cmd, cmdp) != 0x00)
-       {
-               switch(param_getchar(Cmd, cmdp))
-               {
-               case 'h':
-                       return usage_lf_simask();
-               case 'i':
-                       invert = 1;
-                       cmdp++;
-                       break;
-               case 'c':
-                       errors |= param_getdec(Cmd,cmdp+1,&clk);
-                       cmdp+=2;
-                       break;
-               case 'b':
-                       encoding=2; //biphase
-                       cmdp++;
-                       break;
-               case 'm':
-                       encoding=1;
-                       cmdp++;
-                       break;
-               case 'r':
-                       encoding=0;
-                       cmdp++;
-                       break;
-               case 's':
-                       separator=1;
-                       cmdp++;
-                       break;
-               case 'd':
-                       dataLen = param_getstr(Cmd, cmdp+1, hexData);
-                       if (dataLen==0) {
-                               errors=TRUE; 
-                       } else {
-                               dataLen = hextobinarray((char *)data, hexData);
-                       }
-                       if (dataLen==0) errors=TRUE; 
-                       if (errors) PrintAndLog ("Error getting hex data, datalen: %d",dataLen);
-                               cmdp+=2;
-                       break;
-               default:
-                       PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
-                       errors = TRUE;
-                       break;
-               }
-               if(errors) break;
-       }
-       if(cmdp == 0 && DemodBufferLen == 0)
-       {
-               errors = TRUE;// No args
-       }
-
-       //Validations
-       if(errors)
-       {
-               return usage_lf_simask();
-       }
-       if (dataLen == 0){ //using DemodBuffer
-               if (clk == 0) clk = GetAskClock("0", false, false);
-       } else {
-               setDemodBuf(data, dataLen, 0);
-       }
-       if (clk == 0) clk = 64;
-       if (encoding == 0) clk = clk/2; //askraw needs to double the clock speed
-       uint16_t arg1, arg2;
-       size_t size=DemodBufferLen;
-       arg1 = clk << 8 | encoding;
-       arg2 = invert << 8 | separator;
-       if (size > USB_CMD_DATA_SIZE) {
-               PrintAndLog("DemodBuffer too long for current implementation - length: %d - max: %d", size, USB_CMD_DATA_SIZE);
-               size = USB_CMD_DATA_SIZE;
-       }
-       UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
-       PrintAndLog("preparing to sim ask data: %d bits", size);
-       memcpy(c.d.asBytes, DemodBuffer, size);
-       SendCommand(&c);
-       return 0;
+  uint8_t encoding = 1, separator = 0;
+  uint8_t clk=0, invert=0;
+  bool errors = FALSE;
+  char hexData[32] = {0x00}; 
+  uint8_t data[255]= {0x00}; // store entered hex data
+  int dataLen = 0;
+  uint8_t cmdp = 0;
+  while(param_getchar(Cmd, cmdp) != 0x00)
+  {
+    switch(param_getchar(Cmd, cmdp))
+    {
+    case 'h':
+      return usage_lf_simask();
+    case 'i':
+      invert = 1;
+      cmdp++;
+      break;
+    case 'c':
+      errors |= param_getdec(Cmd,cmdp+1,&clk);
+      cmdp+=2;
+      break;
+    case 'b':
+      encoding=2; //biphase
+      cmdp++;
+      break;
+    case 'm':
+      encoding=1;
+      cmdp++;
+      break;
+    case 'r':
+      encoding=0;
+      cmdp++;
+      break;
+    case 's':
+      separator=1;
+      cmdp++;
+      break;
+    case 'd':
+      dataLen = param_getstr(Cmd, cmdp+1, hexData);
+      if (dataLen==0) {
+        errors=TRUE; 
+      } else {
+        dataLen = hextobinarray((char *)data, hexData);
+      }
+      if (dataLen==0) errors=TRUE; 
+      if (errors) PrintAndLog ("Error getting hex data, datalen: %d",dataLen);
+        cmdp+=2;
+      break;
+    default:
+      PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+      errors = TRUE;
+      break;
+    }
+    if(errors) break;
+  }
+  if(cmdp == 0 && DemodBufferLen == 0)
+  {
+    errors = TRUE;// No args
+  }
+
+  //Validations
+  if(errors)
+  {
+    return usage_lf_simask();
+  }
+  if (dataLen == 0){ //using DemodBuffer
+    if (clk == 0) clk = GetAskClock("0", false, false);
+  } else {
+    setDemodBuf(data, dataLen, 0);
+  }
+  if (clk == 0) clk = 64;
+  if (encoding == 0) clk = clk/2; //askraw needs to double the clock speed
+  uint16_t arg1, arg2;
+  size_t size=DemodBufferLen;
+  arg1 = clk << 8 | encoding;
+  arg2 = invert << 8 | separator;
+  if (size > USB_CMD_DATA_SIZE) {
+    PrintAndLog("DemodBuffer too long for current implementation - length: %d - max: %d", size, USB_CMD_DATA_SIZE);
+    size = USB_CMD_DATA_SIZE;
+  }
+  UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}};
+  PrintAndLog("preparing to sim ask data: %d bits", size);
+  memcpy(c.d.asBytes, DemodBuffer, size);
+  SendCommand(&c);
+  return 0;
 }
 
 // by marshmellow - sim psk data given carrier, clock, invert 
 // - allow pull data from DemodBuffer or parameters
 int CmdLFpskSim(const char *Cmd)
 {
-       //might be able to autodetect FC and clock from Graphbuffer if using demod buffer
-       //will need carrier, Clock, and bitstream
-       uint8_t carrier=0, clk=0;
-       uint8_t invert=0;
-       bool errors = FALSE;
-       char hexData[32] = {0x00}; // store entered hex data
-       uint8_t data[255] = {0x00}; 
-       int dataLen = 0;
-       uint8_t cmdp = 0;
-       uint8_t pskType = 1;
-       while(param_getchar(Cmd, cmdp) != 0x00)
-       {
-               switch(param_getchar(Cmd, cmdp))
-               {
-               case 'h':
-                       return usage_lf_simpsk();
-               case 'i':
-                       invert = 1;
-                       cmdp++;
-                       break;
-               case 'c':
-                       errors |= param_getdec(Cmd,cmdp+1,&clk);
-                       cmdp+=2;
-                       break;
-               case 'r':
-                       errors |= param_getdec(Cmd,cmdp+1,&carrier);
-                       cmdp+=2;
-                       break;
-               case '1':
-                       pskType=1;
-                       cmdp++;
-                       break;
-               case '2':
-                       pskType=2;
-                       cmdp++;
-                       break;
-               case '3':
-                       pskType=3;
-                       cmdp++;
-                       break;
-               case 'd':
-                       dataLen = param_getstr(Cmd, cmdp+1, hexData);
-                       if (dataLen==0) {
-                               errors=TRUE; 
-                       } else {
-                               dataLen = hextobinarray((char *)data, hexData);
-                       }    
-                       if (dataLen==0) errors=TRUE; 
-                       if (errors) PrintAndLog ("Error getting hex data");
-                       cmdp+=2;
-                       break;
-               default:
-                       PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
-                       errors = TRUE;
-                       break;
-               }
-               if (errors) break;
-       }
-       if (cmdp == 0 && DemodBufferLen == 0)
-       {
-               errors = TRUE;// No args
-       }
-
-       //Validations
-       if (errors)
-       {
-               return usage_lf_simpsk();
-       }
-       if (dataLen == 0){ //using DemodBuffer
-               PrintAndLog("Getting Clocks");
-               if (clk==0) clk = GetPskClock("", FALSE, FALSE);
-               PrintAndLog("clk: %d",clk);
-               if (!carrier) carrier = GetPskCarrier("", FALSE, FALSE); 
-               PrintAndLog("carrier: %d", carrier);
-       } else {
-               setDemodBuf(data, dataLen, 0);
-       }
-
-       if (clk <= 0) clk = 32;
-       if (carrier == 0) carrier = 2;
-       if (pskType != 1){
-               if (pskType == 2){
-                       //need to convert psk2 to psk1 data before sim
-                       psk2TOpsk1(DemodBuffer, DemodBufferLen);
-               } else {
-                       PrintAndLog("Sorry, PSK3 not yet available");
-               }
-       }
-       uint16_t arg1, arg2;
-       arg1 = clk << 8 | carrier;
-       arg2 = invert;
-       size_t size=DemodBufferLen;
-       if (size > USB_CMD_DATA_SIZE) {
-               PrintAndLog("DemodBuffer too long for current implementation - length: %d - max: %d", size, USB_CMD_DATA_SIZE);
-               size=USB_CMD_DATA_SIZE;
-       }
-       UsbCommand c = {CMD_PSK_SIM_TAG, {arg1, arg2, size}};
-       PrintAndLog("DEBUG: Sending DemodBuffer Length: %d", size);
-       memcpy(c.d.asBytes, DemodBuffer, size);
-       SendCommand(&c);
-       
-       return 0;
+  //might be able to autodetect FC and clock from Graphbuffer if using demod buffer
+  //will need carrier, Clock, and bitstream
+  uint8_t carrier=0, clk=0;
+  uint8_t invert=0;
+  bool errors = FALSE;
+  char hexData[32] = {0x00}; // store entered hex data
+  uint8_t data[255] = {0x00}; 
+  int dataLen = 0;
+  uint8_t cmdp = 0;
+  uint8_t pskType = 1;
+  while(param_getchar(Cmd, cmdp) != 0x00)
+  {
+    switch(param_getchar(Cmd, cmdp))
+    {
+    case 'h':
+      return usage_lf_simpsk();
+    case 'i':
+      invert = 1;
+      cmdp++;
+      break;
+    case 'c':
+      errors |= param_getdec(Cmd,cmdp+1,&clk);
+      cmdp+=2;
+      break;
+    case 'r':
+      errors |= param_getdec(Cmd,cmdp+1,&carrier);
+      cmdp+=2;
+      break;
+    case '1':
+      pskType=1;
+      cmdp++;
+      break;
+    case '2':
+      pskType=2;
+      cmdp++;
+      break;
+    case '3':
+      pskType=3;
+      cmdp++;
+      break;
+    case 'd':
+      dataLen = param_getstr(Cmd, cmdp+1, hexData);
+      if (dataLen==0) {
+        errors=TRUE; 
+      } else {
+        dataLen = hextobinarray((char *)data, hexData);
+      }    
+      if (dataLen==0) errors=TRUE; 
+      if (errors) PrintAndLog ("Error getting hex data");
+      cmdp+=2;
+      break;
+    default:
+      PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+      errors = TRUE;
+      break;
+    }
+    if (errors) break;
+  }
+  if (cmdp == 0 && DemodBufferLen == 0)
+  {
+    errors = TRUE;// No args
+  }
+
+  //Validations
+  if (errors)
+  {
+    return usage_lf_simpsk();
+  }
+  if (dataLen == 0){ //using DemodBuffer
+    PrintAndLog("Getting Clocks");
+    if (clk==0) clk = GetPskClock("", FALSE, FALSE);
+    PrintAndLog("clk: %d",clk);
+    if (!carrier) carrier = GetPskCarrier("", FALSE, FALSE); 
+    PrintAndLog("carrier: %d", carrier);
+  } else {
+    setDemodBuf(data, dataLen, 0);
+  }
+
+  if (clk <= 0) clk = 32;
+  if (carrier == 0) carrier = 2;
+  if (pskType != 1){
+    if (pskType == 2){
+      //need to convert psk2 to psk1 data before sim
+      psk2TOpsk1(DemodBuffer, DemodBufferLen);
+    } else {
+      PrintAndLog("Sorry, PSK3 not yet available");
+    }
+  }
+  uint16_t arg1, arg2;
+  arg1 = clk << 8 | carrier;
+  arg2 = invert;
+  size_t size=DemodBufferLen;
+  if (size > USB_CMD_DATA_SIZE) {
+    PrintAndLog("DemodBuffer too long for current implementation - length: %d - max: %d", size, USB_CMD_DATA_SIZE);
+    size=USB_CMD_DATA_SIZE;
+  }
+  UsbCommand c = {CMD_PSK_SIM_TAG, {arg1, arg2, size}};
+  PrintAndLog("DEBUG: Sending DemodBuffer Length: %d", size);
+  memcpy(c.d.asBytes, DemodBuffer, size);
+  SendCommand(&c);
+  
+  return 0;
 }
 
 int CmdLFSimBidir(const char *Cmd)
 {
-       // Set ADC to twice the carrier for a slight supersampling
-       // HACK: not implemented in ARMSRC.
-       PrintAndLog("Not implemented yet.");
-       UsbCommand c = {CMD_LF_SIMULATE_BIDIR, {47, 384, 0}};
-       SendCommand(&c);
-       return 0;
+  // Set ADC to twice the carrier for a slight supersampling
+  // HACK: not implemented in ARMSRC.
+  PrintAndLog("Not implemented yet.");
+  UsbCommand c = {CMD_LF_SIMULATE_BIDIR, {47, 384, 0}};
+  SendCommand(&c);
+  return 0;
 }
 
 int CmdVchDemod(const char *Cmd)
 {
-       // Is this the entire sync pattern, or does this also include some
-       // data bits that happen to be the same everywhere? That would be
-       // lovely to know.
-       static const int SyncPattern[] = {
-               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
-               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-       };
-
-       // So first, we correlate for the sync pattern, and mark that.
-       int bestCorrel = 0, bestPos = 0;
-       int i;
-       // It does us no good to find the sync pattern, with fewer than
-       // 2048 samples after it...
-       for (i = 0; i < (GraphTraceLen-2048); i++) {
-               int sum = 0;
-               int j;
-               for (j = 0; j < arraylen(SyncPattern); j++) {
-                       sum += GraphBuffer[i+j]*SyncPattern[j];
-               }
-               if (sum > bestCorrel) {
-                       bestCorrel = sum;
-                       bestPos = i;
-               }
-       }
-       PrintAndLog("best sync at %d [metric %d]", bestPos, bestCorrel);
-
-       char bits[257];
-       bits[256] = '\0';
-
-       int worst = INT_MAX;
-       int worstPos = 0;
-
-       for (i = 0; i < 2048; i += 8) {
-               int sum = 0;
-               int j;
-               for (j = 0; j < 8; j++) {
-                       sum += GraphBuffer[bestPos+i+j];
-               }
-               if (sum < 0) {
-                       bits[i/8] = '.';
-               } else {
-                       bits[i/8] = '1';
-               }
-               if(abs(sum) < worst) {
-                       worst = abs(sum);
-                       worstPos = i;
-               }
-       }
-       PrintAndLog("bits:");
-       PrintAndLog("%s", bits);
-       PrintAndLog("worst metric: %d at pos %d", worst, worstPos);
-
-       if (strcmp(Cmd, "clone")==0) {
-               GraphTraceLen = 0;
-               char *s;
-               for(s = bits; *s; s++) {
-                       int j;
-                       for(j = 0; j < 16; j++) {
-                               GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;
-                       }
-               }
-               RepaintGraphWindow();
-       }
-       return 0;
+  // Is this the entire sync pattern, or does this also include some
+  // data bits that happen to be the same everywhere? That would be
+  // lovely to know.
+  static const int SyncPattern[] = {
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  };
+
+  // So first, we correlate for the sync pattern, and mark that.
+  int bestCorrel = 0, bestPos = 0;
+  int i;
+  // It does us no good to find the sync pattern, with fewer than
+  // 2048 samples after it...
+  for (i = 0; i < (GraphTraceLen-2048); i++) {
+    int sum = 0;
+    int j;
+    for (j = 0; j < arraylen(SyncPattern); j++) {
+      sum += GraphBuffer[i+j]*SyncPattern[j];
+    }
+    if (sum > bestCorrel) {
+      bestCorrel = sum;
+      bestPos = i;
+    }
+  }
+  PrintAndLog("best sync at %d [metric %d]", bestPos, bestCorrel);
+
+  char bits[257];
+  bits[256] = '\0';
+
+  int worst = INT_MAX;
+  int worstPos = 0;
+
+  for (i = 0; i < 2048; i += 8) {
+    int sum = 0;
+    int j;
+    for (j = 0; j < 8; j++) {
+      sum += GraphBuffer[bestPos+i+j];
+    }
+    if (sum < 0) {
+      bits[i/8] = '.';
+    } else {
+      bits[i/8] = '1';
+    }
+    if(abs(sum) < worst) {
+      worst = abs(sum);
+      worstPos = i;
+    }
+  }
+  PrintAndLog("bits:");
+  PrintAndLog("%s", bits);
+  PrintAndLog("worst metric: %d at pos %d", worst, worstPos);
+
+  if (strcmp(Cmd, "clone")==0) {
+    GraphTraceLen = 0;
+    char *s;
+    for(s = bits; *s; s++) {
+      int j;
+      for(j = 0; j < 16; j++) {
+        GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;
+      }
+    }
+    RepaintGraphWindow();
+  }
+  return 0;
 }
 
 //by marshmellow
 int CmdLFfind(const char *Cmd)
 {
-       int ans=0;
-       char cmdp = param_getchar(Cmd, 0);
-       char testRaw = param_getchar(Cmd, 1);
-       if (strlen(Cmd) > 3 || cmdp == 'h' || cmdp == 'H') {
-               PrintAndLog("Usage:  lf search <0|1> [u]");
-               PrintAndLog("     <use data from Graphbuffer> , if not set, try reading data from tag.");
-               PrintAndLog("     [Search for Unknown tags] , if not set, reads only known tags.");
-               PrintAndLog("");
-               PrintAndLog("    sample: lf search     = try reading data from tag & search for known tags");
-               PrintAndLog("          : lf search 1   = use data from GraphBuffer & search for known tags");
-               PrintAndLog("          : lf search u   = try reading data from tag & search for known and unknown tags");
-               PrintAndLog("          : lf search 1 u = use data from GraphBuffer & search for known and unknown tags");
-
-               return 0;
-       }
-
-       if (!offline && (cmdp != '1')){
+  int ans=0;
+  char cmdp = param_getchar(Cmd, 0);
+  char testRaw = param_getchar(Cmd, 1);
+  if (strlen(Cmd) > 3 || cmdp == 'h' || cmdp == 'H') {
+    PrintAndLog("Usage:  lf search <0|1> [u]");
+    PrintAndLog("     <use data from Graphbuffer> , if not set, try reading data from tag.");
+    PrintAndLog("     [Search for Unknown tags] , if not set, reads only known tags.");
+    PrintAndLog("");
+    PrintAndLog("    sample: lf search     = try reading data from tag & search for known tags");
+    PrintAndLog("          : lf search 1   = use data from GraphBuffer & search for known tags");
+    PrintAndLog("          : lf search u   = try reading data from tag & search for known and unknown tags");
+    PrintAndLog("          : lf search 1 u = use data from GraphBuffer & search for known and unknown tags");
+    return 0;
+  }
+
+  if (!offline && (cmdp != '1')){
                CmdLFRead("s");
                getSamples("30000",false);
-       } else if (GraphTraceLen < 1000) {
-               PrintAndLog("Data in Graphbuffer was too small.");
-               return 0;
-       }
-       if (cmdp == 'u' || cmdp == 'U') testRaw = 'u';
-
-       PrintAndLog("NOTE: some demods output possible binary\n  if it finds something that looks like a tag");
-       PrintAndLog("False Positives ARE possible\n");  
-       PrintAndLog("\nChecking for known tags:\n");
-
-       ans=CmdFSKdemodIO("");
-       if (ans>0) {
-               PrintAndLog("\nValid IO Prox ID Found!");
-               return 1;
-       }
-
-       ans=CmdFSKdemodPyramid("");
-       if (ans>0) {
-               PrintAndLog("\nValid Pyramid ID Found!");
-               return 1;
-       }
-
-       ans=CmdFSKdemodParadox("");
-       if (ans>0) {
-               PrintAndLog("\nValid Paradox ID Found!");
-               return 1;
-       }
-
-       ans=CmdFSKdemodAWID("");
-       if (ans>0) {
-               PrintAndLog("\nValid AWID ID Found!");
-               return 1;
-       }
-
-       ans=CmdFSKdemodHID("");
-       if (ans>0) {
-               PrintAndLog("\nValid HID Prox ID Found!");
-               return 1;
-       }
-
-       //add psk and indala
-       ans=CmdIndalaDecode("");
-       if (ans>0) {
-               PrintAndLog("\nValid Indala ID Found!");
-               return 1;
-       }
-
-       ans=CmdAskEM410xDemod("");
-       if (ans>0) {
-               PrintAndLog("\nValid EM410x ID Found!");
-               return 1;
-       }
-
-       ans=CmdG_Prox_II_Demod("");
-       if (ans>0) {
-               PrintAndLog("\nValid G Prox II ID Found!");
-               return 1;
-       }
+  } else if (GraphTraceLen < 1000) {
+    PrintAndLog("Data in Graphbuffer was too small.");
+    return 0;
+  }
+  if (cmdp == 'u' || cmdp == 'U') testRaw = 'u';
+
+  PrintAndLog("NOTE: some demods output possible binary\n  if it finds something that looks like a tag");
+  PrintAndLog("False Positives ARE possible\n");  
+  PrintAndLog("\nChecking for known tags:\n");
+
+  ans=CmdFSKdemodIO("");
+  
+  if (ans>0) {
+    PrintAndLog("\nValid IO Prox ID Found!");
+    return 1;
+  }
+
+  ans=CmdFSKdemodPyramid("");
+  if (ans>0) {
+    PrintAndLog("\nValid Pyramid ID Found!");
+    return 1;
+  }
+
+  ans=CmdFSKdemodParadox("");
+  if (ans>0) {
+    PrintAndLog("\nValid Paradox ID Found!");
+    return 1;
+  }
+
+  ans=CmdFSKdemodAWID("");
+  if (ans>0) {
+    PrintAndLog("\nValid AWID ID Found!");
+    return 1;
+  }
+
+  ans=CmdFSKdemodHID("");
+  if (ans>0) {
+    PrintAndLog("\nValid HID Prox ID Found!");
+    return 1;
+  }
+
+  //add psk and indala
+  ans=CmdIndalaDecode("");
+  if (ans>0) {
+    PrintAndLog("\nValid Indala ID Found!");
+    return 1;
+  }
+
+  ans=CmdAskEM410xDemod("");
+  if (ans>0) {
+    PrintAndLog("\nValid EM410x ID Found!");
+    return 1;
+  }
+
+  ans=CmdG_Prox_II_Demod("");
+  if (ans>0) {
+    PrintAndLog("\nValid G Prox II ID Found!");
+    return 1;
+  }
 
        ans=CmdFDXBdemodBI("");
        if (ans>0) {
@@ -1090,73 +1095,101 @@ int CmdLFfind(const char *Cmd)
                return 1;
        }
 
-       PrintAndLog("\nNo Known Tags Found!\n");
-       if (testRaw=='u' || testRaw=='U'){
-               //test unknown tag formats (raw mode)
-               PrintAndLog("\nChecking for Unknown tags:\n");
-               ans=AutoCorrelate(4000, FALSE, FALSE);
-               if (ans > 0) PrintAndLog("Possible Auto Correlation of %d repeating samples",ans);
-               ans=GetFskClock("",FALSE,FALSE); 
-               if (ans != 0){ //fsk
-                       ans=FSKrawDemod("",TRUE);
-                       if (ans>0) {
-                               PrintAndLog("\nUnknown FSK Modulated Tag Found!");
-                               return 1;
+  PrintAndLog("\nNo Known Tags Found!\n");
+  if (testRaw=='u' || testRaw=='U'){
+    //test unknown tag formats (raw mode)
+    PrintAndLog("\nChecking for Unknown tags:\n");
+    ans=AutoCorrelate(4000, FALSE, FALSE);
+       
+    if (ans > 0) {
+
+               PrintAndLog("Possible Auto Correlation of %d repeating samples",ans);
+
+               if ( ans % 8 == 0)  {
+                       int bytes = (ans / 8);
+                       PrintAndLog("Possible %d bytes", bytes);
+                       int blocks = 0;
+                       if ( bytes % 2 == 0) {
+                               blocks = (bytes / 2);   
+                               PrintAndLog("Possible  2 blocks, width %d", blocks);
+                       }
+                       if ( bytes % 4 == 0) {
+                               blocks = (bytes / 4);   
+                               PrintAndLog("Possible  4 blocks, width %d", blocks);
+                       }
+                       if ( bytes % 8 == 0) {
+                               blocks = (bytes / 8);   
+                               PrintAndLog("Possible  8 blocks, width %d", blocks);
+                       }
+                       if ( bytes % 16 == 0) {
+                               blocks = (bytes / 16);  
+                               PrintAndLog("Possible 16 blocks, width %d", blocks);
                        }
                }
-               ans=ASKDemod("0 0 0",TRUE,FALSE,1);
-               if (ans>0) {
-                       PrintAndLog("\nUnknown ASK Modulated and Manchester encoded Tag Found!");
-                       PrintAndLog("\nif it does not look right it could instead be ASK/Biphase - try 'data rawdemod ab'");
-                       return 1;
-               }
-               ans=CmdPSK1rawDemod("");
-               if (ans>0) {
-                       PrintAndLog("Possible unknown PSK1 Modulated Tag Found above!\n\nCould also be PSK2 - try 'data rawdemod p2'");
-                       PrintAndLog("\nCould also be PSK3 - [currently not supported]");
-                       PrintAndLog("\nCould also be NRZ - try 'data nrzrawdemod");
-                       return 1;
-               }
-               PrintAndLog("\nNo Data Found!\n");
        }
-       return 0;
+               ans=GetFskClock("",FALSE,FALSE); 
+    if (ans != 0){ //fsk
+                       ans=FSKrawDemod("",TRUE);
+      if (ans>0) {
+        PrintAndLog("\nUnknown FSK Modulated Tag Found!");
+        return 1;
+      }
+    }
+               ans=ASKDemod("0 0 0",TRUE,FALSE,1);
+    if (ans>0) {
+      PrintAndLog("\nUnknown ASK Modulated and Manchester encoded Tag Found!");
+      PrintAndLog("\nif it does not look right it could instead be ASK/Biphase - try 'data rawdemod ab'");
+      return 1;
+    }
+    ans=CmdPSK1rawDemod("");
+    if (ans>0) {
+      PrintAndLog("Possible unknown PSK1 Modulated Tag Found above!\n\nCould also be PSK2 - try 'data rawdemod p2'");
+      PrintAndLog("\nCould also be PSK3 - [currently not supported]");
+      PrintAndLog("\nCould also be NRZ - try 'data nrzrawdemod");
+      return 1;
+    }
+    PrintAndLog("\nNo Data Found!\n");
+  }
+  return 0;
 }
 
 static command_t CommandTable[] = 
 {
-       {"help",        CmdHelp,            1, "This help"},
-       {"cmdread",     CmdLFCommandRead,   0, "<off period> <'0' period> <'1' period> <command> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)"},
-       {"em4x",        CmdLFEM4X,          1, "{ EM4X RFIDs... }"},
-       {"config",      CmdLFSetConfig,     0, "Set config for LF sampling, bit/sample, decimation, frequency"},
-       {"flexdemod",   CmdFlexdemod,       1, "Demodulate samples for FlexPass"},
-       {"hid",         CmdLFHID,           1, "{ HID RFIDs... }"},
-       {"io",            CmdLFIO,                1, "{ ioProx tags... }"},
-       {"indalademod", CmdIndalaDemod,     1, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
-       {"indalaclone", CmdIndalaClone,     0, "<UID> ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"},
-       {"read",        CmdLFRead,          0, "['s' silent] Read 125/134 kHz LF ID-only tag. Do 'lf read h' for help"},
-       {"search",      CmdLFfind,          1, "[offline] ['u'] Read and Search for valid known tag (in offline mode it you can load first then search) - 'u' to search for unknown tags"},
-       {"sim",         CmdLFSim,           0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"},
-       {"simask",      CmdLFaskSim,        0, "[clock] [invert <1|0>] [manchester/raw <'m'|'r'>] [msg separator 's'] [d <hexdata>] -- Simulate LF ASK tag from demodbuffer or input"},
-       {"simfsk",      CmdLFfskSim,        0, "[c <clock>] [i] [H <fcHigh>] [L <fcLow>] [d <hexdata>] -- Simulate LF FSK tag from demodbuffer or input"},
-       {"simpsk",      CmdLFpskSim,        0, "[1|2|3] [c <clock>] [i] [r <carrier>] [d <raw hex to sim>] -- Simulate LF PSK tag from demodbuffer or input"},
-       {"simbidir",    CmdLFSimBidir,      0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
-       {"snoop",       CmdLFSnoop,         0, "['l'|'h'|<divisor>] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"},
-       {"ti",          CmdLFTI,            1, "{ TI RFIDs... }"},
-       {"hitag",       CmdLFHitag,         1, "{ Hitag tags and transponders... }"},
-       {"vchdemod",    CmdVchDemod,        1, "['clone'] -- Demodulate samples for VeriChip"},
-       {"t55xx",       CmdLFT55XX,         1, "{ T55xx RFIDs... }"},
-       {"pcf7931",     CmdLFPCF7931,       1, "{PCF7931 RFIDs...}"},
-       {NULL, NULL, 0, NULL}
+  {"help",        CmdHelp,            1, "This help"},
+  {"em4x",        CmdLFEM4X,          1, "{ EM4X RFIDs... }"},
+  {"hid",         CmdLFHID,           1, "{ HID RFIDs... }"},
+  {"hitag",       CmdLFHitag,         1, "{ HITAG RFIDs... }"},
+  {"io",                 CmdLFIO,                1, "{ IOPROX RFIDs... }"},
+  {"pcf7931",     CmdLFPCF7931,       1, "{ PCF7931 RFIDs... }"},
+  {"ti",          CmdLFTI,            1, "{ TI RFIDs... }"},
+  {"t55xx",       CmdLFT55XX,         1, "{ T55X7 RFIDs... }"},
+
+  {"config",      CmdLFSetConfig,     0, "Set config for LF sampling, bit/sample, decimation, frequency"},
+  {"cmdread",     CmdLFCommandRead,   0, "<off period> <'0' period> <'1' period> <command> ['h' 134] \n\t\t-- Modulate LF reader field to send command before read (all periods in microseconds)"},
+  {"flexdemod",   CmdFlexdemod,       1, "Demodulate samples for FlexPass"},
+  {"indalademod", CmdIndalaDemod,     1, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
+  {"indalaclone", CmdIndalaClone,     0, "<UID> ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"},
+  {"read",        CmdLFRead,          0, "['s' silent] Read 125/134 kHz LF ID-only tag. Do 'lf read h' for help"},
+  {"search",      CmdLFfind,          1, "[offline] ['u'] Read and Search for valid known tag (in offline mode it you can load first then search) \n\t\t- 'u' to search for unknown tags"},
+  {"sim",         CmdLFSim,           0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"},
+  {"simask",      CmdLFaskSim,        0, "[clock] [invert <1|0>] [manchester/raw <'m'|'r'>] [msg separator 's'] [d <hexdata>] \n\t\t-- Simulate LF ASK tag from demodbuffer or input"},
+  {"simfsk",      CmdLFfskSim,        0, "[c <clock>] [i] [H <fcHigh>] [L <fcLow>] [d <hexdata>] \n\t\t-- Simulate LF FSK tag from demodbuffer or input"},
+  {"simpsk",      CmdLFpskSim,        0, "[1|2|3] [c <clock>] [i] [r <carrier>] [d <raw hex to sim>] \n\t\t-- Simulate LF PSK tag from demodbuffer or input"},
+  {"simbidir",    CmdLFSimBidir,      0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
+  {"snoop",       CmdLFSnoop,         0, "['l'|'h'|<divisor>] [trigger threshold] -- Snoop LF (l:125khz, h:134khz)"},
+  {"vchdemod",    CmdVchDemod,        1, "['clone'] -- Demodulate samples for VeriChip"},
+  {NULL, NULL, 0, NULL}
 };
 
 int CmdLF(const char *Cmd)
 {
-       CmdsParse(CommandTable, Cmd);
-       return 0; 
+  CmdsParse(CommandTable, Cmd);
+  return 0; 
 }
 
 int CmdHelp(const char *Cmd)
 {
-       CmdsHelp(CommandTable);
-       return 0;
+  CmdsHelp(CommandTable);
+  return 0;
 }
diff --git a/client/cmdlfawid26.c b/client/cmdlfawid26.c
new file mode 100644 (file)
index 0000000..48e599d
--- /dev/null
@@ -0,0 +1,208 @@
+//-----------------------------------------------------------------------------
+//
+// 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.
+//-----------------------------------------------------------------------------
+// Low frequency AWID26 commands
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include "proxmark3.h"
+#include "ui.h"
+//#include "graph.h"
+#include "cmdmain.h"
+#include "cmdparser.h"
+//#include "cmddata.h"
+#include "cmdlf.h"
+#include "cmdlfawid26.h"
+#include "util.h"
+//#include "data.h"
+
+
+static int CmdHelp(const char *Cmd);
+
+int CmdClone(const char *Cmd)
+{
+       char cmdp = param_getchar(Cmd, 0);
+
+       if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') {
+               PrintAndLog("Usage:  lf awid26 clone  <facility> <id>");
+               PrintAndLog("     [], ");
+               PrintAndLog("");
+               PrintAndLog("     sample: lf awid26 clone 15 2233");
+               return 0;
+       }
+
+       //sscanf(Cmd, "%d %d", &facilitycode, &cardno);
+
+       // char block0 = "00107060";  
+       // char block1 = "00107060";  
+       // char block2 = "00107060";  
+       // char block3 = "00107060";  
+
+       unsigned char buf[10] = {0x00};
+       unsigned char *resp = buf;
+       
+       
+       awid26_hex_to_uid(resp, "");
+       // PrintAndLog("Writing block %d with data %08X", Block, Data);
+       return 0;
+}
+
+
+// convert 96 bit AWID FSK data to 8 digit BCD UID
+bool awid26_hex_to_uid(unsigned char *response, char *awid26)
+{
+       //uint8_t i, tmp[96], tmp1[7];
+       //uint8_t tmp[96] = {0x00};
+    //int site;
+    //int id;
+       
+    //if(!hextobinarray(tmp, awid26))
+        return false;
+
+    // // data is in blocks of 4 bits - every 4th bit is parity, except the first
+    // // block which is all zeros
+    // for(i= 0 ; i < 4 ; ++i)
+        // if(tmp[i] != 0x00)
+            // return false;
+
+    // // discard 1st block
+    // memcpy(tmp, tmp + 4, 92);
+
+    // // check and strip parity on the rest
+    // for(i= 1 ; i < 23 ; ++i)
+        // if(tmp[(i * 4) - 1] != GetParity(tmp + (i - 1) * 4, ODD, 3))
+            // return false;
+        // else
+            // memcpy((tmp + (i - 1) * 3), tmp + (i - 1) * 4, 3);
+
+    // // discard the rest of the header - 1 more 3 bit block
+    // memcpy(tmp, tmp + 3, 66);
+
+    // // next 8 bits is data length - should be 26: 0x1A
+    // binarraytohex(tmp1, tmp, 8);
+    // if(strcmp(tmp1, "1A") != 0)
+        // return false;
+    // memcpy(tmp, tmp +8, 58);
+
+    // // standard wiegand parity check - even for 1st 12 bits, odd for 2nd 12
+    // if(tmp[0] != GetParity(tmp + 1, EVEN, 12))
+        // return false;
+    // if(tmp[25] != GetParity(tmp + 13, ODD, 12))
+        // return false;
+
+    // // convert to hex, ignoring parity bits
+    // if(!binarraytohex(tmp1, tmp + 1, 24))
+        // return false;
+
+    // // convert hex to site/id
+    // sscanf(tmp1,"%2X%4X", &site, &id);
+
+    // // final output 8 byte BCD
+    // sprintf(response,"%03d%05d", site, id);
+
+    return true;
+}
+
+// convert null-terminated BCD UID (8 digits) to 96 bit awid26 encoded binary array
+bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd)
+{
+    // char i, p, tmp1[8], tmp2[26];
+    // int tmpint;
+
+    // if(strlen(bcd) != 8)
+        // return false;
+
+    // // convert BCD site code to HEX
+    // sscanf(bcd, "%03d", &tmpint);
+    // sprintf(tmp2, "%02x", tmpint);
+    // memcpy(tmp1, tmp2, 2);
+
+    // // convert BCD ID to HEX
+    // sscanf(bcd + 3, "%05d", &tmpint);;
+    // sprintf(tmp2, "%04x", tmpint);
+       
+    // // copy with trailing NULL
+    // memcpy(tmp1 + 2, tmp2, 5);
+
+    // // convert full HEX to binary, leaving room for parity prefix
+    // hextobinarray(tmp2 + 1, tmp1);
+    
+    // wiegand_add_parity(tmp2, tmp2 + 1, 24);
+
+    // memset(awid26, '\x0', 96);
+
+    // // magic 18 bit awid26 header (we will overwrite the last two bits)
+    // hextobinarray(awid26, "011D8");
+
+    // // copy to target leaving space for parity bits
+    // for(i= 0, p= 18 ; i < 26 ; ++i, ++p)
+    // {
+        // // skip target bit if this is a parity location
+        // if(!((p + 1) % 4))
+            // p += 1;
+        // awid26[p]= tmp2[i];
+    // }
+
+    // // add parity bits
+    // for(i= 1 ; i < 24 ; ++i)
+        // awid26[((i + 1) * 4) - 1]= GetParity(&awid26[i * 4], ODD, 3);
+
+    return false;
+}
+
+// int CmdReadTrace(const char *Cmd)
+// {
+
+       // uint8_t bits[LF_BITSSTREAM_LEN] = {0x00};
+       // uint8_t * bitstream = bits;
+       
+       // uint8_t si = 5;
+       // uint32_t bl0     = PackBits(si, 32, bitstream);
+       // uint32_t bl1     = PackBits(si+32, 32, bitstream);
+       
+       // uint32_t acl     = PackBits(si,  8, bitstream); si += 8;
+       // uint32_t mfc     = PackBits(si, 8, bitstream); si += 8;
+       // uint32_t cid     = PackBits(si, 5, bitstream); si += 5;
+       // uint32_t icr     = PackBits(si, 3, bitstream); si += 3;
+       // uint32_t year    = PackBits(si, 4, bitstream); si += 4;
+       // uint32_t quarter = PackBits(si, 2, bitstream); si += 2;
+       // uint32_t lotid    = PackBits(si, 12, bitstream); si += 12;
+       // uint32_t wafer   = PackBits(si, 5, bitstream); si += 5;
+       // uint32_t dw      = PackBits(si, 15, bitstream); 
+       
+       // PrintAndLog("");
+       // PrintAndLog("-- T55xx Trace Information ----------------------------------");
+       // PrintAndLog("-------------------------------------------------------------");
+       // PrintAndLog(" ACL Allocation class (ISO/IEC 15963-1)  : 0x%02X (%d)", acl, acl);
+       // PrintAndLog(" MFC Manufacturer ID (ISO/IEC 7816-6)    : 0x%02X (%d)", mfc, mfc);
+       // PrintAndLog(" CID                                     : 0x%02X (%d)", cid, cid);
+       // PrintAndLog(" ICR IC Revision                         : %d",icr );
+       
+       
+  // return 0;
+// }
+
+static command_t CommandTable[] =
+{
+  {"help",   CmdHelp,     1, "This help"},
+  {"clone",  CmdClone,    1, "<facility> <id> -- clone AWID26 to t55xx tag"},
+  {NULL, NULL, 0, NULL}
+};
+
+int CmdLFAWID26(const char *Cmd)
+{
+  CmdsParse(CommandTable, Cmd);
+  return 0;
+}
+
+int CmdHelp(const char *Cmd)
+{
+  CmdsHelp(CommandTable);
+  return 0;
+}
diff --git a/client/cmdlfawid26.h b/client/cmdlfawid26.h
new file mode 100644 (file)
index 0000000..7c23d56
--- /dev/null
@@ -0,0 +1,18 @@
+//-----------------------------------------------------------------------------
+//
+// 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.
+//-----------------------------------------------------------------------------
+// Low frequency AWID 26 commands
+//-----------------------------------------------------------------------------
+
+#ifndef CMDLFAWID26_H__
+#define CMDLFAWID26_H__
+
+int CmdLFAWID26(const char *Cmd);
+
+int CmdClone(const char *Cmd);
+bool awid26_hex_to_uid(unsigned char *response, char *awid26);
+bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd);
+#endif
index c492a64d52e5c4e056202302142836a2f893ae80..c68d35f88a9b5859f53db3700f38eedc18a2bfa5 100644 (file)
@@ -20,6 +20,9 @@
 #include "cmdlf.h"
 #include "cmdlfem4x.h"
 #include "lfdemod.h"
+
+#define llx PRIx64
+
 char *global_em410xId;
 
 static int CmdHelp(const char *Cmd);
@@ -70,9 +73,9 @@ int CmdEM410xSim(const char *Cmd)
        uint8_t uid[5] = {0x00};
 
        if (cmdp == 'h' || cmdp == 'H') {
-               PrintAndLog("Usage:  lf em4x 410xsim <UID>");
+               PrintAndLog("Usage:  lf em4x em410xsim <UID>");
                PrintAndLog("");
-               PrintAndLog("     sample: lf em4x 410xsim 0F0368568B");
+               PrintAndLog("     sample: lf em4x em410xsim 0F0368568B");
                return 0;
        }
 
index b357e71c30c50e327f42cbe346475614685da428..2953e7802726094cfef7a8005796765ec0daf9e4 100644 (file)
@@ -50,11 +50,11 @@ int usage_t55xx_config(){
 }\r
 int usage_t55xx_read(){\r
        PrintAndLog("Usage:  lf t55xx read <block> <password>");\r
-       PrintAndLog("     <block>, block number to read. Between 0-7");\r
-       PrintAndLog("     <password>, OPTIONAL password (8 hex characters)");\r
-       PrintAndLog("");\r
+    PrintAndLog("     <block>, block number to read. Between 0-7");\r
+    PrintAndLog("     <password>, OPTIONAL password (8 hex characters)");\r
+    PrintAndLog("");\r
        PrintAndLog("Examples:");\r
-       PrintAndLog("      lf t55xx read 0           - read data from block 0");\r
+    PrintAndLog("      lf t55xx read 0           - read data from block 0");\r
        PrintAndLog("      lf t55xx read 0 feedbeef  - read data from block 0 password feedbeef");\r
        PrintAndLog("");\r
        return 0;\r
@@ -63,8 +63,8 @@ int usage_t55xx_write(){
        PrintAndLog("Usage:  lf t55xx wr <block> <data> [password]");\r
        PrintAndLog("     <block>, block number to write. Between 0-7");\r
        PrintAndLog("     <data>,  4 bytes of data to write (8 hex characters)");\r
-       PrintAndLog("     [password], OPTIONAL password 4bytes (8 hex characters)");\r
-       PrintAndLog("");\r
+    PrintAndLog("     [password], OPTIONAL password 4bytes (8 hex characters)");\r
+    PrintAndLog("");\r
        PrintAndLog("Examples:");\r
        PrintAndLog("      lf t55xx wr 3 11223344           - write 11223344 to block 3");\r
        PrintAndLog("      lf t55xx wr 3 11223344 feedbeef  - write 11223344 to block 3 password feedbeef");\r
@@ -1050,6 +1050,7 @@ char * GetSelectedModulationStr( uint8_t id){
        return buf;\r
 }\r
 \r
+/*\r
 uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits){\r
        \r
        int i = start;\r
@@ -1063,7 +1064,7 @@ uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits){
 \r
        return tmp;\r
 }\r
-\r
+*/\r
 static command_t CommandTable[] =\r
 {\r
   {"help",   CmdHelp,           1, "This help"},\r
index 512aa13cc91d7e6e950de83346e9342900aef9a1..2bb76d7b02919553b53a32bb424c4b3c459481b8 100644 (file)
 #include "cmdmain.h"
 #include "util.h"
 #include "cmdscript.h"
+#include "cmdcrc.h"
 
 
 unsigned int current_command = CMD_UNKNOWN;
 
 static int CmdHelp(const char *Cmd);
 static int CmdQuit(const char *Cmd);
+static int CmdRev(const char *Cmd);
 
 //For storing command that are received from the device
-#define CMD_BUFFER_SIZE 50
 static UsbCommand cmdBuffer[CMD_BUFFER_SIZE];
 //Points to the next empty position to write to
 static int cmd_head;//Starts as 0
@@ -42,15 +43,16 @@ static int cmd_tail;//Starts as 0
 
 static command_t CommandTable[] = 
 {
-  {"help",  CmdHelp,  1, "This help. Use '<command> help' for details of a particular command."},
-  {"data",  CmdData,  1, "{ Plot window / data buffer manipulation... }"},
-  {"hf",       CmdHF,          1, "{ High Frequency commands... }"},
-  {"hw",    CmdHW,    1, "{ Hardware commands... }"},
-  {"lf",       CmdLF,          1, "{ Low Frequency commands... }"},
-  {"script", CmdScript,   1,"{ Scripting commands }"},
-  {"quit",  CmdQuit,  1, "Exit program"},
-  {"exit",  CmdQuit,  1, "Exit program"},
-  {NULL, NULL, 0, NULL}
+       {"help",        CmdHelp,        1, "This help. Use '<command> help' for details of a particular command."},
+       {"data",        CmdData,        1, "{ Plot window / data buffer manipulation... }"},
+       {"hf",          CmdHF,          1, "{ High Frequency commands... }"},
+       {"hw",          CmdHW,          1, "{ Hardware commands... }"},
+       {"lf",          CmdLF,          1, "{ Low Frequency commands... }"},
+  {"reveng",CmdRev,   1, "Crc calculations from the software reveng1-30"},
+       {"script",      CmdScript,      1, "{ Scripting commands }"},
+       {"quit",        CmdQuit,        1, "Exit program"},
+       {"exit",        CmdQuit,        1, "Exit program"},
+       {NULL, NULL, 0, NULL}
 };
 
 command_t* getTopLevelCommandTable()
@@ -68,6 +70,12 @@ int CmdQuit(const char *Cmd)
   exit(0);
   return 0;
 }
+
+int CmdRev(const char *Cmd)
+{
+  CmdCrc(Cmd);
+  return 0;
+}
 /**
  * @brief This method should be called when sending a new command to the pm3. In case any old
  *  responses from previous commands are stored in the buffer, a call to this method should clear them.
index 0cf2b35d436e5656d2aaf11c087f4ecc791e5c86..aa87052c782e76274159ab239b4ff92a8a0e89a7 100644 (file)
@@ -19,4 +19,8 @@ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeou
 bool WaitForResponse(uint32_t cmd, UsbCommand* response);
 void clearCommandBuffer();
 command_t* getTopLevelCommandTable();
+
+//For storing command that are received from the device
+#define CMD_BUFFER_SIZE 50
+
 #endif
index c273c1f383b759c76a008669d91f1300c30134e7..e982ecf19141f474e3f90a858b80848c55d22f74 100644 (file)
@@ -13,7 +13,7 @@
 #include "proxmark3.h"
 #include "flash.h"
 #include "uart.h"
-#include "usb_cmd.h"
+#include "../include/usb_cmd.h"
 
 #ifdef _WIN32
 # define unlink(x)
index 7c9cc873a019f1ae67c9c84ba8cabd789d4e88bd..7d3950b1aef2711d03211305ad19573096a1b95d 100644 (file)
@@ -219,7 +219,7 @@ void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
        BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0};
        State initState = suc(k,init(k),&input);
        output(k,initState,&input_32_zeroes,&out);
-}
+}       
 
 void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
 {
@@ -229,15 +229,15 @@ void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
 
        memcpy(cc_nr,cc_nr_p,12);
     memcpy(div_key,div_key_p,8);
-
+    
        reverse_arraybytes(cc_nr,12);
        BitstreamIn bitstream = {cc_nr,12 * 8,0};
-    uint8_t dest []= {0,0,0,0,0,0,0,0};
-    BitstreamOut out = { dest, sizeof(dest)*8, 0 };
-    MAC(div_key,bitstream, out);
-    //The output MAC must also be reversed
-    reverse_arraybytes(dest, sizeof(dest));
-    memcpy(mac, dest, 4);
+       uint8_t dest []= {0,0,0,0,0,0,0,0};
+       BitstreamOut out = { dest, sizeof(dest)*8, 0 };
+       MAC(div_key,bitstream, out);
+       //The output MAC must also be reversed
+       reverse_arraybytes(dest, sizeof(dest));
+       memcpy(mac,dest,4);
        //free(cc_nr);
     return;
 }
@@ -264,8 +264,8 @@ int testMAC()
                prnlog("[+] FAILED: MAC calculation failed:");
                printarr("    Calculated_MAC", calculated_mac, 4);
                printarr("    Correct_MAC   ", correct_MAC, 4);
-               return 1;
-       }
+       return 1;
+}
 
        return 0;
 }
index 10720f76d1e50b903d1acc0469a5d3af14f9bb0e..f18472ab4e73b07f026918c21be2ba07000cb87d 100644 (file)
  * @return 0 for ok, 1 for failz
  */
 int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
+/**
+ * @brief Utility function to save load binary data from a a file. This method takes a filename,
+ * Should only be used for fixed-size binary files
+ * @param fileName the name of the file
+ * @param data a buffer to place data in
+ * @param datalen the length of the data/data.
+ * @return
+ */
 
 int fileExists(const char *filename);
 #endif //ON_DEVICE
diff --git a/client/loclass/hash1_brute.c b/client/loclass/hash1_brute.c
new file mode 100644 (file)
index 0000000..a9fe0d1
--- /dev/null
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include "cipherutils.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include "elite_crack.h"
+
+void calc_score(uint8_t* csn, uint8_t* k)
+{
+    uint8_t score =0 ;
+    uint8_t i;
+    uint8_t goodvals[16] = {0};
+    uint8_t uniq_vals[8] = {0};
+    memset(goodvals, 0x00, 16);
+    memset(uniq_vals, 0x00, 8);
+    uint8_t badval = 0;
+    int badscore =0;
+    for(i=0; i < 8 ; i++)
+    {
+        if(k[i] == 0x01) continue;
+        if(k[i] == 0x00) continue;
+        if(k[i] == 0x45) continue;
+        if(k[i] < 16){
+            goodvals[k[i]] = 1;
+        }
+//        if(k[i] ==9 || k[i]==2){
+//            goodvals[k[i]] = 1;
+//        }
+
+        else if(k[i]>=16){
+            badscore++;
+            badval = k[i];
+        }
+    }
+    for(i =0; i < 16; i++)
+    {
+        if(goodvals[i])
+        {
+            uniq_vals[score] = i;
+            score +=1;
+        }
+    }
+    if(score >=2 && badscore < 2)
+    {
+        printf("CSN\t%02x%02x%02x%02x%02x%02x%02x%02x\t%02x %02x %02x %02x %02x %02x %02x %02x\t"
+               ,csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]
+                ,k[0],k[1],k[2],k[3],k[4],k[5],k[6],k[7]
+                );
+        for(i =0 ; i < score; i++)
+        {
+            printf("%d,", uniq_vals[i]);
+        }
+        printf("\tbadscore: %d (%02x)", badscore, badval);
+        printf("\r\n");
+
+    }
+
+}
+
+void brute_hash1(){
+    uint8_t csn[8] = {0,0,0,0,0xf7,0xff,0x12,0xe0};
+    uint8_t k[8]= {0,0,0,0,0,0,0,0};
+    uint16_t a,b,c,d;
+    uint8_t testcsn[8] ={0x00,0x0d,0x0f,0xfd,0xf7,0xff,0x12,0xe0} ;
+    uint8_t testkey[8] ={0x05 ,0x01 ,0x00 ,0x10 ,0x45 ,0x08 ,0x45,0x56} ;
+    calc_score(testcsn,testkey);
+    printf("Brute forcing hashones\n");
+    //exit(1);
+    for(a=0;a < 256;a++)
+    {
+        //if(a > 0)printf("%d/256 done...\n", a);
+        for(b=0;b < 256 ; b++)
+            for(c=0;c < 256;c++)
+               for(d=0;d < 256;d++)
+                {
+                    csn[0] = a;
+                    csn[1] = b;
+                    csn[2] = c;
+                    csn[3] = d;
+                    csn[4] = 0xf7;
+                    csn[5] = 0xff;
+                    csn[6] = 0x12;
+                    csn[7] = 0xe0;
+                    hash1(csn, k);
+                    calc_score(csn,k);
+               }
+    }
+
+}
+
diff --git a/client/loclass/hash1_brute.h b/client/loclass/hash1_brute.h
new file mode 100644 (file)
index 0000000..b26ad96
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef HASH1_BRUTE_H
+#define HASH1_BRUTE_H
+void brute_hash1();
+
+#endif // HASH1_BRUTE_H
index 678c745ec65cc2afd8b0583ed99ec3d74489c80f..bedb83678d48d562ea57e1459ba986f6fd480a8a 100644 (file)
@@ -136,8 +136,8 @@ local _commands = {
 
        --//ultralightC
        CMD_MIFAREUC_AUTH =                                                  0x0724,
-       CMD_MIFAREUC_SETPWD =                                                0x0727,
-       CMD_MIFAREU_SETUID =                                                 0x0728,
+       CMD_MIFAREUC_SETPWD =                                                                                            0x0727,
+       CMD_MIFAREU_SETUID =                                                                         0x0728,
 
        --// mifare desfire
        CMD_MIFARE_DESFIRE_READBL =                                          0x0728,
index 566128f7dde5324f5db084fc8d008517cb958365..1709606385ccfbb4c92c30e4be84ffaa0be42d26 100644 (file)
@@ -193,6 +193,8 @@ return {
        convert_bin_to_html = convert_bin_to_html,
        convert_eml_to_html = convert_eml_to_html,
        convert_eml_to_bin = convert_eml_to_bin,
-       SaveAsBinary = save_BIN,
+    SaveAsBinary = save_BIN,
+       SaveAsText = save_TEXT,
+    SaveAsBinary = save_BIN,
        SaveAsText = save_TEXT,
 }
index 592d0477d9f1ead73a754860e218e4d8ba2eb77d..da1797582132a1781831cfbb0e848cef27f4e91d 100644 (file)
@@ -37,9 +37,7 @@ local Utils =
        ------------ FILE READING\r
        ReadDumpFile = function (filename)\r
        \r
-               if filename == nil then \r
-                       return nil, 'Filename is empty'\r
-               end\r
+               filename = filename or 'dumpdata.bin'\r
                if #filename == 0 then\r
                        return nil, 'Filename length is zero'\r
                end\r
@@ -112,7 +110,7 @@ local Utils =
                        return hash\r
                end\r
                return nil\r
-       end,\r
+       end,    \r
        -- Takes a hex string and calculates a SHA1 hash\r
        Sha1Hex = function(s)\r
                if s == nil then return nil end\r
@@ -124,8 +122,8 @@ local Utils =
                        return hash\r
                end\r
                return nil\r
-       end,\r
-       \r
+       end,    \r
+\r
        \r
        -- input parameter is a string\r
        -- Swaps the endianess and returns a number,  \r
@@ -314,4 +312,4 @@ local Utils =
 -- end\r
 \r
 }\r
-return Utils\r
+return Utils
\ No newline at end of file
index 237979c1bfaaefc13ca0940093c2a47d5b954f40..d754b06b4a1a01dd589c6523bc354fdd0c99566d 100644 (file)
@@ -15,6 +15,8 @@
 #include "mifarehost.h"\r
 #include "proxmark3.h"\r
 \r
+#define llx PRIx64\r
+\r
 // MIFARE\r
 int compar_int(const void * a, const void * b) {\r
        // didn't work: (the result is truncated to 32 bits)\r
@@ -72,7 +74,6 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo
        uint16_t i, len;\r
        uint32_t uid;\r
        UsbCommand resp;\r
-\r
        StateList_t statelists[2];\r
        struct Crypto1State *p1, *p2, *p3, *p4;\r
        \r
@@ -216,7 +217,7 @@ int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) {
        UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}};\r
        SendCommand(&c);\r
 \r
-  UsbCommand resp;\r
+       UsbCommand resp;\r
        if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) return 1;\r
        memcpy(data, resp.d.asBytes, blocksCount * 16);\r
        return 0;\r
@@ -266,7 +267,7 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uin
        memcpy(c.d.asBytes, data, 16); \r
        SendCommand(&c);\r
 \r
-  UsbCommand resp;\r
+       UsbCommand resp;\r
        if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
                isOK  = resp.arg[0] & 0xff;\r
                if (uid != NULL) \r
@@ -313,16 +314,17 @@ static uint8_t traceCurKey = 0;
 \r
 struct Crypto1State *traceCrypto1 = NULL;\r
 \r
-struct Crypto1State *revstate;\r
-uint64_t lfsr;\r
-uint32_t ks2;\r
-uint32_t ks3;\r
+struct Crypto1State *revstate = NULL;\r
 \r
-uint32_t uid;     // serial number\r
-uint32_t nt;      // tag challenge\r
-uint32_t nr_enc;  // encrypted reader challenge\r
-uint32_t ar_enc;  // encrypted reader response\r
-uint32_t at_enc;  // encrypted tag response\r
+uint64_t key = 0;\r
+uint32_t ks2 = 0;\r
+uint32_t ks3 = 0;\r
+\r
+uint32_t uid = 0;     // serial number\r
+uint32_t nt =0;      // tag challenge\r
+uint32_t nr_enc =0;  // encrypted reader challenge\r
+uint32_t ar_enc =0;  // encrypted reader response\r
+uint32_t at_enc =0;  // encrypted tag response\r
 \r
 int isTraceCardEmpty(void) {\r
        return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0));\r
@@ -365,7 +367,7 @@ int loadTraceCard(uint8_t *tuid) {
                        PrintAndLog("File reading error.");\r
                        fclose(f);\r
                        return 2;\r
-       }\r
+               }\r
 \r
                if (strlen(buf) < 32){\r
                        if (feof(f)) break;\r
@@ -468,7 +470,7 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) {
                }\r
                \r
                // AUTHENTICATION\r
-               if ((len ==4) && ((data[0] == 0x60) || (data[0] == 0x61))) {\r
+               if ((len == 4) && ((data[0] == 0x60) || (data[0] == 0x61))) {\r
                        traceState = TRACE_AUTH1;\r
                        traceCurBlock = data[1];\r
                        traceCurKey = data[0] == 60 ? 1:0;\r
@@ -578,17 +580,17 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) {
                        lfsr_rollback_word(revstate, nr_enc, 1);\r
                        lfsr_rollback_word(revstate, uid ^ nt, 0);\r
 \r
-                       crypto1_get_lfsr(revstate, &lfsr);\r
-                       printf("key> %x%x\n", (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF));\r
-                       AddLogUint64(logHexFileName, "key> ", lfsr); \r
+                       crypto1_get_lfsr(revstate, &key);\r
+                       printf("Key: %012"llx"\n",key);\r
+                       AddLogUint64(logHexFileName, "key: ", key); \r
                        \r
                        int blockShift = ((traceCurBlock & 0xFC) + 3) * 16;\r
                        if (isBlockEmpty((traceCurBlock & 0xFC) + 3)) memcpy(traceCard + blockShift + 6, trailerAccessBytes, 4);\r
                        \r
                        if (traceCurKey) {\r
-                               num_to_bytes(lfsr, 6, traceCard + blockShift + 10);\r
+                               num_to_bytes(key, 6, traceCard + blockShift + 10);\r
                        } else {\r
-                               num_to_bytes(lfsr, 6, traceCard + blockShift);\r
+                               num_to_bytes(key, 6, traceCard + blockShift);\r
                        }\r
                        if (wantSaveToEmlFile) saveTraceCard();\r
 \r
@@ -601,7 +603,7 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) {
                        \r
 //     nt = crypto1_word(traceCrypto1, nt ^ uid, 1) ^ nt;\r
 \r
-       /*      traceCrypto1 = crypto1_create(lfsr); // key in lfsr\r
+       /*      traceCrypto1 = crypto1_create(key); // key in lfsr\r
                crypto1_word(traceCrypto1, nt ^ uid, 0);\r
                crypto1_word(traceCrypto1, ar, 1);\r
                crypto1_word(traceCrypto1, 0, 0);\r
index 1015e27a74b2a866078cb0ca350113081bd95baa..13c4c063af078fb4d155b7f227d26eda6b8fa9c9 100644 (file)
@@ -1,21 +1,21 @@
 /*  crapto1.c\r
 \r
-       This program is free software; you can redistribute it and/or\r
-       modify it under the terms of the GNU General Public License\r
-       as published by the Free Software Foundation; either version 2\r
-       of the License, or (at your option) any later version.\r
-\r
-       This program is distributed in the hope that it will be useful,\r
-       but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-       GNU General Public License for more details.\r
-\r
-       You should have received a copy of the GNU General Public License\r
-       along with this program; if not, write to the Free Software\r
-       Foundation, Inc., 51 Franklin Street, Fifth Floor,\r
-       Boston, MA  02110-1301, US$\r
-\r
-       Copyright (C) 2008-2008 bla <blapost@gmail.com>\r
+    This program is free software; you can redistribute it and/or\r
+    modify it under the terms of the GNU General Public License\r
+    as published by the Free Software Foundation; either version 2\r
+    of the License, or (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program; if not, write to the Free Software\r
+    Foundation, Inc., 51 Franklin Street, Fifth Floor,\r
+    Boston, MA  02110-1301, US$\r
+\r
+    Copyright (C) 2008-2008 bla <blapost@gmail.com>\r
 */\r
 #include "crapto1.h"\r
 #include <stdlib.h>\r
@@ -24,9 +24,9 @@
 static uint8_t filterlut[1 << 20];\r
 static void __attribute__((constructor)) fill_lut()\r
 {\r
-               uint32_t i;\r
-               for(i = 0; i < 1 << 20; ++i)\r
-                               filterlut[i] = filter(i);\r
+        uint32_t i;\r
+        for(i = 0; i < 1 << 20; ++i)\r
+                filterlut[i] = filter(i);\r
 }\r
 #define filter(x) (filterlut[(x) & 0xfffff])\r
 #endif\r
@@ -147,7 +147,7 @@ extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in
                        *p ^= in;\r
                } else {                                                                                // drop\r
                        *p-- = *(*end)--;\r
-               }\r
+       }\r
        }\r
 \r
 }\r
@@ -209,7 +209,7 @@ recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks,
 \r
        for (int i = bucket_info.numbuckets - 1; i >= 0; i--) {\r
                sl = recover(bucket_info.bucket_info[1][i].head, bucket_info.bucket_info[1][i].tail, oks,\r
-                                        bucket_info.bucket_info[0][i].head, bucket_info.bucket_info[0][i].tail, eks,\r
+                                    bucket_info.bucket_info[0][i].head, bucket_info.bucket_info[0][i].tail, eks,\r
                                         rem, sl, in, bucket);\r
        }\r
 \r
@@ -251,7 +251,6 @@ struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in)
                        }\r
                }\r
 \r
-\r
        // initialize statelists: add all possible states which would result into the rightmost 2 bits of the keystream\r
        for(i = 1 << 20; i >= 0; --i) {\r
                if(filter(i) == (oks & 1))\r
@@ -272,9 +271,7 @@ struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in)
 \r
        in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00);            // Byte swapping\r
 \r
-       recover(odd_head, odd_tail, oks,\r
-               even_head, even_tail, eks, 11, statelist, in << 1, bucket);\r
-\r
+       recover(odd_head, odd_tail, oks, even_head, even_tail, eks, 11, statelist, in << 1, bucket);\r
 \r
 out:\r
        free(odd_head);\r
@@ -484,7 +481,7 @@ uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd)
  */\r
 static struct Crypto1State*\r
 brute_top(uint32_t prefix, uint32_t rresp, unsigned char parities[8][8],\r
-                 uint32_t odd, uint32_t even, struct Crypto1State* sl, uint8_t no_chk)\r
+          uint32_t odd, uint32_t even, struct Crypto1State* sl, uint8_t no_chk)\r
 {\r
        struct Crypto1State s;\r
        uint32_t ks1, nr, ks2, rr, ks3, good, c;\r
@@ -536,8 +533,7 @@ brute_top(uint32_t prefix, uint32_t rresp, unsigned char parities[8][8],
  * It returns a zero terminated list of possible cipher states after the\r
  * tag nonce was fed in\r
  */\r
-struct Crypto1State*\r
-lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint8_t no_par)\r
+struct Crypto1State* lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint8_t no_par)\r
 {\r
        struct Crypto1State *statelist, *s;\r
        uint32_t *odd, *even, *o, *e, top;\r
@@ -548,10 +544,10 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8],
        statelist = malloc((sizeof *statelist) << 21);  //how large should be?\r
        if(!statelist || !odd || !even)\r
        {\r
-                               free(statelist);\r
-                               free(odd);\r
-                               free(even);\r
-                               return 0;\r
+               free(statelist);\r
+               free(odd);\r
+               free(even);\r
+               return 0;\r
        }\r
 \r
        s = statelist;\r
@@ -571,3 +567,66 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8],
 \r
        return statelist;\r
 }\r
+\r
+/*\r
+struct Crypto1State* lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint8_t no_par, uint32_t nt, uint32_t uid)\r
+{\r
+    long long int amount = 0;\r
+    struct Crypto1State *statelist, *s;\r
+    uint32_t *odd, *even, *o, *e, top;\r
+\r
+    odd = lfsr_prefix_ks(ks, 1);\r
+    even = lfsr_prefix_ks(ks, 0);\r
+\r
+    s = statelist = malloc((sizeof *statelist) << 20);\r
+    if(!s || !odd || !even) {\r
+               free(odd);\r
+               free(even);\r
+               free(statelist);\r
+               return 0;\r
+    }\r
+\r
+    char filename[50] = "archivo.txt";\r
+    sprintf(filename, "logs/%x.txt", nt);\r
+    PrintAndLog("Name: %s\n", filename);\r
+    FILE *file = fopen(filename,"w+");\r
+       if ( !file ) {\r
+               s->odd = s->even = 0;\r
+               free(odd);\r
+               free(even);\r
+               PrintAndLog("Failed to create file");\r
+               return 0;\r
+       }\r
+    PrintAndLog("Creating file... ");\r
+       uint32_t xored = uid^nt;\r
+       \r
+    int lastOdd = 0;\r
+    for(o = odd; *o + 1; ++o)\r
+        for(e = even; *e + 1; ++e)\r
+            for(top = 0; top < 64; ++top) {\r
+                *o += 1 << 21;\r
+                *e += (!(top & 7) + 1) << 21;\r
+\r
+                //added by MG\r
+                if(lastOdd != statelist->odd){\r
+                                       // Here I create a temporal crypto1 state, \r
+                                       // where I load the odd and even state and work with it,\r
+                                       // in order not to interfere with regular mechanism, This is what I save to file\r
+                                       struct Crypto1State *state;\r
+                    lastOdd = state->odd = statelist->odd; state->even = statelist->even;\r
+                    lfsr_rollback_word(state,xored,0);\r
+                    fprintf(file,"%x %x \n",state->odd,state->even);\r
+                    amount++;\r
+                }\r
+                //s = check_pfx_parity(pfx, rr, par, *o, *e, s); //This is not useful at all when attacking chineese cards\r
+                               s = brute_top(pfx, rr, par, *o, *e, s, no_par); \r
+            }\r
+\r
+       PrintAndLog("File created, amount %u\n",amount);\r
+       fclose(file);\r
+       s->odd = s->even = 0;\r
+       free(odd);\r
+       free(even);\r
+    return statelist;\r
+}\r
+ */\r
index 111f58cd6b07a8d21ddff7e006e5de485bf4830b..54cb0d2a5df723c85d64ef86a75dc5cfbb5042bf 100644 (file)
@@ -149,3 +149,99 @@ int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_
        
        return 1;
 }
+
+int tryMfk32(uint64_t myuid, uint8_t *data, uint8_t *outputkey ){
+
+       struct Crypto1State *s,*t;
+       uint64_t key;     // recovered key
+       uint32_t uid;     // serial number
+       uint32_t nt;      // tag challenge
+       uint32_t nr0_enc; // first encrypted reader challenge
+       uint32_t ar0_enc; // first encrypted reader response
+       uint32_t nr1_enc; // second encrypted reader challenge
+       uint32_t ar1_enc; // second encrypted reader response   
+       bool isSuccess = FALSE;
+       int counter = 0;
+       
+       uid     = myuid;//(uint32_t)bytes_to_num(data +  0, 4);
+       nt              = *(uint32_t*)(data+8);
+       nr0_enc = *(uint32_t*)(data+12);
+       ar0_enc = *(uint32_t*)(data+16);
+       nr1_enc = *(uint32_t*)(data+32);
+       ar1_enc = *(uint32_t*)(data+36);
+
+       // PrintAndLog("recovering key for:");
+       // PrintAndLog("    uid: %08x   %08x",uid, myuid);
+       // PrintAndLog("     nt: %08x",nt);
+       // PrintAndLog(" {nr_0}: %08x",nr0_enc);
+       // PrintAndLog(" {ar_0}: %08x",ar0_enc);
+       // PrintAndLog(" {nr_1}: %08x",nr1_enc);
+       // PrintAndLog(" {ar_1}: %08x",ar1_enc);
+
+       s = lfsr_recovery32(ar0_enc ^ prng_successor(nt, 64), 0);
+  
+       for(t = s; t->odd | t->even; ++t) {
+               lfsr_rollback_word(t, 0, 0);
+               lfsr_rollback_word(t, nr0_enc, 1);
+               lfsr_rollback_word(t, uid ^ nt, 0);
+               crypto1_get_lfsr(t, &key);
+               crypto1_word(t, uid ^ nt, 0);
+               crypto1_word(t, nr1_enc, 1);
+               if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt, 64))) {
+                       PrintAndLog("Found Key: [%012"llx"]",key);
+                       isSuccess = TRUE;
+                       ++counter;
+                       if (counter==20)
+                               break;
+               }
+       }
+       free(s);
+       return isSuccess;
+}
+
+int tryMfk64(uint64_t myuid, uint8_t *data, uint8_t *outputkey ){
+
+       struct Crypto1State *revstate;
+       uint64_t key;     // recovered key
+       uint32_t uid;     // serial number
+       uint32_t nt;      // tag challenge
+       uint32_t nr_enc;  // encrypted reader challenge
+       uint32_t ar_enc;  // encrypted reader response
+       uint32_t at_enc;  // encrypted tag response
+       uint32_t ks2;     // keystream used to encrypt reader response
+       uint32_t ks3;     // keystream used to encrypt tag response
+
+       struct Crypto1State mpcs = {0, 0};
+       struct Crypto1State *pcs;
+       pcs = &mpcs;
+       
+       uid     = myuid;//(uint32_t)bytes_to_num(data +  0, 4);
+       nt              = *(uint32_t*)(data+8);
+       nr_enc = *(uint32_t*)(data+12);
+       ar_enc = *(uint32_t*)(data+16);
+       
+       crypto1_word(pcs, nr_enc , 1);
+       at_enc = prng_successor(nt, 96) ^ crypto1_word(pcs, 0, 0);
+
+       // printf("Recovering key for:\n");
+       // printf("  uid: %08x\n",uid);
+       // printf("   nt: %08x\n",nt);
+       // printf(" {nr}: %08x\n",nr_enc);
+       // printf(" {ar}: %08x\n",ar_enc);
+       // printf(" {at}: %08x\n",at_enc);
+
+       // Extract the keystream from the messages
+       ks2 = ar_enc ^ prng_successor(nt, 64);
+       ks3 = at_enc ^ prng_successor(nt, 96);
+
+       revstate = lfsr_recovery64(ks2, ks3);
+       lfsr_rollback_word(revstate, 0, 0);
+       lfsr_rollback_word(revstate, 0, 0);
+       lfsr_rollback_word(revstate, nr_enc, 1);
+       lfsr_rollback_word(revstate, uid ^ nt, 0);
+       crypto1_get_lfsr(revstate, &key);
+       PrintAndLog("Found Key: [%012"llx"]",key);
+       crypto1_destroy(revstate);
+       crypto1_destroy(pcs);
+       return 0;
+}
index e7d5f431194f92a4777bc2726c66aad8038ff0b4..82c65b55617fbef1edbb85ea33b324f82ee3bdae 100644 (file)
@@ -2,7 +2,7 @@
 // Merlok - June 2011
 // Roel - Dec 2009
 // Unknown author
-//
+// icemane - may 2015
 // 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.
@@ -19,5 +19,6 @@
 #include "common.h"
 
 int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key); 
-
+int tryMfk32(uint64_t myuid, uint8_t *data, uint8_t *outputkey );
+int tryMfk64(uint64_t myuid, uint8_t *data, uint8_t *outputkey );
 #endif
diff --git a/client/obj/reveng/.gitignore b/client/obj/reveng/.gitignore
new file mode 100644 (file)
index 0000000..07669e1
--- /dev/null
@@ -0,0 +1,35 @@
+# .gitignore
+# don't push these files to the repository
+
+*.log
+*.eml
+*.o
+*.a
+*.d
+*.elf
+*.s19
+*.map
+*.bin
+*.dll
+*.moc.cpp
+*.exe
+proxmark
+proxmark3
+flasher
+version.c
+lua
+luac
+
+fpga/*
+!fpga/tests
+!fpga/fpga_lf.bit
+!fpga/fpga_hf.bit
+!fpga/*.v
+!fpga/Makefile
+!fpga/fpga.ucf
+!fpga/xst_lf.scr
+!fpga/xst_hf.scr
+!fpga/go.bat
+!fpga/sim.tcl
+
+
diff --git a/client/platforms/.gitignore b/client/platforms/.gitignore
new file mode 100644 (file)
index 0000000..07669e1
--- /dev/null
@@ -0,0 +1,35 @@
+# .gitignore
+# don't push these files to the repository
+
+*.log
+*.eml
+*.o
+*.a
+*.d
+*.elf
+*.s19
+*.map
+*.bin
+*.dll
+*.moc.cpp
+*.exe
+proxmark
+proxmark3
+flasher
+version.c
+lua
+luac
+
+fpga/*
+!fpga/tests
+!fpga/fpga_lf.bit
+!fpga/fpga_hf.bit
+!fpga/*.v
+!fpga/Makefile
+!fpga/fpga.ucf
+!fpga/xst_lf.scr
+!fpga/xst_hf.scr
+!fpga/go.bat
+!fpga/sim.tcl
+
+
index 0e2a698c1b8ca3783f2a1bc16d980539c423ce22..c100bbea0985d05222f580adbf90d05d887540bd 100644 (file)
@@ -35,7 +35,7 @@ volatile static bool txcmd_pending = false;
 
 void SendCommand(UsbCommand *c) {
        #if 0
-               printf("Sending %d bytes\n", sizeof(UsbCommand));
+  printf("Sending %d bytes\n", sizeof(UsbCommand));
        #endif
 
        if (offline) {
@@ -47,110 +47,110 @@ void SendCommand(UsbCommand *c) {
        or disconnected. The main console thread is alive, but comm thread just spins here.
        Not good.../holiman
        **/
-       while(txcmd_pending);
-       txcmd = *c;
-       txcmd_pending = true;
+  while(txcmd_pending);
+  txcmd = *c;
+  txcmd_pending = true;
 }
 
 struct receiver_arg {
-       int run;
+  int run;
 };
 
 struct main_loop_arg {
-       int usb_present;
-       char *script_cmds_file;
+  int usb_present;
+  char *script_cmds_file;
 };
 
 byte_t rx[0x1000000];
 byte_t* prx = rx;
 
 static void *uart_receiver(void *targ) {
-       struct receiver_arg *arg = (struct receiver_arg*)targ;
-       size_t rxlen;
-       size_t cmd_count;
+  struct receiver_arg *arg = (struct receiver_arg*)targ;
+  size_t rxlen;
+  size_t cmd_count;
 
-       while (arg->run) {
-               rxlen = sizeof(UsbCommand);
+  while (arg->run) {
+    rxlen = sizeof(UsbCommand);
                if (uart_receive(sp, prx, &rxlen)) {
-                       prx += rxlen;
-                       if (((prx-rx) % sizeof(UsbCommand)) != 0) {
-                               continue;
-                       }
-                       cmd_count = (prx-rx) / sizeof(UsbCommand);
+      prx += rxlen;
+      if (((prx-rx) % sizeof(UsbCommand)) != 0) {
+        continue;
+      }
+      cmd_count = (prx-rx) / sizeof(UsbCommand);
 
                        for (size_t i = 0; i < cmd_count; i++) {
-                               UsbCommandReceived((UsbCommand*)(rx+(i*sizeof(UsbCommand))));
-                       }
-               }
-               prx = rx;
+        UsbCommandReceived((UsbCommand*)(rx+(i*sizeof(UsbCommand))));
+      }
+    }
+    prx = rx;
 
-               if(txcmd_pending) {
+    if(txcmd_pending) {
                        if (!uart_send(sp, (byte_t*) &txcmd, sizeof(UsbCommand))) {
-                               PrintAndLog("Sending bytes to proxmark failed");
-                       }
-                       txcmd_pending = false;
-               }
-       }
+        PrintAndLog("Sending bytes to proxmark failed");
+      }
+      txcmd_pending = false;
+    }
+  }
 
-       pthread_exit(NULL);
-       return NULL;
+  pthread_exit(NULL);
+  return NULL;
 }
 
 static void *main_loop(void *targ) {
-       struct main_loop_arg *arg = (struct main_loop_arg*)targ;
-       struct receiver_arg rarg;
-       char *cmd = NULL;
-       pthread_t reader_thread;
+  struct main_loop_arg *arg = (struct main_loop_arg*)targ;
+  struct receiver_arg rarg;
+  char *cmd = NULL;
+  pthread_t reader_thread;
   
-       if (arg->usb_present == 1) {
+  if (arg->usb_present == 1) {
                rarg.run = 1;
-               pthread_create(&reader_thread, NULL, &uart_receiver, &rarg);
-       }
+    pthread_create(&reader_thread, NULL, &uart_receiver, &rarg);
+  }
 
-       FILE *script_file = NULL;
+  FILE *script_file = NULL;
        char script_cmd_buf[256];  // iceman, needs lua script the same file_path_buffer as the rest
 
        if (arg->script_cmds_file) {
-               script_file = fopen(arg->script_cmds_file, "r");
+    script_file = fopen(arg->script_cmds_file, "r");
                if (script_file) {
-                       printf("using 'scripting' commands file %s\n", arg->script_cmds_file);
-               }
-       }
+      printf("using 'scripting' commands file %s\n", arg->script_cmds_file);
+    }
+  }
 
        read_history(".history");
 
        while(1)  {
 
-               // If there is a script file
-               if (script_file)
-               {
+    // If there is a script file
+    if (script_file)
+    {
                        if (!fgets(script_cmd_buf, sizeof(script_cmd_buf), script_file)) {
-                               fclose(script_file);
-                               script_file = NULL;
+        fclose(script_file);
+        script_file = NULL;
                        } else {
-                               char *nl;
-                               nl = strrchr(script_cmd_buf, '\r');
-                               if (nl) *nl = '\0';
+        char *nl;
+        nl = strrchr(script_cmd_buf, '\r');
+        if (nl) *nl = '\0';
                                
-                               nl = strrchr(script_cmd_buf, '\n');
-                               if (nl) *nl = '\0';
+        nl = strrchr(script_cmd_buf, '\n');
+        if (nl) *nl = '\0';
 
                                if ((cmd = (char*) malloc(strlen(script_cmd_buf) + 1)) != NULL) {
-                                       memset(cmd, 0, strlen(script_cmd_buf));
-                                       strcpy(cmd, script_cmd_buf);
-                                       printf("%s\n", cmd);
-                               }
-                       }
-               }
+          memset(cmd, 0, strlen(script_cmd_buf));
+          strcpy(cmd, script_cmd_buf);
+          printf("%s\n", cmd);
+        }
+      }
+    }
                
                if (!script_file) {
-                       cmd = readline(PROXPROMPT);
+      cmd = readline(PROXPROMPT);
                }
                
                if (cmd) {
 
                        while(cmd[strlen(cmd) - 1] == ' ')
-                               cmd[strlen(cmd) - 1] = 0x00;
+        cmd[strlen(cmd) - 1] = 0x00;
                        
                        if (cmd[0] != 0x00) {
                                if (strncmp(cmd, "quit", 4) == 0) {
@@ -169,19 +169,19 @@ static void *main_loop(void *targ) {
   
        write_history(".history");
   
-       if (arg->usb_present == 1) {
-               rarg.run = 0;
-               pthread_join(reader_thread, NULL);
-       }
+  if (arg->usb_present == 1) {
+    rarg.run = 0;
+    pthread_join(reader_thread, NULL);
+  }
 
        if (script_file) {
-               fclose(script_file);
-               script_file = NULL;
-       }
+    fclose(script_file);
+    script_file = NULL;
+  }
 
-       ExitGraphics();
-       pthread_exit(NULL);
-       return NULL;
+  ExitGraphics();
+  pthread_exit(NULL);
+  return NULL;
 }
 
 static void dumpAllHelp(int markdown)
index 8236bfe71fb345cbd5c3b3066cc40f779cae8277..a634fd68179bf1d29b3bb4a8a29fed6fde3d3080 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "usb_cmd.h"
 
-#define PROXPROMPT "proxmark3> "
+#define PROXPROMPT "pm3 --> "
 
 void SendCommand(UsbCommand *c);
 
diff --git a/client/reveng/bmpbit.c b/client/reveng/bmpbit.c
new file mode 100644 (file)
index 0000000..39a29e6
--- /dev/null
@@ -0,0 +1,86 @@
+/* bmpbit.c
+ * Greg Cook, 9/Apr/2015
+ */
+
+/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Gregory Cook
+ *
+ * This file is part of CRC RevEng.
+ *
+ * CRC RevEng 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.
+ *
+ * CRC RevEng 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 CRC RevEng.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef BMPTST
+#  include <stdio.h>
+#  include <stdlib.h>
+#else
+#  define FILE void
+#endif
+#include "reveng.h"
+
+#if (defined BMPTST) || (BMP_BIT < 32)
+/* Size in bits of a bmp_t.  Not necessarily a power of two. */
+int bmpbit;
+
+/* The highest power of two that is strictly less than BMP_BIT.
+ * Initialises the index of a binary search for set bits in a bmp_t.
+ * (Computed correctly for BMP_BIT >= 2)
+ */
+int bmpsub;
+
+void
+setbmp(void) {
+       /* Initialise BMP_BIT and BMP_SUB for the local architecture. */
+       bmp_t bmpmax = ~(bmp_t) 0;
+
+       bmpbit = 0; bmpsub = 1;
+
+       while(bmpmax) {
+               bmpmax <<= 1;
+               ++bmpbit;
+       }
+
+       while((bmpsub | (bmpsub - 1)) < bmpbit - 1)
+               bmpsub <<= 1;
+}
+#endif
+
+#ifdef BMPTST
+int
+main(int argc, char *argv[]) {
+       /* check the compile-time bitmap width is correct, otherwise
+        * searches run forever. */
+#  if BMP_BIT > 0
+       setbmp();
+       if(BMP_BIT != bmpbit || BMP_SUB != bmpsub) {
+               fprintf(stderr,"reveng: configuration fault.  Update "
+                       "config.h with these definitions and "
+                       "recompile:\n"
+                       "\t#define BMP_BIT   %d\n"
+                       "\t#define BMP_SUB   %d\n",
+                       bmpbit, bmpsub);
+               exit(EXIT_FAILURE);
+       }
+#  endif /* BMP_BIT > 0 */
+       /* check the bitmap constant macro */
+       if(~(bmp_t) 0 != ~BMP_C(0)) {
+               fprintf(stderr, "reveng: configuration fault.  Edit "
+                       "the definition of BMP_C() in config.h to "
+                       "match BMP_T and recompile.\n");
+               exit(EXIT_FAILURE);
+       }
+       exit(EXIT_SUCCESS);
+}
+
+#endif /* BMPTST */
diff --git a/client/reveng/cli.c b/client/reveng/cli.c
new file mode 100644 (file)
index 0000000..fe1155d
--- /dev/null
@@ -0,0 +1,616 @@
+/* cli.c
+ * Greg Cook, 9/Apr/2015
+ */
+
+/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Gregory Cook
+ *
+ * This file is part of CRC RevEng.
+ *
+ * CRC RevEng 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.
+ *
+ * CRC RevEng 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 CRC RevEng.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 2015-04-03: added -z
+ * 2013-09-16: do not search with -M
+ * 2013-06-11: uprog() suppresses first progress report
+ * 2013-04-22: uprog() prints poly same as mtostr()
+ * 2013-02-07: added -q, uprog(), removed -W, R_ODDLY
+ * 2012-05-24: -D dumps parameters of all models
+ * 2012-03-03: added code to test sort order of model table
+ * 2012-02-20: set stdin to binary (MinGW). offer -D if preset unknown.
+ * 2011-09-06: -s reads arguments once. stdin not closed.
+ * 2011-09-06: fixed bad argument-freeing loops.
+ * 2011-08-27: validates BMP_C()
+ * 2011-08-26: validates BMPBIT and BMPSUB
+ * 2011-08-25: fixed Init/Xorout reflection logic in -V and -v
+ * 2011-01-17: fixed ANSI C warnings
+ * 2011-01-15: added NOFORCE
+ * 2011-01-14: added -k, -P
+ * 2011-01-10: reorganised switches, added -V, -X
+ * 2010-12-26: renamed CRC RevEng
+ * 2010-12-18: implemented -c, -C
+ * 2010-12-14: added and implemented -d, -D, fixed -ipx entry
+ * 2010-12-11: implemented -e. first tests
+ * 2010-12-10: finalised option processing. started input validation
+ * 2010-12-07: started cli
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "getopt.h"
+#ifdef _WIN32
+#  include <io.h>
+#  include <fcntl.h>
+#  ifndef STDIN_FILENO
+#    define STDIN_FILENO 0
+#  endif /* STDIN_FILENO */
+#endif /* _WIN32 */
+
+#include "reveng.h"
+
+static FILE *oread(const char *);
+static poly_t rdpoly(const char *, int, int);
+static void usage(void);
+
+static const char *myname = "reveng"; /* name of our program */
+
+int reveng_main(int argc, char *argv[]) {
+       /* Command-line interface for CRC RevEng.
+        * Process options and switches in the argument list and
+        * run the required function.
+        */
+
+       /* default values */
+       model_t model = {
+               PZERO,          /* no CRC polynomial, user must specify */
+               PZERO,          /* Init = 0 */
+               P_BE,           /* RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h */
+               PZERO,          /* XorOut = 0 */
+               PZERO,          /* check value unused */
+               NULL            /* no model name */
+       };
+       int ibperhx = 8, obperhx = 8;
+       int rflags = 0, uflags = 0; /* search and UI flags */
+
+       unsigned long width = 0UL;
+       int c, mode = 0, args, psets, pass;
+       poly_t apoly, crc, qpoly = PZERO, *apolys, *pptr = NULL, *qptr = NULL;
+       model_t pset = model, *candmods, *mptr;
+       char *string;
+
+       myname = argv[0];
+
+       /* stdin must be binary */
+#ifdef _WIN32
+       _setmode(STDIN_FILENO, _O_BINARY);
+#endif /* _WIN32 */
+
+       SETBMP();
+
+       pos=0;
+       optind=1;
+       do {
+               c=getopt(argc, argv, "?A:BDFLMP:SVXa:bcdefhi:k:lm:p:q:rstuvw:x:yz");
+               switch(c) {
+                       case 'A': /* A: bits per output character */
+                       case 'a': /* a: bits per character */
+                               if((obperhx = atoi(optarg)) > BMP_BIT) {
+                                       fprintf(stderr,"%s: argument to -%c must be between 1 and %d\n", myname, c, BMP_BIT);
+                                       return 0;
+                                       //exit(EXIT_FAILURE);
+                               }
+                               if(c == 'a') ibperhx = obperhx;
+                               break;
+                       case 'b': /* b  big-endian (RefIn = false, RefOut = false ) */
+                               model.flags &= ~P_REFIN;
+                               rflags |= R_HAVERI;
+                               /* fall through: */
+                       case 'B': /* B  big-endian output (RefOut = false) */
+                               model.flags &= ~P_REFOUT;
+                               rflags |= R_HAVERO;
+                               mnovel(&model);
+                               /* fall through: */
+                       case 'r': /* r  right-justified */
+                               model.flags |= P_RTJUST;
+                               break;
+                       case 'c': /* c  calculate CRC */
+                       case 'D': /* D  list primary model names */
+                       case 'd': /* d  dump CRC model */
+                       case 'e': /* e  echo arguments */
+                       case 's': /* s  search for algorithm */
+                       case 'v': /* v  calculate reversed CRC */
+                               if(mode) {
+                                       fprintf(stderr,"%s: more than one mode switch specified.  Use %s -h for help.\n", myname, myname);
+                                       return 0;
+                                       //exit(EXIT_FAILURE);
+                               }
+                               mode = c;
+                               break;
+                       case 'F': /* F  force search */
+#ifndef NOFORCE
+                               uflags |= C_FORCE;
+#endif
+                               break;
+                       case 'f': /* f  arguments are filenames */
+                               uflags |= C_INFILE;
+                               break;
+                       case 'h': /* h  get help / usage */
+                       case 'u': /* u  get help / usage */
+                       case '?': /* ?  get help / usage */
+                       default:
+                               usage();
+                               return 0;
+                               //exit(EXIT_FAILURE);
+                               break;
+                       case 'i': /* i: Init value */
+                               pptr = &model.init;
+                               rflags |= R_HAVEI;
+                               goto ippx;
+                       case 'k': /* k: polynomial in Koopman notation */
+                               pfree(&model.spoly);
+                               model.spoly = strtop(optarg, 0, 4);
+                               pkchop(&model.spoly);
+                               width = plen(model.spoly);
+                               rflags |= R_HAVEP;
+                               mnovel(&model);
+                               break;
+                       case 'l': /* l  little-endian input and output */
+                               model.flags |= P_REFIN;
+                               rflags |= R_HAVERI;
+                               /* fall through: */
+                       case 'L': /* L  little-endian output */
+                               model.flags |= P_REFOUT;
+                               rflags |= R_HAVERO;
+                               mnovel(&model);
+                               /* fall through: */
+                       case 't': /* t  left-justified */
+                               model.flags &= ~P_RTJUST;
+                               break;
+                       case 'm': /* m: select preset CRC model */
+                               if(!(c = mbynam(&model, optarg))) {
+                                       fprintf(stderr,"%s: preset model '%s' not found.  Use %s -D to list presets.\n", myname, optarg, myname);
+                                       return 0;
+                                       //exit(EXIT_FAILURE);
+                               }
+                               if(c < 0){
+                                       uerror("no preset models available");
+                                       return 0;
+                               }
+                               /* must set width so that parameter to -ipx is not zeroed */
+                               width = plen(model.spoly);
+                               rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX;
+                               break;
+                       case 'M': /* M  non-augmenting algorithm */
+                               model.flags &= ~P_MULXN;
+                               break;
+                       case 'P': /* P: reversed polynomial */
+                       case 'p': /* p: polynomial */
+                               pptr = &model.spoly;
+                               rflags &= ~R_HAVEQ;
+                               rflags |= R_HAVEP;
+ippx:
+                               pfree(pptr);
+                               *pptr = strtop(optarg, 0, 4);
+                               pright(pptr, width);
+                               if(c == 'P')
+                                       prev(pptr);
+                               mnovel(&model);
+                               break;
+                       case 'q': /* q: range end polynomial */
+                               pptr = &qpoly;
+                               rflags &= ~R_HAVEP;
+                               rflags |= R_HAVEQ;
+                               goto ippx;
+                       case 'S': /* s  space between output characters */
+                               model.flags |= P_SPACE;
+                               break;
+                       case 'V': /* v  reverse algorithm */
+                               /* Distinct from the -v switch as the
+                                * user will have to reverse his or her
+                                * own arguments.  The user cannot dump
+                                * the model generated by -v either.
+                                */
+                               mrev(&model);
+                               break;
+                       case 'w': /* w: CRC width = order - 1 */
+                               width = (unsigned long) atol(optarg);
+                               break;
+                       case 'X': /* X  print uppercase hex */
+                               model.flags |= P_UPPER;
+                               break;
+                       case 'x': /* x: XorOut value */
+                               pptr = &model.xorout;
+                               rflags |= R_HAVEX;
+                               goto ippx;
+                       case 'y': /* y  little-endian byte order in files */
+                               model.flags |= P_LTLBYT;
+                               break;
+                       case 'z': /* z  raw binary arguments */
+                               model.flags |= P_DIRECT;
+                               break;
+                       case -1: /* no more options, continue */
+                               ;
+               }
+       } while(c != -1);
+
+       /* canonicalise the model, so the one we dump is the one we
+        * calculate with (not with -s, spoly may be blank which will
+        * normalise to zero and clear init and xorout.)
+        */
+       if(mode != 's')
+               mcanon(&model);
+
+       switch(mode) {
+               case 'v': /* v  calculate reversed CRC */
+                       /* Distinct from the -V switch as this causes
+                        * the arguments and output to be reversed as well.
+                        */
+                       /* reciprocate Poly */
+                       prcp(&model.spoly);
+
+                       /* mrev() does:
+                        *   if(refout) prev(init); else prev(xorout);
+                        * but here the entire argument polynomial is
+                        * reflected, not just the characters, so RefIn
+                        * and RefOut are not inverted as with -V.
+                        * Consequently Init is the mirror image of the
+                        * one resulting from -V, and so we have:
+                        */
+                       if(~model.flags & P_REFOUT) {
+                               prev(&model.init);
+                               prev(&model.xorout);
+                       }
+
+                       /* swap init and xorout */
+                       apoly = model.init;
+                       model.init = model.xorout;
+                       model.xorout = apoly;
+
+                       /* fall through: */
+               case 'c': /* c  calculate CRC */
+
+                       /* validate inputs */
+                       /* if(plen(model.spoly) == 0) {
+                        *      fprintf(stderr,"%s: no polynomial specified for -%c (add -w WIDTH -p POLY)\n", myname, mode);
+                        *      exit(EXIT_FAILURE);
+                        * }
+                        */
+
+                       /* in the Williams model, xorout is applied after the refout stage.
+                        * as refout is part of ptostr(), we reverse xorout here.
+                        */
+                       if(model.flags & P_REFOUT)
+                               prev(&model.xorout);
+
+                       for(; optind < argc; ++optind) {
+                               if(uflags & C_INFILE)
+                                       apoly = rdpoly(argv[optind], model.flags, ibperhx);
+                               else
+                                       apoly = strtop(argv[optind], model.flags, ibperhx);
+
+                               if(mode == 'v')
+                                       prev(&apoly);
+
+                               crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags);
+
+                               if(mode == 'v')
+                                       prev(&crc);
+
+                               string = ptostr(crc, model.flags, obperhx);
+                               puts(string);
+                               free(string);
+                               pfree(&crc);
+                               pfree(&apoly);
+                       }
+                       break;
+               case 'D': /* D  dump all models */
+                       args = mcount();
+                       if(!args){
+                               uerror("no preset models available");
+                               return 0;
+                       }
+                       for(mode = 0; mode < args; ++mode) {
+                               mbynum(&model, mode);
+                               mcanon(&model);
+                               ufound(&model);
+                       }
+                       break;
+               case 'd': /* d  dump CRC model */
+                       /* maybe we don't want to do this:
+                        * either attaching names to arbitrary models or forcing to a preset
+                        * mmatch(&model, M_OVERWR);
+                        */
+                       if(~model.flags & P_MULXN){
+                               uerror("not a Williams model compliant algorithm");
+                               return 0;
+                       }
+                       string = mtostr(&model);
+                       puts(string);
+                       free(string);
+                       break;
+               case 'e': /* e  echo arguments */
+                       for(; optind < argc; ++optind) {
+                               if(uflags & C_INFILE)
+                                       apoly = rdpoly(argv[optind], model.flags, ibperhx);
+                               else
+                                       apoly = strtop(argv[optind], model.flags, ibperhx);
+
+                               psum(&apoly, model.init, 0UL);
+                               string = ptostr(apoly, model.flags, obperhx);
+                               puts(string);
+                               free(string);
+                               pfree(&apoly);
+                       }
+                       break;
+               case 's': /* s  search for algorithm */
+                       if(!width){
+                               uerror("must specify positive -k or -w before -s");
+                               return 0;
+                       }
+                       if(~model.flags & P_MULXN){
+                               uerror("cannot search for non-Williams compliant models");
+                               return 0;
+                       }
+                       praloc(&model.spoly, width);
+                       praloc(&model.init, width);
+                       praloc(&model.xorout, width);
+                       if(!plen(model.spoly))
+                               palloc(&model.spoly, width);
+                       else
+                               width = plen(model.spoly);
+
+                       /* special case if qpoly is zero, search to end of range */
+                       if(!ptst(qpoly))
+                               rflags &= ~R_HAVEQ;
+
+                       /* allocate argument array */
+                       args = argc - optind;
+                       if(!(apolys = malloc(args * sizeof(poly_t)))){
+                               uerror("cannot allocate memory for argument list");
+                               return 0;
+                       }
+
+                       for(pptr = apolys; optind < argc; ++optind) {
+                               if(uflags & C_INFILE)
+                                       *pptr++ = rdpoly(argv[optind], model.flags, ibperhx);
+                               else
+                                       *pptr++ = strtop(argv[optind], model.flags, ibperhx);
+                       }
+                       /* exit value of pptr is used hereafter! */
+
+                       /* if endianness not specified, try
+                        * little-endian then big-endian.
+                        * NB: crossed-endian algorithms will not be
+                        * searched.
+                        */
+
+                       /* scan against preset models */
+                       if(~uflags & C_FORCE) {
+                               pass = 0;
+                               do {
+                                       psets = mcount();
+                                       while(psets) {
+                                               mbynum(&pset, --psets);
+                                               /* skip if different width, or refin or refout don't match */
+                                               if(plen(pset.spoly) != width || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT))
+                                                       continue;
+                                               /* skip if the preset doesn't match specified parameters */
+                                               if(rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly))
+                                                       continue;
+                                               if(rflags & R_HAVEI && psncmp(&model.init, &pset.init))
+                                                       continue;
+                                               if(rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
+                                                       continue;
+                                               apoly = pclone(pset.xorout);
+                                               if(pset.flags & P_REFOUT)
+                                                       prev(&apoly);
+                                               for(qptr = apolys; qptr < pptr; ++qptr) {
+                                                       crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
+                                                       if(ptst(crc)) {
+                                                               pfree(&crc);
+                                                               break;
+                                                       } else
+                                                               pfree(&crc);
+                                               }
+                                               pfree(&apoly);
+                                               if(qptr == pptr) {
+                                                       /* the selected model solved all arguments */
+                                                       mcanon(&pset);
+                                                       ufound(&pset);
+                                                       uflags |= C_RESULT;
+                                               }
+                                       }
+                                       mfree(&pset);
+
+                                       /* toggle refIn/refOut and reflect arguments */
+                                       if(~rflags & R_HAVERI) {
+                                               model.flags ^= P_REFIN | P_REFOUT;
+                                               for(qptr = apolys; qptr < pptr; ++qptr)
+                                                       prevch(qptr, ibperhx);
+                                       }
+                               } while(~rflags & R_HAVERI && ++pass < 2);
+                       }
+                       if(uflags & C_RESULT) {
+                               for(qptr = apolys; qptr < pptr; ++qptr)
+                                       pfree(qptr);
+                               //return 1;
+                               //exit(EXIT_SUCCESS);
+                       }
+                       if(!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)){
+                               uerror("cannot search for crossed-endian models");
+                               return 0;
+                       }
+                       pass = 0;
+                       do {
+                               mptr = candmods = reveng(&model, qpoly, rflags, args, apolys);
+                               if(mptr && plen(mptr->spoly))
+                                       uflags |= C_RESULT;
+                               while(mptr && plen(mptr->spoly)) {
+                                       /* results were printed by the callback
+                                        * string = mtostr(mptr);
+                                        * puts(string);
+                                        * free(string);
+                                        */
+                                       mfree(mptr++);
+                               }
+                               free(candmods);
+                               if(~rflags & R_HAVERI) {
+                                       model.flags ^= P_REFIN | P_REFOUT;
+                                       for(qptr = apolys; qptr < pptr; ++qptr)
+                                               prevch(qptr, ibperhx);
+                               }
+                       } while(~rflags & R_HAVERI && ++pass < 2);
+                       for(qptr = apolys; qptr < pptr; ++qptr)
+                               pfree(qptr);
+                       free(apolys);
+                       if(~uflags & C_RESULT)
+                               uerror("no models found");
+                       break;
+               default:  /* no mode specified */
+                       fprintf(stderr, "%s: no mode switch specified. Use %s -h for help.\n", myname, myname);
+                       //exit(EXIT_FAILURE);
+       }
+
+       return 1;
+       //exit(EXIT_SUCCESS);
+}
+
+void
+ufound(const model_t *model) {
+       /* Callback function to report each model found */
+       char *string;
+
+       if(!model) return;
+       /* generated models will be canonical */
+       string = mtostr(model);
+       puts(string);
+       free(string);
+}
+
+void
+uerror(const char *msg) {
+       /* Callback function to report fatal errors */
+       fprintf(stderr, "%s: %s\n", myname, msg);
+       return;
+       //exit(EXIT_FAILURE);
+}
+
+void
+uprog(const poly_t gpoly, int flags, unsigned long seq) {
+       /* Callback function to report search progress */
+       char *string;
+
+       /* Suppress first report in CLI */
+       if(!seq)
+               return;
+       string = ptostr(gpoly, P_RTJUST, 4);
+       fprintf(stderr, "%s: searching: width=%ld  poly=0x%s  refin=%s  refout=%s\n",
+                       myname, plen(gpoly), string,
+                       (flags & P_REFIN ? "true" : "false"),
+                       (flags & P_REFOUT ? "true" : "false")
+                       );
+       free(string);
+}
+
+static poly_t
+rdpoly(const char *name, int flags, int bperhx) {
+       /* read poly from file in chunks and report errors */
+
+       poly_t apoly = PZERO, chunk = PZERO;
+       FILE *input;
+
+       input = oread(name);
+       while(!feof(input) && !ferror(input)) {
+               chunk = filtop(input, BUFFER, flags, bperhx);
+               psum(&apoly, chunk, plen(apoly));
+               pfree(&chunk);
+       }
+       if(ferror(input)) {
+               fprintf(stderr,"%s: error condition on file '%s'\n", myname, name);
+               exit(EXIT_FAILURE);
+       }
+       /* close file unless stdin */
+       if(input == stdin)
+               /* reset EOF condition */
+               clearerr(input);
+       else if(fclose(input)) {
+               fprintf(stderr,"%s: error closing file '%s'\n", myname, name);
+               exit(EXIT_FAILURE);
+       }
+       return(apoly);
+}
+
+static FILE *
+oread(const char *name) {
+       /* open file for reading and report errors */
+       FILE *handle;
+
+       /* recognise special name '-' as standard input */
+       if(*name == '-' && name[1] == '\0')
+               return(stdin);
+       if(!(handle = fopen(name, "rb"))) {
+               fprintf(stderr, "%s: cannot open '%s' for reading\n", myname, name);
+               return 0;
+               //exit(EXIT_FAILURE);
+       }
+       return(handle);
+}
+
+static void
+usage(void) {
+       /* print usage if asked, or if syntax incorrect */
+       fprintf(stderr,
+                       "CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder\n"
+                       "Usage:\t");
+       fputs(myname, stderr);
+       fprintf(stderr,
+                       "\t-cdDesvhu? [-bBfFlLMrStVXyz]\n"
+                       "\t\t[-a BITS] [-A OBITS] [-i INIT] [-k KPOLY] [-m MODEL]\n"
+                       "\t\t[-p POLY] [-P RPOLY] [-q QPOLY] [-w WIDTH] [-x XOROUT]\n"
+                       "\t\t[STRING...]\n"
+                       "Options:\n"
+                       "\t-a BITS\t\tbits per character (1 to %d)\n"
+                       "\t-A OBITS\tbits per output character (1 to %d)\n"
+                       "\t-i INIT\t\tinitial register value\n"
+                       "\t-k KPOLY\tgenerator in Koopman notation (implies WIDTH)\n"
+                       "\t-m MODEL\tpreset CRC algorithm\n"
+                       "\t-p POLY\t\tgenerator or search range start polynomial\n"
+                       "\t-P RPOLY\treversed generator polynomial\n",
+                       BMP_BIT, BMP_BIT);
+       fprintf(stderr,
+                       "\t-q QPOLY\tsearch range end polynomial\n"
+                       "\t-w WIDTH\tregister size, in bits\n"
+                       "\t-x XOROUT\tfinal register XOR value\n"
+                       "Modifier switches:\n"
+                       "\t-b big-endian CRC\t\t-B big-endian CRC output\n"
+                       "\t-f read files named in STRINGs\t-F find presets less quickly\n"
+                       "\t-l little-endian CRC\t\t-L little-endian CRC output\n"
+                       "\t-M non-augmenting algorithm\t-r right-justified output\n"
+                       "\t-S print spaces between chars\t-t left-justified output\n"
+                       "\t-V reverse algorithm only\t-X print uppercase hex\n"
+                       "\t-y low bytes first in files\t-z raw binary STRINGs\n");
+       fprintf(stderr,
+                       "Mode switches:\n"
+                       "\t-c calculate CRCs\t\t-d dump algorithm parameters\n"
+                       "\t-D list preset algorithms\t-e echo (and reformat) input\n"
+                       "\t-s search for algorithm\t\t-v calculate reversed CRCs\n"
+                       "\t-h | -u | -? show this help\n"
+                       "\n"
+                       "Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Gregory Cook\n"
+                       "This is free software; see the source for copying conditions.  There is NO\n"
+                       "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
+                       "Version "
+                       VERSION
+                       "\t\t\t\t  <http://reveng.sourceforge.net/>\n");
+}
diff --git a/client/reveng/config.h b/client/reveng/config.h
new file mode 100644 (file)
index 0000000..084c79a
--- /dev/null
@@ -0,0 +1,92 @@
+/* config.h
+ * Greg Cook, 9/Apr/2015
+ */
+
+/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Gregory Cook
+ *
+ * This file is part of CRC RevEng.
+ *
+ * CRC RevEng 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.
+ *
+ * CRC RevEng 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 CRC RevEng.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H 1
+
+/*****************************************
+ *                                      *
+ *  Start of user configuration options  *
+ *                                      *
+ *****************************************/
+
+/* A type to contain polynomial coefficient bitmaps.
+ * Can be changed to 'unsigned long long' for some extended compilers.
+ * Adjust BMP_C(), BMP_BIT and BMP_SUB below if this is changed.
+ */
+
+#define BMP_T unsigned long
+
+/* Creates an appropriate numeric constant for bmp_t.
+ * If the underlying type is 'unsigned long long', change UL to ULL.
+ */
+
+#define BMP_C(n) (n##UL)
+
+/* Define BMPMACRO to turn the definitions of the size of a bmp_t into
+ * compile-time constants.  This improves efficiency but makes the code
+ * platform-specific.
+ */
+
+/* #define BMPMACRO 1 */
+
+/* Some enterprise users may wish to disable the -F switch to minimise CPU
+ * usage.  To do this, define the macro NOFORCE.
+ */
+
+/* #define NOFORCE  1 */
+
+/* Define PRESETS to compile CRC RevEng with the preset models from the
+ * CRC Catalogue.  This implies BMPMACRO and so makes the code platform-
+ * specific.
+ */
+
+#ifdef _WIN32
+ #define PRESETS  1 //
+#endif
+
+
+/* Macros defining the size of a bmp_t.
+ * Their values only matter if PRESETS and/or BMPMACRO are defined, in
+ * which case edit the macros below to suit your architecture.
+ * Otherwise, BMP_BIT and BMP_SUB will be redefined as aliases of bmpbit
+ * and bmpsub, global objects initialised at run time.
+ */
+
+/* Size in bits of a bmp_t.  Not necessarily a power of two. */
+
+#define BMP_BIT   32
+
+/* The highest power of two that is strictly less than BMP_BIT.
+ * Initialises the index of a binary search for set bits in a bmp_t.
+ */
+
+#define BMP_SUB   16
+
+/*****************************************
+ *                                      *
+ *   End of user configuration options   *
+ *                                      *
+ *****************************************/
+
+#endif /* CONFIG_H */
diff --git a/client/reveng/getopt.c b/client/reveng/getopt.c
new file mode 100644 (file)
index 0000000..abe9963
--- /dev/null
@@ -0,0 +1,81 @@
+/*----------------------------------------------------------------------
+
+    Replacement for Unix "getopt()", for DOS/Windows/etc.
+
+    getopt.c 1.3 2003/09/17 16:17:59
+
+    Copyright (C) 1998, 2003 by David A. Hinds -- All Rights Reserved
+
+    This file is part of ASPEX.
+
+    ASPEX is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    ASPEX 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 ASPEX; if not, write to the Free Software Foundation,
+    Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+----------------------------------------------------------------------*/
+
+#include "string.h"
+#include "stdio.h"
+#include "getopt.h"
+
+char *optarg;
+int optind = 1, opterr, optopt;
+int pos = 0;
+int getopt(int argc, char *argv[], const char *optstring)
+{
+    //static int pos = 0;
+    char *str;
+    
+    if (pos == 0) {
+       if ((optind >= argc) || (*argv[optind] != '-'))
+           return EOF;
+       pos = 1;
+       if (argv[optind][pos] == '\0')
+           return EOF;
+    }
+    
+    str = strchr(optstring, argv[optind][pos]);
+    if (str == NULL) {
+       optopt = argv[optind][pos];
+       if (opterr)
+           fprintf(stderr, "%s: illegal option -- %c\n", argv[0],
+                   optopt);
+       return '?';
+    }
+    
+    if (str[1] == ':') {
+       if (argv[optind][pos+1] != '\0') {
+           optarg = &argv[optind][pos+1];
+           return *str;
+       }
+       optind++;
+       if (optind >= argc) {
+           optopt = *str;
+           if (opterr)
+               fprintf(stderr, "%s: option requires an argument -- %c\n",
+                       argv[0], optopt);
+           return '?';
+       }
+       optarg = argv[optind];
+       optind++; pos = 0;
+       return *str;
+    }
+    else {
+       pos++;
+       if (argv[optind][pos] == '\0') {
+           optind++;
+           pos = 0;
+       }
+       return *str;
+    }
+}
diff --git a/client/reveng/getopt.h b/client/reveng/getopt.h
new file mode 100644 (file)
index 0000000..bf66d9b
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+    getopt.h 1.2 2003/09/17 16:17:59
+
+    Copyright (C) 1998, 2003 by David A. Hinds -- All Rights Reserved
+
+    This file is part of ASPEX.
+
+    ASPEX is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    ASPEX 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 ASPEX; if not, write to the Free Software Foundation,
+    Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+extern char *optarg;
+extern int optind, opterr, optopt, pos;
+int getopt(int argc, char *argv[], const char *optstring);
diff --git a/client/reveng/model.c b/client/reveng/model.c
new file mode 100644 (file)
index 0000000..2d45b2f
--- /dev/null
@@ -0,0 +1,823 @@
+/* model.c
+ * Greg Cook, 9/Apr/2015
+ */
+
+/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Gregory Cook
+ *
+ * This file is part of CRC RevEng.
+ *
+ * CRC RevEng 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.
+ *
+ * CRC RevEng 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 CRC RevEng.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 2014-01-14: added CRC-8/DVB-S2
+ * 2014-01-11: corrected CRC-40/GSM, added alias CRC-8/AES
+ * 2013-10-14: added CRC-13/BBC and six cdma2000 algorithms
+ * 2013-06-11: ensure BMP_BIT is an integer constant to compile presets
+ * 2013-01-20: big polynomials autogenerated, corrected CRC-82/DARC
+ * 2012-07-19: added CRC-8/EBU
+ * 2012-07-16: added CRC-15/MPT1327
+ * 2012-05-25: removed CRC-1/PARITY-EVEN, CRC-1/PARITY-ODD
+ * 2012-04-12: added model CRC-31/PHILIPS
+ * 2012-03-03: single-line Williams model string conversion
+ * 2012-02-20: corrected model CRC-6/DARC
+ * 2011-09-03: added mrev(), mnovel()
+ * 2011-08-28: added model CRC-64/XZ
+ * 2011-04-30: added models CRC-16/TMS37157 and CRC-A, and alias CRC-B
+ * 2011-02-10: made preset models ANSI C compliant
+ * 2011-01-17: fixed ANSI C warnings (except preset models)
+ * 2011-01-01: added mbynum(), mcount()
+ * 2010-12-26: renamed CRC RevEng
+ * 2010-12-18: minor change to mtostr() output format
+ * 2010-12-15: added mcmp(), mmatch()
+ * 2010-12-14: finished mbynam(), mnames(), mtostr()
+ * 2010-12-13: restarted with PCONST macros
+ * 2010-12-12: was having so much fun I didn't think to try compiling. :(
+ * 2010-12-12: started models.c
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "reveng.h"
+
+/* Private declarations */
+
+struct mpreset {
+       const unsigned long width;      /* width of CRC algorithm */
+       const bmp_t *const bspoly;      /* polynomial with highest-order term removed. length determines CRC width */
+       const bmp_t *const binit;       /* initial register value. length == poly.length */
+       const int flags;                /* P_REFIN and P_REFOUT indicate reflected input/output */
+       const bmp_t *const bxorout;     /* final register XOR mask. length == poly.length */
+       const bmp_t *const bcheck;      /* optional check value, the CRC of the UTF-8 string "123456789" */
+       const char *const name;         /* optional canonical name of the model */
+};
+
+struct malias {
+       const char *name;
+       const struct mpreset *model;
+       const int isprimry;
+};
+
+#ifdef PRESETS
+#  if BMP_BIT < 32
+#    error config.h: BMP_BIT must be an integer constant macro to compile presets
+#  else /* BMP_BIT */
+
+/* Big polynomial constants. */
+
+/* Directives for relink.pl */
+/* CONSTANT b40  = (40, 0x0004820009) */
+/* CONSTANT b40a = (40, 0xffffffffff) */
+/* CONSTANT b40b = (40, 0xd4164fc646) */
+/* CONSTANT b64  = (64, 0x42f0e1eba9ea3693) */
+/* CONSTANT b64a = (64, 0x6c40df5f0b497347) */
+/* CONSTANT b64b = (64, 0xffffffffffffffff) */
+/* CONSTANT b64c = (64, 0x62ec59e3f1a4f00a) */
+/* CONSTANT b64d = (64, 0x995dc9bbdf1939fa) */
+/* CONSTANT b82  = (82, 0x0308c0111011401440411) */
+/* CONSTANT b82a = (82, 0x09ea83f625023801fd612) */
+
+/* The next section was generated by relink.pl from the directives above. */
+
+/* DO NOT EDIT the section below, INCLUDING the next comment. */
+/* BEGIN AUTO-GENERATED CONSTANTS */
+#    if BMP_BIT >= 40
+static const bmp_t b40[] = {
+       BMP_C(0x0004820009) << (BMP_BIT - 40),
+};
+static const bmp_t b40a[] = {
+       BMP_C(0xffffffffff) << (BMP_BIT - 40),
+};
+static const bmp_t b40b[] = {
+       BMP_C(0xd4164fc646) << (BMP_BIT - 40),
+};
+#    else /* BMP_BIT */
+static const bmp_t b40[] = {
+       BMP_C(0x00048200) << (BMP_BIT - 32) | BMP_C(0x04) >> (39 - BMP_BIT),
+       BMP_C(0x09) << (BMP_BIT * 2 - 40),
+};
+static const bmp_t b40a[] = {
+       BMP_C(0xffffffff) << (BMP_BIT - 32) | BMP_C(0x7f) >> (39 - BMP_BIT),
+       BMP_C(0xff) << (BMP_BIT * 2 - 40),
+};
+static const bmp_t b40b[] = {
+       BMP_C(0xd4164fc6) << (BMP_BIT - 32) | BMP_C(0x23) >> (39 - BMP_BIT),
+       BMP_C(0x46) << (BMP_BIT * 2 - 40),
+};
+#    endif /* BMP_BIT */
+
+#    if BMP_BIT >= 64
+static const bmp_t b64[] = {
+       BMP_C(0x42f0e1eba9ea3693) << (BMP_BIT - 64),
+};
+static const bmp_t b64a[] = {
+       BMP_C(0x6c40df5f0b497347) << (BMP_BIT - 64),
+};
+static const bmp_t b64b[] = {
+       BMP_C(0xffffffffffffffff) << (BMP_BIT - 64),
+};
+static const bmp_t b64c[] = {
+       BMP_C(0x62ec59e3f1a4f00a) << (BMP_BIT - 64),
+};
+static const bmp_t b64d[] = {
+       BMP_C(0x995dc9bbdf1939fa) << (BMP_BIT - 64),
+};
+#    else /* BMP_BIT */
+static const bmp_t b64[] = {
+       BMP_C(0x42f0e1eb) << (BMP_BIT - 32) | BMP_C(0x54f51b49) >> (63 - BMP_BIT),
+       BMP_C(0xa9ea3693) << (BMP_BIT * 2 - 64),
+};
+static const bmp_t b64a[] = {
+       BMP_C(0x6c40df5f) << (BMP_BIT - 32) | BMP_C(0x05a4b9a3) >> (63 - BMP_BIT),
+       BMP_C(0x0b497347) << (BMP_BIT * 2 - 64),
+};
+static const bmp_t b64b[] = {
+       BMP_C(0xffffffff) << (BMP_BIT - 32) | BMP_C(0x7fffffff) >> (63 - BMP_BIT),
+       BMP_C(0xffffffff) << (BMP_BIT * 2 - 64),
+};
+static const bmp_t b64c[] = {
+       BMP_C(0x62ec59e3) << (BMP_BIT - 32) | BMP_C(0x78d27805) >> (63 - BMP_BIT),
+       BMP_C(0xf1a4f00a) << (BMP_BIT * 2 - 64),
+};
+static const bmp_t b64d[] = {
+       BMP_C(0x995dc9bb) << (BMP_BIT - 32) | BMP_C(0x6f8c9cfd) >> (63 - BMP_BIT),
+       BMP_C(0xdf1939fa) << (BMP_BIT * 2 - 64),
+};
+#    endif /* BMP_BIT */
+
+#    if BMP_BIT >= 82
+static const bmp_t b82[] = {
+       BMP_C(0x0308c0111011401440411) << (BMP_BIT - 82),
+};
+static const bmp_t b82a[] = {
+       BMP_C(0x09ea83f625023801fd612) << (BMP_BIT - 82),
+};
+#    elif BMP_BIT >= 41
+static const bmp_t b82[] = {
+       BMP_C(0x01846008880) << (BMP_BIT - 41) | BMP_C(0x08a00a20208) >> (81 - BMP_BIT),
+       BMP_C(0x11401440411) << (BMP_BIT * 2 - 82),
+};
+static const bmp_t b82a[] = {
+       BMP_C(0x04f541fb128) << (BMP_BIT - 41) | BMP_C(0x011c00feb09) >> (81 - BMP_BIT),
+       BMP_C(0x023801fd612) << (BMP_BIT * 2 - 82),
+};
+#    else /* BMP_BIT */
+static const bmp_t b82[] = {
+       BMP_C(0x0c230044) << (BMP_BIT - 32) | BMP_C(0x040) >> (40 - BMP_BIT),
+       BMP_C(0x40450051) << (BMP_BIT * 2 - 64) | BMP_C(0x00104) >> (80 - BMP_BIT * 2),
+       BMP_C(0x00411) << (BMP_BIT * 3 - 82),
+};
+static const bmp_t b82a[] = {
+       BMP_C(0x27aa0fd8) << (BMP_BIT - 32) | BMP_C(0x094) >> (40 - BMP_BIT),
+       BMP_C(0x9408e007) << (BMP_BIT * 2 - 64) | BMP_C(0x0f584) >> (80 - BMP_BIT * 2),
+       BMP_C(0x3d612) << (BMP_BIT * 3 - 82),
+};
+#    endif /* BMP_BIT */
+
+/* END AUTO-GENERATED CONSTANTS */
+/* DO NOT EDIT the section above, INCLUDING the previous comment. */
+
+/* Array of the polynomial bitmaps used in the model table. */
+static const bmp_t b32[] = {
+       BMP_C(0x00000000) << (BMP_BIT - 32),    /*   0 --  5,      00 */
+       BMP_C(0x000000af) << (BMP_BIT - 32),    /*   1 -- 32,000000af */
+       BMP_C(0x00010000) << (BMP_BIT - 32),    /*   2 -- 16,    0001 */
+       BMP_C(0x00020000) << (BMP_BIT - 32),    /*   3 -- 15,    0001 */
+       BMP_C(0x007e0000) << (BMP_BIT - 32),    /*   4 -- 16,    007e */
+       BMP_C(0x007f0000) << (BMP_BIT - 32),    /*   5 -- 16,    007f */
+       BMP_C(0x03400000) << (BMP_BIT - 32),    /*   6 -- 11,     01a */
+       BMP_C(0x0376e6e7) << (BMP_BIT - 32),    /*   7 -- 32,0376e6e7 */
+       BMP_C(0x04c11db7) << (BMP_BIT - 32),    /*   8 -- 32,04c11db7 */
+       BMP_C(0x05890000) << (BMP_BIT - 32),    /*   9 -- 16,    0589 */
+       BMP_C(0x07000000) << (BMP_BIT - 32),    /*  10 --  8,      07 */
+       BMP_C(0x09823b6e) << (BMP_BIT - 32),    /*  11 -- 31,04c11db7 */
+       BMP_C(0x0b3c0000) << (BMP_BIT - 32),    /*  12 -- 15,    059e */
+       BMP_C(0x0c000000) << (BMP_BIT - 32),    /*  13 --  6,      03 */
+       BMP_C(0x0fb30000) << (BMP_BIT - 32),    /*  14 -- 16,    0fb3 */
+       BMP_C(0x10210000) << (BMP_BIT - 32),    /*  15 -- 16,    1021 */
+       BMP_C(0x12000000) << (BMP_BIT - 32),    /*  16 --  7,      09 */
+       BMP_C(0x15000000) << (BMP_BIT - 32),    /*  17 --  8,      15 */
+       BMP_C(0x18000000) << (BMP_BIT - 32),    /*  18 --  6,      06 */
+       BMP_C(0x19d3c8d8) << (BMP_BIT - 32),    /*  19 -- 31,0ce9e46c */
+       BMP_C(0x1c000000) << (BMP_BIT - 32),    /*  20 --  6,      07 */
+       BMP_C(0x1d000000) << (BMP_BIT - 32),    /*  21 --  8,      1d */
+       BMP_C(0x1d0f0000) << (BMP_BIT - 32),    /*  22 -- 16,    1d0f */
+       BMP_C(0x1edc6f41) << (BMP_BIT - 32),    /*  23 -- 32,1edc6f41 */
+       BMP_C(0x1f23b800) << (BMP_BIT - 32),    /*  24 -- 24,  1f23b8 */
+       BMP_C(0x20140000) << (BMP_BIT - 32),    /*  25 -- 14,    0805 */
+       BMP_C(0x20b40000) << (BMP_BIT - 32),    /*  26 -- 14,    082d */
+       BMP_C(0x21890000) << (BMP_BIT - 32),    /*  27 -- 16,    2189 */
+       BMP_C(0x21cf0200) << (BMP_BIT - 32),    /*  28 -- 24,  21cf02 */
+       BMP_C(0x25000000) << (BMP_BIT - 32),    /*  29 --  8,      25 */
+       BMP_C(0x26b10000) << (BMP_BIT - 32),    /*  30 -- 16,    26b1 */
+       BMP_C(0x27d00000) << (BMP_BIT - 32),    /*  31 -- 13,    04fa */
+       BMP_C(0x28000000) << (BMP_BIT - 32),    /*  32 --  5,      05 */
+       BMP_C(0x29b10000) << (BMP_BIT - 32),    /*  33 -- 16,    29b1 */
+       BMP_C(0x30000000) << (BMP_BIT - 32),    /*  34 --  4,       3 */
+       BMP_C(0x3010bf7f) << (BMP_BIT - 32),    /*  35 -- 32,3010bf7f */
+       BMP_C(0x31000000) << (BMP_BIT - 32),    /*  36 --  8,      31 */
+       BMP_C(0x31c30000) << (BMP_BIT - 32),    /*  37 -- 16,    31c3 */
+       BMP_C(0x34000000) << (BMP_BIT - 32),    /*  38 --  6,      0d */
+       BMP_C(0x340bc6d9) << (BMP_BIT - 32),    /*  39 -- 32,340bc6d9 */
+       BMP_C(0x38000000) << (BMP_BIT - 32),    /*  40 --  5,      07 */
+       BMP_C(0x39000000) << (BMP_BIT - 32),    /*  41 --  8,      39 */
+       BMP_C(0x3d650000) << (BMP_BIT - 32),    /*  42 -- 16,    3d65 */
+       BMP_C(0x44c20000) << (BMP_BIT - 32),    /*  43 -- 16,    44c2 */
+       BMP_C(0x48000000) << (BMP_BIT - 32),    /*  44 --  5,      09 */
+       BMP_C(0x4acc0000) << (BMP_BIT - 32),    /*  45 -- 15,    2566 */
+       BMP_C(0x4b370000) << (BMP_BIT - 32),    /*  46 -- 16,    4b37 */
+       BMP_C(0x4c060000) << (BMP_BIT - 32),    /*  47 -- 16,    4c06 */
+       BMP_C(0x55000000) << (BMP_BIT - 32),    /*  48 --  8,      55 */
+       BMP_C(0x5d6dcb00) << (BMP_BIT - 32),    /*  49 -- 24,  5d6dcb */
+       BMP_C(0x60000000) << (BMP_BIT - 32),    /*  50 --  3,       3 */
+       BMP_C(0x63d00000) << (BMP_BIT - 32),    /*  51 -- 16,    63d0 */
+       BMP_C(0x64000000) << (BMP_BIT - 32),    /*  52 --  6,      19 */
+       BMP_C(0x66400000) << (BMP_BIT - 32),    /*  53 -- 10,     199 */
+       BMP_C(0x6f910000) << (BMP_BIT - 32),    /*  54 -- 16,    6f91 */
+       BMP_C(0x70000000) << (BMP_BIT - 32),    /*  55 --  4,       7 */
+       BMP_C(0x70a00000) << (BMP_BIT - 32),    /*  56 -- 11,     385 */
+       BMP_C(0x765e7680) << (BMP_BIT - 32),    /*  57 -- 32,765e7680 */
+       BMP_C(0x7979bd00) << (BMP_BIT - 32),    /*  58 -- 24,  7979bd */
+       BMP_C(0x7e000000) << (BMP_BIT - 32),    /*  59 --  8,      7e */
+       BMP_C(0x80050000) << (BMP_BIT - 32),    /*  60 -- 16,    8005 */
+       BMP_C(0x800d0000) << (BMP_BIT - 32),    /*  61 -- 16,    800d */
+       BMP_C(0x80f00000) << (BMP_BIT - 32),    /*  62 -- 12,     80f */
+       BMP_C(0x814141ab) << (BMP_BIT - 32),    /*  63 -- 32,814141ab */
+       BMP_C(0x864cfb00) << (BMP_BIT - 32),    /*  64 -- 24,  864cfb */
+       BMP_C(0x87315576) << (BMP_BIT - 32),    /*  65 -- 32,87315576 */
+       BMP_C(0x89ec0000) << (BMP_BIT - 32),    /*  66 -- 16,    89ec */
+       BMP_C(0x8b320000) << (BMP_BIT - 32),    /*  67 -- 15,    4599 */
+       BMP_C(0x8bb70000) << (BMP_BIT - 32),    /*  68 -- 16,    8bb7 */
+       BMP_C(0x8cc00000) << (BMP_BIT - 32),    /*  69 -- 10,     233 */
+       BMP_C(0x906e0000) << (BMP_BIT - 32),    /*  70 -- 16,    906e */
+       BMP_C(0x97000000) << (BMP_BIT - 32),    /*  71 --  8,      97 */
+       BMP_C(0x98000000) << (BMP_BIT - 32),    /*  72 --  6,      26 */
+       BMP_C(0x9b000000) << (BMP_BIT - 32),    /*  73 --  8,      9b */
+       BMP_C(0x9c000000) << (BMP_BIT - 32),    /*  74 --  6,      27 */
+       BMP_C(0x9e000000) << (BMP_BIT - 32),    /*  75 --  7,      4f */
+       BMP_C(0x9ecf0000) << (BMP_BIT - 32),    /*  76 -- 16,    9ecf */
+       BMP_C(0xa0970000) << (BMP_BIT - 32),    /*  77 -- 16,    a097 */
+       BMP_C(0xa1000000) << (BMP_BIT - 32),    /*  78 --  8,      a1 */
+       BMP_C(0xa6000000) << (BMP_BIT - 32),    /*  79 --  7,      53 */
+       BMP_C(0xa8000000) << (BMP_BIT - 32),    /*  80 --  5,      15 */
+       BMP_C(0xa833982b) << (BMP_BIT - 32),    /*  81 -- 32,a833982b */
+       BMP_C(0xabcdef00) << (BMP_BIT - 32),    /*  82 -- 24,  abcdef */
+       BMP_C(0xb2aa0000) << (BMP_BIT - 32),    /*  83 -- 16,    b2aa */
+       BMP_C(0xb4600000) << (BMP_BIT - 32),    /*  84 -- 11,     5a3 */
+       BMP_C(0xb4c80000) << (BMP_BIT - 32),    /*  85 -- 16,    b4c8 */
+       BMP_C(0xb704ce00) << (BMP_BIT - 32),    /*  86 -- 24,  b704ce */
+       BMP_C(0xbb3d0000) << (BMP_BIT - 32),    /*  87 -- 16,    bb3d */
+       BMP_C(0xbc000000) << (BMP_BIT - 32),    /*  88 --  8,      bc */
+       BMP_C(0xbd0be338) << (BMP_BIT - 32),    /*  89 -- 32,bd0be338 */
+       BMP_C(0xbf050000) << (BMP_BIT - 32),    /*  90 -- 16,    bf05 */
+       BMP_C(0xc0000000) << (BMP_BIT - 32),    /*  91 --  3,       6 */
+       BMP_C(0xc2b70000) << (BMP_BIT - 32),    /*  92 -- 16,    c2b7 */
+       BMP_C(0xc6c60000) << (BMP_BIT - 32),    /*  93 -- 16,    c6c6 */
+       BMP_C(0xc8000000) << (BMP_BIT - 32),    /*  94 --  5,      19 */
+       BMP_C(0xc8670000) << (BMP_BIT - 32),    /*  95 -- 16,    c867 */
+       BMP_C(0xcbf43926) << (BMP_BIT - 32),    /*  96 -- 32,cbf43926 */
+       BMP_C(0xd0000000) << (BMP_BIT - 32),    /*  97 --  8,      d0 */
+       BMP_C(0xd02a0000) << (BMP_BIT - 32),    /*  98 -- 15,    6815 */
+       BMP_C(0xd0db0000) << (BMP_BIT - 32),    /*  99 -- 16,    d0db */
+       BMP_C(0xd4d00000) << (BMP_BIT - 32),    /* 100 -- 12,     d4d */
+       BMP_C(0xd5000000) << (BMP_BIT - 32),    /* 101 --  8,      d5 */
+       BMP_C(0xd64e0000) << (BMP_BIT - 32),    /* 102 -- 16,    d64e */
+       BMP_C(0xda000000) << (BMP_BIT - 32),    /* 103 --  8,      da */
+       BMP_C(0xdaf00000) << (BMP_BIT - 32),    /* 104 -- 12,     daf */
+       BMP_C(0xe0000000) << (BMP_BIT - 32),    /* 105 --  3,       7 */
+       BMP_C(0xe3069283) << (BMP_BIT - 32),    /* 106 -- 32,e3069283 */
+       BMP_C(0xe5cc0000) << (BMP_BIT - 32),    /* 107 -- 16,    e5cc */
+       BMP_C(0xe7a80000) << (BMP_BIT - 32),    /* 108 -- 13,    1cf5 */
+       BMP_C(0xea000000) << (BMP_BIT - 32),    /* 109 --  7,      75 */
+       BMP_C(0xea820000) << (BMP_BIT - 32),    /* 110 -- 16,    ea82 */
+       BMP_C(0xec000000) << (BMP_BIT - 32),    /* 111 --  6,      3b */
+       BMP_C(0xf1300000) << (BMP_BIT - 32),    /* 112 -- 12,     f13 */
+       BMP_C(0xf4000000) << (BMP_BIT - 32),    /* 113 --  8,      f4 */
+       BMP_C(0xf5b00000) << (BMP_BIT - 32),    /* 114 -- 12,     f5b */
+       BMP_C(0xf6400000) << (BMP_BIT - 32),    /* 115 -- 10,     3d9 */
+       BMP_C(0xf8000000) << (BMP_BIT - 32),    /* 116 --  5,      1f */
+       BMP_C(0xfc000000) << (BMP_BIT - 32),    /* 117 --  6,      3f */
+       BMP_C(0xfc891918) << (BMP_BIT - 32),    /* 118 -- 32,fc891918 */
+       BMP_C(0xfd000000) << (BMP_BIT - 32),    /* 119 --  8,      fd */
+       BMP_C(0xfe000000) << (BMP_BIT - 32),    /* 120 --  7,      7f */
+       BMP_C(0xfedcba00) << (BMP_BIT - 32),    /* 121 -- 24,  fedcba */
+       BMP_C(0xfee80000) << (BMP_BIT - 32),    /* 122 -- 16,    fee8 */
+       BMP_C(0xff000000) << (BMP_BIT - 32),    /* 123 --  8,      ff */
+       BMP_C(0xffc00000) << (BMP_BIT - 32),    /* 124 -- 10,     3ff */
+       BMP_C(0xfff00000) << (BMP_BIT - 32),    /* 125 -- 12,     fff */
+       BMP_C(0xffff0000) << (BMP_BIT - 32),    /* 126 -- 16,    ffff */
+       BMP_C(0xfffffffe) << (BMP_BIT - 32),    /* 127 -- 31,7fffffff */
+       BMP_C(0xffffffff) << (BMP_BIT - 32),    /* 128 -- 32,ffffffff */
+};
+
+/* Table of preset CRC models.
+ * Sorted by left-justified polynomial for bsearch().
+ */
+static const struct mpreset models[] = {
+       {32UL, b32+  1, 0,       P_BE,   0,       b32+ 89, "XFER"              },       /*  0 */
+       {40UL, b40,     0,       P_BE,   b40a,    b40b,    "CRC-40/GSM"        },       /*  1 */
+       {32UL, b32+  8, 0,       P_BE,   b32+128, b32+ 57, "CRC-32/POSIX"      },       /*  2 */
+       {32UL, b32+  8, b32+128, P_BE,   0,       b32+  7, "CRC-32/MPEG-2"     },       /*  3 */
+       {32UL, b32+  8, b32+128, P_BE,   b32+128, b32+118, "CRC-32/BZIP2"      },       /*  4 */
+       {32UL, b32+  8, b32+128, P_LE,   0,       b32+ 39, "JAMCRC"            },       /*  5 */
+       {32UL, b32+  8, b32+128, P_LE,   b32+128, b32+ 96, "CRC-32"            },       /*  6 */
+       {16UL, b32+  9, 0,       P_BE,   0,       b32+  5, "CRC-16/DECT-X"     },       /*  7 */
+       {16UL, b32+  9, 0,       P_BE,   b32+  2, b32+  4, "CRC-16/DECT-R"     },       /*  8 */
+       { 8UL, b32+ 10, 0,       P_BE,   0,       b32+113, "CRC-8"             },       /*  9 */
+       { 8UL, b32+ 10, 0,       P_BE,   b32+ 48, b32+ 78, "CRC-8/ITU"         },       /* 10 */
+       { 8UL, b32+ 10, b32+123, P_LE,   0,       b32+ 97, "CRC-8/ROHC"        },       /* 11 */
+       {31UL, b32+ 11, b32+127, P_BE,   b32+127, b32+ 19, "CRC-31/PHILIPS"    },       /* 12 */
+       { 6UL, b32+ 13, 0,       P_LE,   0,       b32+ 18, "CRC-6/ITU"         },       /* 13 */
+       {82UL, b82,     0,       P_LE,   0,       b82a,    "CRC-82/DARC"       },       /* 14 */
+       {16UL, b32+ 15, 0,       P_BE,   0,       b32+ 37, "XMODEM"            },       /* 15 */
+       {16UL, b32+ 15, 0,       P_LE,   0,       b32+ 27, "KERMIT"            },       /* 16 */
+       {16UL, b32+ 15, b32+ 22, P_BE,   0,       b32+107, "CRC-16/AUG-CCITT"  },       /* 17 */
+       {16UL, b32+ 15, b32+ 66, P_LE,   0,       b32+ 30, "CRC-16/TMS37157"   },       /* 18 */
+       {16UL, b32+ 15, b32+ 83, P_LE,   0,       b32+ 51, "CRC-16/RIELLO"     },       /* 19 */
+       {16UL, b32+ 15, b32+ 93, P_LE,   0,       b32+ 90, "CRC-A"             },       /* 20 */
+       {16UL, b32+ 15, b32+126, P_BE,   0,       b32+ 33, "CRC-16/CCITT-FALSE"},       /* 21 */
+       {16UL, b32+ 15, b32+126, P_BE,   b32+126, b32+102, "CRC-16/GENIBUS"    },       /* 22 */
+       {16UL, b32+ 15, b32+126, P_LE,   0,       b32+ 54, "CRC-16/MCRF4XX"    },       /* 23 */
+       {16UL, b32+ 15, b32+126, P_LE,   b32+126, b32+ 70, "X-25"              },       /* 24 */
+       { 7UL, b32+ 16, 0,       P_BE,   0,       b32+109, "CRC-7"             },       /* 25 */
+       { 6UL, b32+ 20, b32+117, P_BE,   0,       b32+111, "CRC-6/CDMA2000-B"  },       /* 26 */
+       { 8UL, b32+ 21, b32+119, P_BE,   0,       b32+ 59, "CRC-8/I-CODE"      },       /* 27 */
+       { 8UL, b32+ 21, b32+123, P_LE,   0,       b32+ 71, "CRC-8/EBU"         },       /* 28 */
+       {32UL, b32+ 23, b32+128, P_LE,   b32+128, b32+106, "CRC-32C"           },       /* 29 */
+       {14UL, b32+ 25, 0,       P_LE,   0,       b32+ 26, "CRC-14/DARC"       },       /* 30 */
+       { 5UL, b32+ 32, b32+116, P_LE,   b32+116, b32+ 94, "CRC-5/USB"         },       /* 31 */
+       { 4UL, b32+ 34, 0,       P_LE,   0,       b32+ 55, "CRC-4/ITU"         },       /* 32 */
+       { 8UL, b32+ 36, 0,       P_LE,   0,       b32+ 78, "CRC-8/MAXIM"       },       /* 33 */
+       { 8UL, b32+ 41, 0,       P_LE,   0,       b32+ 17, "CRC-8/DARC"        },       /* 34 */
+       {16UL, b32+ 42, 0,       P_BE,   b32+126, b32+ 92, "CRC-16/EN-13757"   },       /* 35 */
+       {16UL, b32+ 42, 0,       P_LE,   b32+126, b32+110, "CRC-16/DNP"        },       /* 36 */
+       {64UL, b64,     0,       P_BE,   0,       b64a,    "CRC-64"            },       /* 37 */
+       {64UL, b64,     b64b,    P_BE,   b64b,    b64c,    "CRC-64/WE"         },       /* 38 */
+       {64UL, b64,     b64b,    P_LE,   b64b,    b64d,    "CRC-64/XZ"         },       /* 39 */
+       { 5UL, b32+ 44, b32+ 44, P_BE,   0,       b32+  0, "CRC-5/EPC"         },       /* 40 */
+       {24UL, b32+ 49, b32+ 82, P_BE,   0,       b32+ 24, "CRC-24/FLEXRAY-B"  },       /* 41 */
+       {24UL, b32+ 49, b32+121, P_BE,   0,       b32+ 58, "CRC-24/FLEXRAY-A"  },       /* 42 */
+       { 3UL, b32+ 50, b32+105, P_LE,   0,       b32+ 91, "CRC-3/ROHC"        },       /* 43 */
+       { 6UL, b32+ 52, 0,       P_LE,   0,       b32+ 72, "CRC-6/DARC"        },       /* 44 */
+       {11UL, b32+ 56, b32+  6, P_BE,   0,       b32+ 84, "CRC-11"            },       /* 45 */
+       {16UL, b32+ 60, 0,       P_BE,   0,       b32+122, "CRC-16/BUYPASS"    },       /* 46 */
+       {16UL, b32+ 60, 0,       P_LE,   0,       b32+ 87, "ARC"               },       /* 47 */
+       {16UL, b32+ 60, 0,       P_LE,   b32+126, b32+ 43, "CRC-16/MAXIM"      },       /* 48 */
+       {16UL, b32+ 60, b32+ 61, P_BE,   0,       b32+ 76, "CRC-16/DDS-110"    },       /* 49 */
+       {16UL, b32+ 60, b32+126, P_LE,   0,       b32+ 46, "MODBUS"            },       /* 50 */
+       {16UL, b32+ 60, b32+126, P_LE,   b32+126, b32+ 85, "CRC-16/USB"        },       /* 51 */
+       {12UL, b32+ 62, 0,       P_BE,   0,       b32+114, "CRC-12/DECT"       },       /* 52 */
+       {12UL, b32+ 62, 0,       P_BELE, 0,       b32+104, "CRC-12/3GPP"       },       /* 53 */
+       {32UL, b32+ 63, 0,       P_BE,   0,       b32+ 35, "CRC-32Q"           },       /* 54 */
+       {24UL, b32+ 64, b32+ 86, P_BE,   0,       b32+ 28, "CRC-24"            },       /* 55 */
+       {15UL, b32+ 67, 0,       P_BE,   0,       b32+ 12, "CRC-15"            },       /* 56 */
+       {16UL, b32+ 68, 0,       P_BE,   0,       b32+ 99, "CRC-16/T10-DIF"    },       /* 57 */
+       {10UL, b32+ 69, 0,       P_BE,   0,       b32+ 53, "CRC-10"            },       /* 58 */
+       { 8UL, b32+ 73, 0,       P_LE,   0,       b32+ 29, "CRC-8/WCDMA"       },       /* 59 */
+       { 8UL, b32+ 73, b32+123, P_BE,   0,       b32+103, "CRC-8/CDMA2000"    },       /* 60 */
+       { 6UL, b32+ 74, b32+117, P_BE,   0,       b32+ 38, "CRC-6/CDMA2000-A"  },       /* 61 */
+       { 7UL, b32+ 75, b32+120, P_LE,   0,       b32+ 79, "CRC-7/ROHC"        },       /* 62 */
+       {16UL, b32+ 77, 0,       P_BE,   0,       b32+ 14, "CRC-16/TELEDISK"   },       /* 63 */
+       { 5UL, b32+ 80, 0,       P_LE,   0,       b32+ 40, "CRC-5/ITU"         },       /* 64 */
+       {32UL, b32+ 81, b32+128, P_LE,   b32+128, b32+ 65, "CRC-32D"           },       /* 65 */
+       {16UL, b32+ 95, b32+126, P_BE,   0,       b32+ 47, "CRC-16/CDMA2000"   },       /* 66 */
+       {15UL, b32+ 98, 0,       P_BE,   b32+  3, b32+ 45, "CRC-15/MPT1327"    },       /* 67 */
+       { 8UL, b32+101, 0,       P_BE,   0,       b32+ 88, "CRC-8/DVB-S2"      },       /* 68 */
+       {13UL, b32+108, 0,       P_BE,   0,       b32+ 31, "CRC-13/BBC"        },       /* 69 */
+       {12UL, b32+112, b32+125, P_BE,   0,       b32+100, "CRC-12/CDMA2000"   },       /* 70 */
+       {10UL, b32+115, b32+124, P_BE,   0,       b32+ 69, "CRC-10/CDMA2000"   },       /* 71 */
+};
+#    define NPRESETS 72
+
+/* List of names with pointers to models, pre-sorted for use with bsearch() */
+static const struct malias aliases[] = {
+       {"ARC",                 models+47, 1},  /*   0 */
+       {"B-CRC-32",            models+ 4, 0},  /*   1 */
+       {"CKSUM",               models+ 2, 0},  /*   2 */
+       {"CRC-10",              models+58, 1},  /*   3 */
+       {"CRC-10/CDMA2000",     models+71, 1},  /*   4 */
+       {"CRC-11",              models+45, 1},  /*   5 */
+       {"CRC-12/3GPP",         models+53, 1},  /*   6 */
+       {"CRC-12/CDMA2000",     models+70, 1},  /*   7 */
+       {"CRC-12/DECT",         models+52, 1},  /*   8 */
+       {"CRC-13/BBC",          models+69, 1},  /*   9 */
+       {"CRC-14/DARC",         models+30, 1},  /*  10 */
+       {"CRC-15",              models+56, 1},  /*  11 */
+       {"CRC-15/MPT1327",      models+67, 1},  /*  12 */
+       {"CRC-16",              models+47, 0},  /*  13 */
+       {"CRC-16/ACORN",        models+15, 0},  /*  14 */
+       {"CRC-16/ARC",          models+47, 0},  /*  15 */
+       {"CRC-16/AUG-CCITT",    models+17, 1},  /*  16 */
+       {"CRC-16/BUYPASS",      models+46, 1},  /*  17 */
+       {"CRC-16/CCITT",        models+16, 0},  /*  18 */
+       {"CRC-16/CCITT-FALSE",  models+21, 1},  /*  19 */
+       {"CRC-16/CCITT-TRUE",   models+16, 0},  /*  20 */
+       {"CRC-16/CDMA2000",     models+66, 1},  /*  21 */
+       {"CRC-16/DARC",         models+22, 0},  /*  22 */
+       {"CRC-16/DDS-110",      models+49, 1},  /*  23 */
+       {"CRC-16/DECT-R",       models+ 8, 1},  /*  24 */
+       {"CRC-16/DECT-X",       models+ 7, 1},  /*  25 */
+       {"CRC-16/DNP",          models+36, 1},  /*  26 */
+       {"CRC-16/EN-13757",     models+35, 1},  /*  27 */
+       {"CRC-16/EPC",          models+22, 0},  /*  28 */
+       {"CRC-16/GENIBUS",      models+22, 1},  /*  29 */
+       {"CRC-16/I-CODE",       models+22, 0},  /*  30 */
+       {"CRC-16/IBM-SDLC",     models+24, 0},  /*  31 */
+       {"CRC-16/ISO-HDLC",     models+24, 0},  /*  32 */
+       {"CRC-16/LHA",          models+47, 0},  /*  33 */
+       {"CRC-16/MAXIM",        models+48, 1},  /*  34 */
+       {"CRC-16/MCRF4XX",      models+23, 1},  /*  35 */
+       {"CRC-16/RIELLO",       models+19, 1},  /*  36 */
+       {"CRC-16/SPI-FUJITSU",  models+17, 0},  /*  37 */
+       {"CRC-16/T10-DIF",      models+57, 1},  /*  38 */
+       {"CRC-16/TELEDISK",     models+63, 1},  /*  39 */
+       {"CRC-16/TMS37157",     models+18, 1},  /*  40 */
+       {"CRC-16/USB",          models+51, 1},  /*  41 */
+       {"CRC-16/VERIFONE",     models+46, 0},  /*  42 */
+       {"CRC-24",              models+55, 1},  /*  43 */
+       {"CRC-24/FLEXRAY-A",    models+42, 1},  /*  44 */
+       {"CRC-24/FLEXRAY-B",    models+41, 1},  /*  45 */
+       {"CRC-24/OPENPGP",      models+55, 0},  /*  46 */
+       {"CRC-3/ROHC",          models+43, 1},  /*  47 */
+       {"CRC-31/PHILIPS",      models+12, 1},  /*  48 */
+       {"CRC-32",              models+ 6, 1},  /*  49 */
+       {"CRC-32/AAL5",         models+ 4, 0},  /*  50 */
+       {"CRC-32/ADCCP",        models+ 6, 0},  /*  51 */
+       {"CRC-32/BZIP2",        models+ 4, 1},  /*  52 */
+       {"CRC-32/CASTAGNOLI",   models+29, 0},  /*  53 */
+       {"CRC-32/DECT-B",       models+ 4, 0},  /*  54 */
+       {"CRC-32/ISCSI",        models+29, 0},  /*  55 */
+       {"CRC-32/MPEG-2",       models+ 3, 1},  /*  56 */
+       {"CRC-32/POSIX",        models+ 2, 1},  /*  57 */
+       {"CRC-32C",             models+29, 1},  /*  58 */
+       {"CRC-32D",             models+65, 1},  /*  59 */
+       {"CRC-32Q",             models+54, 1},  /*  60 */
+       {"CRC-4/ITU",           models+32, 1},  /*  61 */
+       {"CRC-40/GSM",          models+ 1, 1},  /*  62 */
+       {"CRC-5/EPC",           models+40, 1},  /*  63 */
+       {"CRC-5/ITU",           models+64, 1},  /*  64 */
+       {"CRC-5/USB",           models+31, 1},  /*  65 */
+       {"CRC-6/CDMA2000-A",    models+61, 1},  /*  66 */
+       {"CRC-6/CDMA2000-B",    models+26, 1},  /*  67 */
+       {"CRC-6/DARC",          models+44, 1},  /*  68 */
+       {"CRC-6/ITU",           models+13, 1},  /*  69 */
+       {"CRC-64",              models+37, 1},  /*  70 */
+       {"CRC-64/WE",           models+38, 1},  /*  71 */
+       {"CRC-64/XZ",           models+39, 1},  /*  72 */
+       {"CRC-7",               models+25, 1},  /*  73 */
+       {"CRC-7/ROHC",          models+62, 1},  /*  74 */
+       {"CRC-8",               models+ 9, 1},  /*  75 */
+       {"CRC-8/AES",           models+28, 0},  /*  76 */
+       {"CRC-8/CDMA2000",      models+60, 1},  /*  77 */
+       {"CRC-8/DARC",          models+34, 1},  /*  78 */
+       {"CRC-8/DVB-S2",        models+68, 1},  /*  79 */
+       {"CRC-8/EBU",           models+28, 1},  /*  80 */
+       {"CRC-8/I-CODE",        models+27, 1},  /*  81 */
+       {"CRC-8/ITU",           models+10, 1},  /*  82 */
+       {"CRC-8/MAXIM",         models+33, 1},  /*  83 */
+       {"CRC-8/ROHC",          models+11, 1},  /*  84 */
+       {"CRC-8/WCDMA",         models+59, 1},  /*  85 */
+       {"CRC-82/DARC",         models+14, 1},  /*  86 */
+       {"CRC-A",               models+20, 1},  /*  87 */
+       {"CRC-B",               models+24, 0},  /*  88 */
+       {"CRC-CCITT",           models+16, 0},  /*  89 */
+       {"CRC-IBM",             models+47, 0},  /*  90 */
+       {"DOW-CRC",             models+33, 0},  /*  91 */
+       {"JAMCRC",              models+ 5, 1},  /*  92 */
+       {"KERMIT",              models+16, 1},  /*  93 */
+       {"MODBUS",              models+50, 1},  /*  94 */
+       {"PKZIP",               models+ 6, 0},  /*  95 */
+       {"R-CRC-16",            models+ 8, 0},  /*  96 */
+       {"X-25",                models+24, 1},  /*  97 */
+       {"X-CRC-12",            models+52, 0},  /*  98 */
+       {"X-CRC-16",            models+ 7, 0},  /*  99 */
+       {"XFER",                models+ 0, 1},  /* 100 */
+       {"XMODEM",              models+15, 1},  /* 101 */
+       {"ZMODEM",              models+15, 0},  /* 102 */
+       {NULL,                  NULL,      0},  /* terminating entry */
+};
+#    define NALIASES 103
+
+#  endif /* BMP_BIT */
+#else /* PRESETS */
+
+static const struct mpreset models[] = {
+       { 0UL, 0,       0,       P_BE,   0,       0,       NULL                },       /* terminating entry */
+};
+#  define NPRESETS 0
+
+static const struct malias aliases[] = {
+       {NULL,                  NULL,      0},  /* terminating entry */
+};
+#  define NALIASES 0
+
+#endif /* PRESETS */
+
+static const poly_t pzero = PZERO;
+
+static int acmp(const struct malias *, const struct malias *);
+static void munpack(model_t *, const struct mpreset *);
+
+/* copy a parameter of a preset into a model */
+#define MUNPACK(parm) \
+       praloc(&dest->parm, (src->b##parm ? src->width : 0UL)); \
+       for(iter=0UL, idx=0UL; iter < dest->parm.length; iter += BMP_BIT, ++idx)\
+               dest->parm.bitmap[idx] = src->b##parm[idx];
+
+/* Definitions */
+
+void
+mcpy(model_t *dest, const model_t *src) {
+       /* Copies the parameters of src to dest.
+        * dest must be an initialised model.
+        */
+       if(!dest || !src) return;
+       pcpy(&dest->spoly, src->spoly);
+       pcpy(&dest->init, src->init);
+       pcpy(&dest->xorout, src->xorout);
+       pcpy(&dest->check, src->check);
+       dest->flags = src->flags;
+       /* link to the name as it is static */
+       dest->name = src->name;
+}
+
+void
+mfree(model_t *model) {
+       /* Frees the parameters of model. */
+       if(!model) return;
+       pfree(&model->spoly);
+       pfree(&model->init);
+       pfree(&model->xorout);
+       pfree(&model->check);
+       /* not name as it is static */
+       /* not model either, it might point to an array! */
+}
+
+int
+mcmp(const model_t *a, const model_t *b) {
+       /* Compares a and b for identical effect, i.e. disregarding
+        * trailing zeroes in parameter polys.
+        * Intended for bsearch() to find a matching model in models[].
+        */
+       int result;
+       if(!a || !b) return(!b - !a);
+       if((result = psncmp(&a->spoly, &b->spoly))) return(result);
+       if((result = psncmp(&a->init, &b->init))) return(result);
+       if((a->flags & P_REFIN) && (~b->flags & P_REFIN)) return(1);
+       if((~a->flags & P_REFIN) && (b->flags & P_REFIN)) return(-1);
+       if((a->flags & P_REFOUT) && (~b->flags & P_REFOUT)) return(1);
+       if((~a->flags & P_REFOUT) && (b->flags & P_REFOUT)) return(-1);
+       return(psncmp(&a->xorout, &b->xorout));
+}
+
+int
+mbynam(model_t *dest, const char *key) {
+       /* Sets parameters in dest according to the model named by key.
+        */
+       struct malias akey = {NULL, NULL, 0}, *aptr;
+       char *ukey, *uptr;
+
+       if(!aliases->name)
+               return(-1);
+       if(!(ukey = malloc((size_t) 1 + strlen(key))))
+               uerror("cannot allocate memory for comparison string");
+       akey.name = uptr = ukey;
+       do
+               *uptr++ = toupper(*key);
+       while(*key++);
+
+       aptr = bsearch(&akey, aliases, NALIASES, sizeof(struct malias), (int (*)(const void *, const void *)) &acmp);
+       free(ukey);
+
+       if(aptr == NULL)
+               return(0);
+       munpack(dest, aptr->model);
+       return(1);
+}
+
+void
+mbynum(model_t *dest, int num) {
+       /* Sets parameters in dest according to the model indexed by num. */
+       if(num > NPRESETS)
+               num = NPRESETS;
+       munpack(dest, models+num);
+}
+
+int
+mcount(void) {
+       /* Returns the number of preset models. */
+       return(NPRESETS);
+}
+
+char *
+mnames(void) {
+       /* Returns a malloc()-ed string of the names of all preset
+        * models, separated by newlines and terminated by NULL.
+        * Aliases are not listed.
+        */
+       size_t size = 0;
+       char *string, *sptr;
+       const struct malias *aptr = aliases;
+
+       while(aptr->name) {
+               if(aptr->isprimry)
+                       size += strlen(aptr->name) + 1;
+               ++aptr;
+       }
+       if(!size) return(NULL);
+       if((string = malloc(size))) {
+               aptr = aliases;
+               sptr = string;
+               while(aptr->name) {
+                       if(aptr->isprimry) {
+                               strcpy(sptr, aptr->name);
+                               sptr += strlen(aptr->name);
+                               *sptr++ = '\n';
+                       }
+                       ++aptr;
+               }
+               *--sptr = '\0';
+       } else
+               uerror("cannot allocate memory for list of models");
+
+       return(string);
+}
+
+char *
+mtostr(const model_t *model) {
+       /* Returns a malloc()-ed string containing a Williams model
+        * record representing the input model.
+        * mcanon() should be called on the argument before printing.
+        */
+       size_t size;
+       char *polystr, *initstr, *xorotstr, *checkstr, strbuf[512], *string = NULL;
+
+       if(!model) return(NULL);
+       polystr = ptostr(model->spoly, P_RTJUST, 4);
+       initstr = ptostr(model->init, P_RTJUST, 4);
+       xorotstr = ptostr(model->xorout, P_RTJUST, 4);
+       checkstr = ptostr(model->check, P_RTJUST, 4);
+
+       sprintf(strbuf, "%lu", plen(model->spoly));
+       size =
+               70
+               + (model->name && *model->name ? 2 + strlen(model->name) : 6)
+               + strlen(strbuf)
+               + (polystr && *polystr ? strlen(polystr) : 6)
+               + (initstr && *initstr ? strlen(initstr) : 6)
+               + (model->flags & P_REFIN ? 4 : 5)
+               + (model->flags & P_REFOUT ? 4 : 5)
+               + (xorotstr && *xorotstr ? strlen(xorotstr) : 6)
+               + (checkstr && *checkstr ? strlen(checkstr) : 6);
+       if((string = malloc(size))) {
+               sprintf(strbuf, "\"%s\"", model->name);
+               sprintf(string,
+                               "width=%lu  "
+                               "poly=0x%s  "
+                               "init=0x%s  "
+                               "refin=%s  "
+                               "refout=%s  "
+                               "xorout=0x%s  "
+                               "check=0x%s  "
+                               "name=%s",
+                               plen(model->spoly),
+                               polystr && *polystr ? polystr : "(none)",
+                               initstr && *initstr ? initstr :  "(none)",
+                               (model->flags & P_REFIN) ? "true" : "false",
+                               (model->flags & P_REFOUT) ? "true" : "false",
+                               xorotstr && *xorotstr ? xorotstr : "(none)",
+                               checkstr && *checkstr ? checkstr : "(none)",
+                               (model->name && *model->name) ? strbuf : "(none)");
+       }
+       free(polystr);
+       free(initstr);
+       free(xorotstr);
+       free(checkstr);
+       if(!string)
+               uerror("cannot allocate memory for model description");
+       return(string);
+}
+
+void
+mmatch(model_t *model, int flags) {
+       /* searches models[] for a model matching the argument, and links a name if found
+        * if flags & M_OVERWR, copies the found model onto the argument. */
+       model_t *mptr;
+       if(!model) return;
+
+       mptr = bsearch(model, models, NPRESETS, sizeof(model_t), (int (*)(const void *, const void *)) &mcmp);
+       if(mptr) {
+               model->name = mptr->name;
+               if(flags & M_OVERWR)
+                       mcpy(model, mptr);
+       }
+}
+
+void
+mcanon(model_t *model) {
+       /* canonicalise a model */
+       unsigned long dlen;
+
+       if(!model) return;
+
+       /* extending on the right here. This preserves the functionality
+        * of a presumed working model.
+        */
+       psnorm(&model->spoly);
+       dlen = plen(model->spoly);
+       praloc(&model->init, dlen);
+       praloc(&model->xorout, dlen);
+
+       if(!plen(model->check))
+               mcheck(model);
+}
+
+void
+mcheck(model_t *model) {
+       /* calculate a check for the model */
+       poly_t checkstr, check;
+
+       /* generate the check string with the correct bit order */
+       checkstr = strtop("313233343536373839", model->flags, 8);
+       check = pcrc(checkstr, model->spoly, model->init, pzero, model->flags);
+       if(model->flags & P_REFOUT)
+               prev(&check);
+       psum(&check, model->xorout, 0UL);
+       model->check = check;
+       pfree(&checkstr);
+}
+
+void
+mrev(model_t *model) {
+       /* reverse the model to calculate reversed CRCs */
+       /* Here we invert RefIn and RefOut so that the user need only
+        * reverse the order of characters in the arguments, not the
+        * characters themselves.  If RefOut=True, the mirror image of
+        * Init seen through RefOut becomes XorOut, and as RefOut
+        * becomes false, the XorOut value moved to Init stays upright.
+        * If RefOut=False, Init transfers to XorOut without reflection
+        * but the new Init must be reflected to present the same image,
+        * as RefOut becomes true.
+        */
+       poly_t temp;
+
+       prcp(&model->spoly);
+       if(model->flags & P_REFOUT)
+               prev(&model->init);
+       else
+               prev(&model->xorout);
+
+       /* exchange init and xorout */
+       temp = model->init;
+       model->init = model->xorout;
+       model->xorout = temp;
+
+       /* invert refin and refout */
+       model->flags ^= P_REFIN | P_REFOUT;
+
+       mnovel(model);
+}
+
+void
+mnovel(model_t *model) {
+       /* remove name and check string from modified model */
+       model->name = NULL;
+       pfree(&model->check);
+}
+
+static int
+acmp(const struct malias *a, const struct malias *b) {
+       /* compares two aliases, for use in bsearch */
+       if(!a || !b) return(!b - !a);
+       if(!a->name || !b->name) return(!b->name - !a->name);
+       return(strcmp(a->name, b->name));
+}
+
+static void
+munpack(model_t *dest, const struct mpreset *src) {
+       /* Copies the parameters of src to dest.
+        * dest must be an initialised model.
+        */
+       unsigned long iter, idx;
+       if(!dest || !src) return;
+       MUNPACK(spoly);
+       MUNPACK(init);
+       MUNPACK(xorout);
+       MUNPACK(check);
+       dest->flags = src->flags;
+       /* link to the name as it is static */
+       dest->name = src->name;
+}
diff --git a/client/reveng/poly.c b/client/reveng/poly.c
new file mode 100644 (file)
index 0000000..1e22b8d
--- /dev/null
@@ -0,0 +1,1195 @@
+/* poly.c
+ * Greg Cook, 9/Apr/2015
+ */
+
+/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Gregory Cook
+ *
+ * This file is part of CRC RevEng.
+ *
+ * CRC RevEng 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.
+ *
+ * CRC RevEng 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 CRC RevEng.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 2015-04-03: added direct mode to strtop()
+ * 2014-01-11: added LOFS(), RNDUP()
+ * 2013-09-16: SIZE(), IDX(), OFS() macros bitshift if BMP_POF2
+ * 2013-02-07: conditional non-2^n fix, pmpar() return mask constant type
+ * 2013-01-17: fixed pfirst(), plast() for non-2^n BMP_BIT
+ * 2012-07-16: added pident()
+ * 2012-05-23: added pmpar()
+ * 2012-03-03: internal lookup tables stored better
+ * 2012-03-02: fixed full-width masking in filtop()
+ * 2011-09-06: added prevch()
+ * 2011-08-27: fixed zero test in piter()
+ * 2011-01-17: fixed ANSI C warnings, uses bmp_t type
+ * 2011-01-15: palloc() and praloc() gracefully handle lengths slightly
+ *            less than ULONG_MAX
+ * 2011-01-15: strtop() error on invalid argument. pkchop() special case
+ *            when argument all zeroes
+ * 2011-01-14: added pkchop()
+ * 2011-01-04: fixed bogus final length calculation in wide pcrc()
+ * 2011-01-02: faster, more robust prcp()
+ * 2011-01-01: commented functions, full const declarations, all-LUT rev()
+ * 2010-12-26: renamed CRC RevEng
+ * 2010-12-18: removed pmods(), finished pcrc(), added piter()
+ * 2010-12-17: roughed out pcrc(). difficult, etiam aberat musa heri :(
+ * 2010-12-15: added psnorm(), psncmp(); optimised pnorm(); fix to praloc()
+ * 2010-12-14: strtop() resets count between passes
+ * 2010-12-12: added pright()
+ * 2010-12-11: filtop won't read more than length bits
+ * 2010-12-10: finished filtop. 26 public functions
+ * 2010-12-05: finished strtop, pxsubs; unit tests
+ * 2010-12-02: project started
+ */
+
+/* Note: WELL-FORMED poly_t objects have a valid bitmap pointer pointing
+ * to a malloc()-ed array of at least as many bits as stated in its
+ * length field.  Any poly_t with a length of 0 is also a WELL-FORMED
+ * poly_t (whatever value the bitmap pointer has.)
+ * All poly_t objects passed to and from functions must be WELL-FORMED
+ * unless otherwise stated.
+ *
+ * CLEAN (or CANONICAL) poly_t objects are WELL-FORMED objects in which
+ * all spare bits in the bitmap word containing the last bit are zero.
+ * (Any excess allocated words will not be accessed.)
+ *
+ * SEMI-NORMALISED poly_t objects are CLEAN objects in which the last
+ * bit, at position (length - 1), is one.
+ *
+ * NORMALISED poly_t objects are SEMI-NORMALISED objects in which the
+ * first bit is one.
+ *
+ * pfree() should be called on every poly_t object (including
+ * those returned by functions) after its last use.
+ * As always, free() should be called on every malloc()-ed string after
+ * its last use.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "reveng.h"
+
+static bmp_t getwrd(const poly_t poly, unsigned long iter);
+static bmp_t rev(bmp_t accu, int bits);
+static void prhex(char **spp, bmp_t bits, int flags, int bperhx);
+
+static const poly_t pzero = PZERO;
+
+/* word number (0..m-1) of var'th bit (0..n-1) */
+#if BMP_POF2 >= 5
+#  define IDX(var) ((var) >> BMP_POF2)
+#else
+#  define IDX(var) ((var) / BMP_BIT)
+#endif
+
+/* size of polynomial with var bits */
+#if BMP_POF2 >= 5
+#  define SIZE(var) ((BMP_BIT - 1UL + (var)) >> BMP_POF2)
+#else
+#  define SIZE(var) ((BMP_BIT - 1UL + (var)) / BMP_BIT)
+#endif
+
+/* polynomial length rounded up to BMP_BIT */
+#ifdef BMP_POF2
+#  define RNDUP(var) (~(BMP_BIT - 1UL) & (BMP_BIT - 1UL + (var)))
+#else
+#  define RNDUP(var) ((BMP_BIT - (var) % BMP_BIT) % BMP_BIT + (var))
+#endif
+
+/* bit offset (0..BMP_BIT-1, 0 = LSB) of var'th bit (0..n-1) */
+#ifdef BMP_POF2
+#  define OFS(var) ((int) ((BMP_BIT - 1UL) & ~(var)))
+#else
+#  define OFS(var) ((int) (BMP_BIT - 1UL - (var) % BMP_BIT))
+#endif
+
+/* bit offset (0..BMP_BIT-1, 0 = MSB) of var'th bit (0..n-1) */
+#ifdef BMP_POF2
+#  define LOFS(var) ((int) ((BMP_BIT - 1UL) & (var)))
+#else
+#  define LOFS(var) ((int) ((var) % BMP_BIT))
+#endif
+
+poly_t
+filtop(FILE *input, unsigned long length, int flags, int bperhx) {
+       /* reads binary data from input into a poly_t until EOF or until
+        * length bits are read.  Characters are read until
+        * ceil(bperhx / CHAR_BIT) bits are collected; if P_LTLBYT is
+        * set in flags then the first character contains the LSB,
+        * otherwise the last one does.  The least significant bperhx
+        * bits are taken, reflected (if P_REFIN) and appended to the
+        * result, then more characters are read.  The maximum number of
+        * characters read is
+        *   floor(length / bperhx) * ceil(bperhx / * CHAR_BIT).
+        * The returned poly_t is CLEAN.
+        */
+
+       bmp_t accu = BMP_C(0);
+       bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1);
+       unsigned long iter = 0UL, idx;
+       int cmask = ~(~0 << CHAR_BIT), c;
+       int count = 0, ofs;
+       poly_t poly = PZERO;
+       if(bperhx == 0) return(poly);
+
+       length -= length % bperhx;
+       palloc(&poly, length); /* >= 0 */
+
+       while(iter < length && (c = fgetc(input)) != EOF) {
+               if(flags & P_LTLBYT)
+                       accu |= (bmp_t) (c & cmask) << count;
+               else
+                       accu = (accu << CHAR_BIT) | (bmp_t) (c & cmask);
+               count += CHAR_BIT;
+               if(count >= bperhx) {
+                       /* the low bperhx bits of accu contain bits of the poly.*/
+                       iter += bperhx;
+                       count = 0;
+                       if(flags & P_REFIN)
+                               accu = rev(accu, bperhx);
+                       accu &= mask;
+
+                       /* iter >= bperhx > 0 */
+                       idx = IDX(iter - 1UL);
+                       ofs = OFS(iter - 1UL);
+                       poly.bitmap[idx] |= accu << ofs;
+                       if(ofs + bperhx > BMP_BIT) {
+                               poly.bitmap[idx-1] |= accu >> (BMP_BIT - ofs);
+                       }
+                       accu = BMP_C(0); /* only needed for P_LTLBYT */
+               }
+       }
+       praloc(&poly, iter);
+       return(poly);
+}
+
+poly_t
+strtop(const char *string, int flags, int bperhx) {
+       /* Converts a hex or character string to a poly_t.
+        * Each character is converted to a hex nibble yielding 4 bits
+        * unless P_DIRECT, when each character yields CHAR_BIT bits.
+        * Nibbles and characters are accumulated left-to-right
+        * unless P_DIRECT && P_LTLBYT, when they are accumulated
+        * right-to-left without reflection.
+        * As soon as at least bperhx bits are accumulated, the
+        * rightmost bperhx bits are reflected (if P_REFIN)
+        * and appended to the poly.  When !P_DIRECT:
+        * bperhx=8 reads hex nibbles in pairs
+        * bperhx=7 reads hex nibbles in pairs and discards
+        *   b3 of first nibble
+        * bperhx=4 reads hex nibbles singly
+        * bperhx=3 reads octal
+        * bperhx=1 reads longhand binary
+        * in theory if !P_REFIN, bperhx can be any multiple of 4
+        * with equal effect
+        * The returned poly_t is CLEAN.
+        */
+
+       /* make two passes, one to determine the poly size
+        * one to populate the bitmap
+        */
+       unsigned long length = 1UL, idx;
+       bmp_t accu;
+       bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1);
+       int pass, count, ofs;
+       int cmask = ~(~0 << CHAR_BIT), c;
+       const char *s;
+
+       poly_t poly = PZERO;
+       if(bperhx > BMP_BIT || bperhx <= 0 || string == NULL || *string == '\0')
+               return(poly);
+
+       for(pass=0; pass<2 && length > 0UL; ++pass) {
+               s = string;
+               length = 0UL;
+               count = 0;
+               accu = BMP_C(0);
+               while((c = *s++)) {
+                       if(flags & P_DIRECT) {
+                               if(flags & P_LTLBYT)
+                                       accu |= (bmp_t) (c & cmask) << count;
+                               else
+                                       accu = (accu << CHAR_BIT) | (bmp_t) (c & cmask);
+                               count += CHAR_BIT;
+                       } else {
+                               if(c == ' ' || c == '\t' || c == '\r' || c == '\n') continue;
+                               accu <<= 4;
+                               count += 4;
+                               switch(c) {
+                                       case '0':
+                                       case '1':
+                                       case '2':
+                                       case '3':
+                                       case '4':
+                                       case '5':
+                                       case '6':
+                                       case '7':
+                                       case '8':
+                                       case '9':
+                                               accu |= (bmp_t) c - '0';
+                                               break;
+                                       case 'A':
+                                       case 'a':
+                                               accu |= BMP_C(0xa);
+                                               break;
+                                       case 'B':
+                                       case 'b':
+                                               accu |= BMP_C(0xb);
+                                               break;
+                                       case 'C':
+                                       case 'c':
+                                               accu |= BMP_C(0xc);
+                                               break;
+                                       case 'D':
+                                       case 'd':
+                                               accu |= BMP_C(0xd);
+                                               break;
+                                       case 'E':
+                                       case 'e':
+                                               accu |= BMP_C(0xe);
+                                               break;
+                                       case 'F':
+                                       case 'f':
+                                               accu |= BMP_C(0xf);
+                                               break;
+                                       default:
+                                               uerror("invalid character in hexadecimal argument");
+                               }
+                       }
+
+                       if(count >= bperhx) {
+                               /* the low bperhx bits of accu contain bits of the poly.
+                                * in pass 0, increment length by bperhx.
+                                * in pass 1, put the low bits of accu into the bitmap. */
+                               length += bperhx;
+                               count = 0;
+                               if(pass == 1) {
+                                       if(flags & P_REFIN)
+                                               accu = rev(accu, bperhx);
+                                       accu &= mask;
+
+                                       /* length >= bperhx > 0 */
+                                       idx = IDX(length - 1);
+                                       ofs = OFS(length - 1);
+                                       poly.bitmap[idx] |= accu << ofs;
+                                       if(ofs + bperhx > BMP_BIT)
+                                               poly.bitmap[idx-1] |= accu >> (BMP_BIT - ofs);
+                                       accu = BMP_C(0); /* only needed for P_LTLBYT */
+                               }
+                       }
+               }
+               if(pass == 0) palloc(&poly, length);
+       }
+       return(poly);
+}
+
+char *
+ptostr(const poly_t poly, int flags, int bperhx) {
+       /* Returns a malloc()-ed string containing a hexadecimal
+        * representation of poly. See phxsubs().
+        */
+       return(pxsubs(poly, flags, bperhx, 0UL, poly.length));
+}
+
+char *
+pxsubs(const poly_t poly, int flags, int bperhx, unsigned long start, unsigned long end) {
+       /* Returns a malloc()-ed string containing a hexadecimal
+        * representation of a portion of poly, from bit offset start to
+        * (end - 1) inclusive.  The output is grouped into words of
+        * bperhx bits each.  If P_RTJUST then the first word is padded
+        * with zeroes at the MSB end to make a whole number of words,
+        * otherwise the last word is padded at the LSB end.  After
+        * justification the bperhx bits of each word are reversed (if
+        * P_REFOUT) and printed as a hex sequence, with words
+        * optionally separated by spaces (P_SPACE).
+        * If end exceeds the length of poly then zero bits are appended
+        * to make up the difference, in which case poly must be CLEAN.
+        */
+       char *string, *sptr;
+       unsigned long size, iter;
+       bmp_t accu;
+       bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1);
+       int cperhx, part;
+
+       if(bperhx <= 0 || bperhx > BMP_BIT) return(NULL);
+
+       if(start > poly.length) start = poly.length;
+       if(end > poly.length) end = poly.length;
+       if(end < start) end = start;
+
+       cperhx = (bperhx + 3) >> 2;
+       if(flags & P_SPACE) ++cperhx;
+
+       size = (end - start + bperhx - 1UL) / bperhx;
+       size *= cperhx;
+       if(!size || ~flags & P_SPACE) ++size; /* for trailing null */
+
+       if(!(sptr = string = (char *) malloc(size)))
+               uerror("cannot allocate memory for string");
+
+       size = end - start;
+       part = (int) size % bperhx;
+       if(part && flags & P_RTJUST) {
+               iter = start + part;
+               accu = getwrd(poly, iter - 1UL) & ((BMP_C(1) << part) - BMP_C(1));
+               if(flags & P_REFOUT)
+                       /* best to reverse over bperhx rather than part, I think
+                        * e.g. converting a 7-bit poly to 8-bit little-endian hex
+                        */
+                       accu = rev(accu, bperhx);
+               prhex(&sptr, accu, flags, bperhx);
+               if(flags & P_SPACE && size > iter) *sptr++ = ' ';
+       } else {
+               iter = start;
+       }
+
+       while((iter+=bperhx) <= end) {
+               accu = getwrd(poly, iter - 1UL) & mask;
+               if(flags & P_REFOUT)
+                       accu = rev(accu, bperhx);
+               prhex(&sptr, accu, flags, bperhx);
+               if(flags & P_SPACE && size > iter) *sptr++ = ' ';
+       }
+
+       if(part && ~flags & P_RTJUST) {
+               accu = getwrd(poly, end - 1UL);
+               if(flags & P_REFOUT)
+                       accu = rev(accu, part);
+               else
+                       accu = accu << (bperhx - part) & mask;
+               prhex(&sptr, accu, flags, bperhx);
+       }
+       *sptr = '\0';
+       return(string);
+}
+
+poly_t
+pclone(const poly_t poly) {
+       /* Returns a freestanding copy of poly.  Does not clean poly or
+        * the result.
+        */
+       poly_t clone = PZERO;
+
+       pcpy(&clone, poly);
+       return(clone);
+}
+
+void
+pcpy(poly_t *dest, const poly_t src) {
+       /* Assigns (copies) src into dest.  Does not clean src or dest.
+        */
+       unsigned long iter, idx;
+
+       praloc(dest, src.length);
+       for(iter=0UL, idx=0UL; iter < src.length; iter += BMP_BIT, ++idx)
+               dest->bitmap[idx] = src.bitmap[idx];
+}
+
+void
+pcanon(poly_t *poly) {
+       /* Converts poly into a CLEAN object by freeing unused bitmap words
+        * and clearing any bits in the last word beyond the last bit.
+        * The length field has absolute priority over the contents of the bitmap.
+        * Canonicalisation differs from normalisation in that leading and trailing
+        * zero terms are significant and preserved.
+        * poly may or may not be WELL-FORMED.
+        */
+       praloc(poly, poly->length);
+}
+
+void
+pnorm(poly_t *poly) {
+       /* Converts poly into a NORMALISED object by removing leading
+        * and trailing zeroes, so that the polynomial starts and ends
+        * with significant terms.
+        * poly may or may not be WELL-FORMED.
+        */
+       unsigned long first;
+
+       /* call pcanon() here so pfirst() and plast() return the correct
+        * results
+        */
+       pcanon(poly);
+       first = pfirst(*poly);
+       if(first)
+               pshift(poly, *poly, 0UL, first, plast(*poly), 0UL);
+       else
+               praloc(poly, plast(*poly));
+}
+
+void
+psnorm(poly_t *poly) {
+       /* Converts poly into a SEMI-NORMALISED object by removing
+        * trailing zeroes, so that the polynomial ends with a
+        * significant term.
+        * poly may or may not be WELL-FORMED.
+        */
+
+       /* call pcanon() here so plast() returns the correct result */
+       pcanon(poly);
+       praloc(poly, plast(*poly));
+}
+
+void
+pchop(poly_t *poly) {
+       /* Normalise poly, then chop off the highest significant term
+        * (produces a SEMI-NORMALISED object).  poly becomes a suitable
+        * divisor for pcrc().
+        * poly may or may not be WELL-FORMED.
+        */
+
+        /* call pcanon() here so pfirst() and plast() return correct
+         * results
+         */
+       pcanon(poly);
+       pshift(poly, *poly, 0UL, pfirst(*poly) + 1UL, plast(*poly), 0UL);
+}
+
+void
+pkchop(poly_t *poly) {
+       /* Convert poly from Koopman notation to chopped form (produces
+        * a SEMI-NORMALISED object).  poly becomes a suitable divisor
+        * for pcrc().
+        * poly may or may not be WELL-FORMED.
+        */
+       unsigned long first;
+
+       /* call pcanon() here so pfirst() returns the correct result */
+       pcanon(poly);
+       first = pfirst(*poly);
+       if(first >= poly->length) {
+               pfree(poly);
+               return;
+       }
+       pshift(poly, *poly, 0UL, first + 1UL, poly->length, 1UL);
+       piter(poly);
+}
+
+unsigned long
+plen(const poly_t poly) {
+       /* Return length of polynomial.
+        * poly may or may not be WELL-FORMED.
+        */
+       return(poly.length);
+}
+
+int
+pcmp(const poly_t *a, const poly_t *b) {
+       /* Compares poly_t objects for identical sizes and contents.
+        * a and b must be CLEAN.
+        * Defines a total order relation for sorting, etc. although
+        * mathematically, polynomials of equal degree are no greater or
+        * less than one another.
+        */
+       unsigned long iter;
+       bmp_t *aptr, *bptr;
+
+       if(!a || !b) return(!b - !a);
+       if(a->length < b->length) return(-1);
+       if(a->length > b->length) return(1);
+       aptr = a->bitmap;
+       bptr = b->bitmap;
+       for(iter=0UL; iter < a->length; iter += BMP_BIT) {
+               if(*aptr < *bptr)
+                       return(-1);
+               if(*aptr++ > *bptr++)
+                       return(1);
+       }
+       return(0);
+}
+
+int
+psncmp(const poly_t *a, const poly_t *b) {
+       /* Compares polys for identical effect, i.e. as though the
+        * shorter poly were padded with zeroes to the length of the
+        * longer.
+        * a and b must still be CLEAN, therefore psncmp() is *not*
+        * identical to pcmp() on semi-normalised polys as psnorm()
+        * clears the slack space.
+        */
+       unsigned long length, iter, idx;
+       bmp_t aword, bword;
+       if(!a || !b) return(!b - !a);
+       length = (a->length > b->length) ? a->length : b->length;
+       for(iter = 0UL, idx = 0UL; iter < length; iter += BMP_BIT, ++idx) {
+               aword = (iter < a->length) ? a->bitmap[idx] : BMP_C(0);
+               bword = (iter < b->length) ? b->bitmap[idx] : BMP_C(0);
+               if(aword < bword)
+                       return(-1);
+               if(aword > bword)
+                       return(1);
+       }
+       return(0);
+}
+
+
+int
+ptst(const poly_t poly) {
+       /* Tests whether a polynomial equals zero.  Returns 0 if equal,
+        * a nonzero value otherwise.
+        * poly must be CLEAN.
+        */
+       unsigned long iter;
+       bmp_t *bptr;
+       if(!poly.bitmap) return(0);
+       for(iter = 0UL, bptr = poly.bitmap; iter < poly.length; iter += BMP_BIT)
+               if(*bptr++) return(1);
+       return(0);
+}
+
+unsigned long
+pfirst(const poly_t poly) {
+       /* Returns the index of the first nonzero term in poly.  If none
+        * is found, returns the length of poly.
+        * poly must be CLEAN.
+        */
+       unsigned long idx = 0UL, size = SIZE(poly.length);
+       bmp_t accu = BMP_C(0); /* initialiser for Acorn C */
+       unsigned int probe = BMP_SUB, ofs = 0;
+
+       while(idx < size && !(accu = poly.bitmap[idx])) ++idx;
+       if(idx >= size) return(poly.length);
+       while(probe) {
+#ifndef BMP_POF2
+               while((ofs | probe) >= (unsigned int) BMP_BIT) probe >>= 1;
+#endif
+               if(accu >> (ofs | probe)) ofs |= probe;
+               probe >>= 1;
+       }
+
+       return(BMP_BIT - 1UL - ofs + idx * BMP_BIT);
+}
+
+unsigned long
+plast(const poly_t poly) {
+       /* Returns 1 plus the index of the last nonzero term in poly.
+        * If none is found, returns zero.
+        * poly must be CLEAN.
+        */
+       unsigned long idx, size = SIZE(poly.length);
+       bmp_t accu;
+       unsigned int probe = BMP_SUB, ofs = 0;
+
+       if(!poly.length) return(0UL);
+       idx = size - 1UL;
+       while(idx && !(accu = poly.bitmap[idx])) --idx;
+       if(!idx && !(accu = poly.bitmap[idx])) return(0UL);
+       /* now accu == poly.bitmap[idx] and contains last significant term */
+       while(probe) {
+#ifndef BMP_POF2
+               while((ofs | probe) >= (unsigned int) BMP_BIT) probe >>= 1;
+#endif
+               if(accu << (ofs | probe)) ofs |= probe;
+               probe >>= 1;
+       }
+
+       return(idx * BMP_BIT + ofs + 1UL);
+}
+
+poly_t
+psubs(const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail) {
+       poly_t dest = PZERO;
+       pshift(&dest, src, head, start, end, tail);
+       return(dest);
+}
+
+void
+pright(poly_t *poly, unsigned long length) {
+       /* Trims or extends poly to length at the left edge, prepending
+        * zeroes if necessary.  Analogous to praloc() except the
+        * rightmost terms of poly are preserved.
+        * On entry, poly may or may not be WELL-FORMED.
+        * On exit, poly is CLEAN.
+        */
+
+       if(length > poly->length)
+               pshift(poly, *poly, length - poly->length, 0UL, poly->length, 0UL);
+       else if(length < poly->length)
+               pshift(poly, *poly, 0UL, poly->length - length, poly->length, 0UL);
+       else
+               praloc(poly, poly->length);
+}
+
+void
+pshift(poly_t *dest, const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail) {
+       /* copies bits start to end-1 of src to dest, plus the number of leading and trailing zeroes given by head and tail.
+        * end may exceed the length of src in which case more zeroes are appended.
+        * dest may point to src, in which case the poly is edited in place.
+        * On exit, dest is CLEAN.
+        */
+
+       unsigned long length, fulllength, size, fullsize, iter, idx, datidx;
+       /* condition inputs; end, head and tail may be any value */
+       if(end < start) end = start;
+
+       length = end - start + head;
+       fulllength = length + tail;
+       if(fulllength > src.length)
+               praloc(dest, fulllength);
+       else
+               praloc(dest, src.length);
+
+       /* number of words in new poly */
+       size = SIZE(length);
+       fullsize = SIZE(fulllength);
+       /* array index of first word ending up with source material */
+       datidx = IDX(head);
+
+       if(head > start && end > start) {
+               /* shifting right, size > 0 */
+               /* index of the source bit ending up in the LSB of the last word
+                * size * BMP_BIT >= length > head > 0 */
+               iter = size * BMP_BIT - head - 1UL;
+               for(idx = size - 1UL; idx > datidx; iter -= BMP_BIT, --idx)
+                       dest->bitmap[idx] = getwrd(src, iter);
+               dest->bitmap[idx] = getwrd(src, iter);
+               /* iter == size * BMP_BIT - head - 1 - BMP_BIT * (size - 1 - datidx)
+                *      == BMP_BIT * (size - size + 1 + datidx) - head - 1
+                *      == BMP_BIT * (1 + head / BMP_BIT) - head - 1
+                *      == BMP_BIT + head - head % BMP_BIT - head - 1
+                *      == BMP_BIT - head % BMP_BIT - 1
+                *      >= 0
+                */
+       } else if(head <= start) {
+               /* shifting left or copying */
+               /* index of the source bit ending up in the LSB of bitmap[idx] */
+               iter = start - head + BMP_BIT - 1UL;
+               for(idx = datidx; idx < size; iter += BMP_BIT, ++idx)
+                       dest->bitmap[idx] = getwrd(src, iter);
+       }
+
+       /* clear head */
+       for(idx = 0UL; idx < datidx; ++idx)
+               dest->bitmap[idx] = BMP_C(0);
+       if(size)
+               dest->bitmap[datidx] &= ~BMP_C(0) >> LOFS(head);
+
+       /* clear tail */
+       if(LOFS(length))
+               dest->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(length));
+       for(idx = size; idx < fullsize; ++idx)
+               dest->bitmap[idx] = BMP_C(0);
+
+       /* call praloc to shrink poly if required */
+       if(dest->length > fulllength)
+               praloc(dest, fulllength);
+}
+
+void
+ppaste(poly_t *dest, const poly_t src, unsigned long skip, unsigned long seek, unsigned long end, unsigned long fulllength) {
+       /* pastes terms of src, starting from skip, to positions seek to end-1 of dest
+        * then sets length of dest to fulllength (>= end)
+        * to paste n terms of src, give end = seek + n
+        * to truncate dest at end of paste, set fulllength = end
+        * to avoid truncating, set fulllength = plen(*dest)
+        * dest may point to src, in which case the poly is edited in place.
+        * src must be CLEAN in the case that the end is overrun.
+        * On exit, dest is CLEAN.
+        */
+       bmp_t mask;
+       unsigned long seekidx, endidx, iter;
+       int seekofs;
+       if(end < seek) end = seek;
+       if(fulllength < end) fulllength = end;
+
+       /* expand dest if necessary. don't shrink as dest may be src */
+       if(fulllength > dest->length)
+               praloc(dest, fulllength);
+       seekidx = IDX(seek);
+       endidx = IDX(end);
+       seekofs = OFS(seek);
+       /* index of the source bit ending up in the LSB of the first modified word */
+       iter = skip + seekofs;
+       if(seekidx == endidx) {
+               /* paste affects one word (traps end = seek case) */
+               mask = ((BMP_C(1) << seekofs) - (BMP_C(1) << OFS(end))) << 1;
+               dest->bitmap[seekidx] = (dest->bitmap[seekidx] & ~mask) | (getwrd(src, iter) & mask);
+       } else if(seek > skip) {
+               /* shifting right */
+               /* index of the source bit ending up in the LSB of the last modified word */
+               iter += (endidx - seekidx) * BMP_BIT;
+               mask = ~BMP_C(0) >> LOFS(end);
+               dest->bitmap[endidx] = (dest->bitmap[endidx] & mask) | (getwrd(src, iter) & ~mask);
+               for(iter -= BMP_BIT, --endidx; endidx > seekidx; iter -= BMP_BIT, --endidx)
+                       dest->bitmap[endidx] = getwrd(src, iter);
+               mask = ~BMP_C(0) >> LOFS(seek);
+               dest->bitmap[endidx] = (dest->bitmap[endidx] & ~mask) | (getwrd(src, iter) & mask);
+               /* iter == skip + seekofs + (endidx - seekidx) * BMP_BIT - BMP_BIT * (endidx - seekidx)
+                *      == skip + seekofs + BMP_BIT * (endidx - seekidx - endidx + seekidx)
+                *      == skip + seekofs
+                *      >= 0
+                */
+       } else {
+               /* shifting left or copying */
+               mask = ~BMP_C(0) >> LOFS(seek);
+               dest->bitmap[seekidx] = (dest->bitmap[seekidx] & ~mask) | (getwrd(src, iter) & mask);
+               for(iter += BMP_BIT, ++seekidx; seekidx < endidx; iter += BMP_BIT, ++seekidx)
+                       dest->bitmap[seekidx] = getwrd(src, iter);
+               mask = ~BMP_C(0) >> LOFS(end);
+               dest->bitmap[seekidx] = (dest->bitmap[seekidx] & mask) | (getwrd(src, iter) & ~mask);
+       }
+       /* shrink poly if required */
+       if(dest->length > fulllength)
+               praloc(dest, fulllength);
+}
+
+void
+pdiff(poly_t *dest, const poly_t src, unsigned long ofs) {
+       /* Subtract src from dest (modulo 2) at offset ofs.
+        * In modulo 2 arithmetic, subtraction is equivalent to addition
+        * We include an alias for those who wish to retain the distinction
+        * src and dest must be CLEAN.
+        */
+       psum(dest, src, ofs);
+}
+
+void
+psum(poly_t *dest, const poly_t src, unsigned long ofs) {
+       /* Adds src to dest (modulo 2) at offset ofs.
+        * When ofs == dest->length, catenates src on to dest.
+        * src and dest must be CLEAN.
+        */
+       unsigned long fulllength, idx, iter, end;
+
+       fulllength = ofs + src.length;
+       if(fulllength > dest->length)
+               praloc(dest, fulllength);
+       /* array index of first word in dest to be modified */
+       idx = IDX(ofs);
+       /* index of bit in src to be added to LSB of dest->bitmap[idx] */
+       iter = OFS(ofs);
+       /* stop value for iter */
+       end = BMP_BIT - 1UL + src.length;
+       for(; iter < end; iter += BMP_BIT, ++idx)
+               dest->bitmap[idx] ^= getwrd(src, iter);
+}
+
+void
+prev(poly_t *poly) {
+       /* Reverse or reciprocate a polynomial.
+        * On exit, poly is CLEAN.
+        */
+       unsigned long leftidx = 0UL, rightidx = SIZE(poly->length);
+       unsigned long ofs = LOFS(BMP_BIT - LOFS(poly->length));
+       unsigned long fulllength = poly->length + ofs;
+       bmp_t accu;
+
+       if(ofs)
+               /* removable optimisation */
+               if(poly->length < (unsigned long) BMP_BIT) {
+                       *poly->bitmap = rev(*poly->bitmap >> ofs, (int) poly->length) << ofs;
+                       return;
+               }
+
+               /* claim remaining bits of last word (as we use public function pshift()) */
+               poly->length = fulllength;
+
+       /* reverse and swap words in the array, leaving it right-justified */
+       while(leftidx < rightidx) {
+               /* rightidx > 0 */
+               accu = rev(poly->bitmap[--rightidx], BMP_BIT);
+               poly->bitmap[rightidx] = rev(poly->bitmap[leftidx], BMP_BIT);
+               poly->bitmap[leftidx++] = accu;
+       }
+       /* shift polynomial to left edge if required */
+       if(ofs)
+               pshift(poly, *poly, 0UL, ofs, fulllength, 0UL);
+}
+
+void
+prevch(poly_t *poly, int bperhx) {
+       /* Reverse each group of bperhx bits in a polynomial.
+        * Does not clean poly.
+        */
+       unsigned long iter = 0, idx, ofs;
+       bmp_t mask, accu;
+
+       if(bperhx < 2 || bperhx > BMP_BIT)
+               return;
+       if(poly->length % bperhx)
+               praloc(poly, bperhx - (poly->length % bperhx) + poly->length);
+       mask = ~BMP_C(0) >> (BMP_BIT - bperhx);
+       for(iter = (unsigned long) (bperhx - 1); iter < poly->length; iter += bperhx) {
+               accu = getwrd(*poly, iter) & mask;
+               accu ^= rev(accu, bperhx);
+               idx = IDX(iter);
+               ofs = OFS(iter);
+               poly->bitmap[idx] ^= accu << ofs;
+               if(ofs + bperhx > (unsigned int) BMP_BIT)
+                       /* (BMP_BIT - 1UL - (iter) % BMP_BIT) + bperhx > BMP_BIT
+                        * (-1UL - (iter) % BMP_BIT) + bperhx > 0
+                        * (- (iter % BMP_BIT)) + bperhx > 1
+                        * - (iter % BMP_BIT) > 1 - bperhx
+                        * iter % BMP_BIT < bperhx - 1, iter >= bperhx - 1
+                        * iter >= BMP_BIT
+                        * idx >= 1
+                        */
+                       poly->bitmap[idx-1] ^= accu >> (BMP_BIT - ofs);
+       }
+}
+
+void
+prcp(poly_t *poly) {
+       /* Reciprocate a chopped polynomial.  Use prev() on whole
+        * polynomials.
+        * On exit, poly is SEMI-NORMALISED.
+        */
+       unsigned long first;
+
+       praloc(poly, RNDUP(poly->length));
+       prev(poly);
+       first = pfirst(*poly);
+       if(first >= poly->length) {
+               pfree(poly);
+               return;
+       }
+       pshift(poly, *poly, 0UL, first + 1UL, poly->length, 1UL);
+       piter(poly);
+}
+
+void
+pinv(poly_t *poly) {
+       /* Invert a polynomial, i.e. add 1 (modulo 2) to the coefficient of each term
+        * on exit, poly is CLEAN.
+        */
+       unsigned long idx, size = SIZE(poly->length);
+
+       for(idx = 0UL; idx<size; ++idx)
+               poly->bitmap[idx] = ~poly->bitmap[idx];
+       if(LOFS(poly->length))
+               poly->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(poly->length));
+}
+
+poly_t
+pmod(const poly_t dividend, const poly_t divisor) {
+       /* Divide dividend by normalised divisor and return the remainder
+        * This function generates a temporary 'chopped' divisor for pcrc()
+        * If calling repeatedly with a constant divisor, produce a chopped copy
+        * with pchop() and call pcrc() directly for higher efficiency.
+        * dividend and divisor must be CLEAN.
+        */
+
+       /* perhaps generate an error if divisor is zero */
+       poly_t subdivisor = psubs(divisor, 0UL, pfirst(divisor) + 1UL, plast(divisor), 0UL);
+       poly_t result = pcrc(dividend, subdivisor, pzero, pzero, 0);
+       pfree(&subdivisor);
+       return(result);
+}
+
+poly_t
+pcrc(const poly_t message, const poly_t divisor, const poly_t init, const poly_t xorout, int flags) {
+       /* Divide message by divisor and return the remainder.
+        * init is added to divisor, highest terms aligned, before
+        * division.
+        * xorout is added to the remainder, highest terms aligned.
+        * If P_MULXN is set in flags, message is multiplied by x^n
+        * (i.e. trailing zeroes equal to the CRC width are appended)
+        * before adding init and division.  Set P_MULXN for most CRC
+        * calculations.
+        * All inputs must be CLEAN.
+        * If all inputs are CLEAN, the returned poly_t will be CLEAN.
+        */
+       unsigned long max = 0UL, iter, ofs, resiter;
+       bmp_t probe, rem, dvsr, *rptr, *sptr;
+       const bmp_t *bptr, *eptr;
+       poly_t result = PZERO;
+
+       if(flags & P_MULXN)
+               max = message.length;
+       else if(message.length > divisor.length)
+               max = message.length - divisor.length;
+       bptr=message.bitmap;
+       eptr=message.bitmap+SIZE(message.length);
+       probe=~(~BMP_C(0) >> 1);
+       if(divisor.length <= (unsigned long) BMP_BIT
+               && init.length <= (unsigned long) BMP_BIT) {
+               rem = init.length ? *init.bitmap : BMP_C(0);
+               dvsr = divisor.length ? *divisor.bitmap : BMP_C(0);
+               for(iter = 0UL, ofs = 0UL; iter < max; ++iter, --ofs) {
+                       if(!ofs) {
+                               ofs = BMP_BIT;
+                               rem ^= *bptr++;
+                       }
+                       if(rem & probe)
+                               rem = (rem << 1) ^ dvsr;
+                       else
+                               rem <<= 1;
+               }
+               if(bptr < eptr)
+                       /* max < message.length */
+                       rem ^= *bptr >> OFS(BMP_BIT - 1UL + max);
+               if(init.length > max && init.length - max > divisor.length) {
+                       palloc(&result, init.length - max);
+                       *result.bitmap = rem;
+               } else if(divisor.length) {
+                       palloc(&result, divisor.length);
+                       *result.bitmap = rem;
+               }
+       } else {
+               /* allocate maximum size plus one word for shifted divisors and one word containing zero.
+                * This also ensures that result[1] exists
+                */
+               palloc(&result, (init.length > divisor.length ? init.length : divisor.length) + (unsigned long) (BMP_BIT << 1));
+               /*if there is content in init, there will be an extra word in result to clear it */
+               psum(&result, init, 0UL);
+               if(max)
+                       *result.bitmap ^= *bptr++;
+               for(iter = 0UL, ofs = 0UL; iter < max; ++iter, probe >>= 1) {
+                       if(!probe) {
+                               probe = ~(~BMP_C(0) >> 1);
+                               ofs = 0UL;
+                               sptr = rptr = result.bitmap;
+                               ++sptr;
+                               /* iter < max <= message.length, so bptr is valid
+                                * shift result one word to the left, splicing in a message word
+                                * and clearing the last active word
+                                */
+                               *rptr++ = *sptr++ ^ *bptr++;
+                               for(resiter = (unsigned long) (BMP_BIT << 1); resiter < result.length; resiter += BMP_BIT)
+                                       *rptr++ = *sptr++;
+                       }
+                       ++ofs;
+                       if(*result.bitmap & probe)
+                               psum(&result, divisor, ofs);
+               }
+               rptr = result.bitmap;
+               ++rptr;
+               while(bptr < eptr)
+                       *rptr++ ^= *bptr++;
+               /* 0 <= ofs <= BMP_BIT, location of the first bit of the result */
+               pshift(&result, result, 0UL, ofs, (init.length > max + divisor.length ? init.length - max - divisor.length : 0UL) + divisor.length + ofs, 0UL);
+       }
+       psum(&result, xorout, 0UL);
+       return(result);
+}
+
+int
+piter(poly_t *poly) {
+       /* Replace poly with the 'next' polynomial of equal length.
+        * Returns zero if the next polynomial is all zeroes, a nonzero
+        * value otherwise.
+        * Does not clean poly.
+        */
+       bmp_t *bptr;
+       if(!poly->length) return(0);
+
+       bptr = poly->bitmap + IDX(poly->length - 1UL);
+       *bptr += BMP_C(1) << OFS(poly->length - 1UL);
+       while(bptr != poly->bitmap && !*bptr)
+               ++(*--bptr);
+       return(*bptr != BMP_C(0));
+}
+
+void
+palloc(poly_t *poly, unsigned long length) {
+       /* Replaces poly with a CLEAN object of the specified length,
+        * consisting of all zeroes.
+        * It is safe to call with length = 0, in which case the object
+        * is freed.
+        * poly may or may not be WELL-FORMED.
+        * On exit, poly is CLEAN.
+        */
+       unsigned long size = SIZE(length);
+
+       poly->length = 0UL;
+       free(poly->bitmap);
+       poly->bitmap = NULL;
+       if(!length) return;
+       if(!size)
+               size = IDX(length) + 1UL;
+       poly->bitmap = (bmp_t *) calloc(size, sizeof(bmp_t));
+       if(poly->bitmap) {
+               poly->length = length;
+       } else
+               uerror("cannot allocate memory for poly");
+}
+
+void
+pfree(poly_t *poly) {
+       /* Frees poly's bitmap storage and sets poly equal to the empty
+        * polynomial (PZERO).
+        * poly may or may not be WELL-FORMED.
+        * On exit, poly is CLEAN.
+        */
+
+       /* palloc(poly, 0UL); */
+
+       poly->length = 0UL;
+       free(poly->bitmap);
+       poly->bitmap = NULL;
+}
+
+void
+praloc(poly_t *poly, unsigned long length) {
+       /* Trims or extends poly to length at the right edge, appending
+        * zeroes if necessary.
+        * On entry, poly may or may not be WELL-FORMED.
+        * On exit, poly is CLEAN.
+        */
+       unsigned long oldsize, size = SIZE(length);
+       if(!poly) return;
+       if(!length) {
+               poly->length = 0UL;
+               free(poly->bitmap);
+               poly->bitmap = NULL;
+               return;
+       }
+       if(!size)
+               size = IDX(length) + 1UL;
+       if(!poly->bitmap)
+               poly->length = 0UL;
+       oldsize = SIZE(poly->length);
+       if(oldsize != size)
+               /* reallocate if array pointer is null or array resized */
+               poly->bitmap = (bmp_t *) realloc((void *)poly->bitmap, size * sizeof(bmp_t));
+       if(poly->bitmap) {
+               if(poly->length < length) {
+                       /* poly->length >= 0, length > 0, size > 0.
+                        * poly expanded. clear old last word and all new words
+                        */
+                       if(LOFS(poly->length))
+                               poly->bitmap[oldsize - 1UL] &= ~(~BMP_C(0) >> LOFS(poly->length));
+                       while(oldsize < size)
+                               poly->bitmap[oldsize++] = BMP_C(0);
+               } else if(LOFS(length))
+                       /* poly->length >= length > 0.
+                        * poly shrunk. clear new last word
+                        */
+                       poly->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(length));
+               poly->length = length;
+       } else
+               uerror("cannot reallocate memory for poly");
+}
+
+int
+pmpar(const poly_t poly, const poly_t mask) {
+       /* Return even parity of poly masked with mask.
+        * Poly and mask must be CLEAN.
+        */
+       bmp_t res = BMP_C(0);
+       int i = BMP_SUB;
+       const bmp_t *pptr = poly.bitmap, *mptr = mask.bitmap;
+       const bmp_t *const pend = poly.bitmap + SIZE(poly.length);
+       const bmp_t *const mend = mask.bitmap + SIZE(mask.length);
+
+       while(pptr < pend && mptr < mend)
+               res ^= *pptr++ & *mptr++;
+       do
+               res ^= res >> i;
+       while(i >>= 1);
+
+       return((int) (res & BMP_C(1)));
+}
+
+int
+pident(const poly_t a, const poly_t b) {
+       /* Return nonzero if a and b have the same length
+        * and point to the same bitmap.
+        * a and b need not be CLEAN.
+        */
+       return(a.length == b.length && a.bitmap == b.bitmap);
+}
+
+/* Private functions */
+
+static bmp_t
+getwrd(const poly_t poly, unsigned long iter) {
+       /* Fetch unaligned word from poly where LSB of result is
+        * bit iter of the bitmap (counting from zero).  If iter exceeds
+        * the length of poly then zeroes are appended as necessary.
+        * Factored from ptostr().
+        * poly must be CLEAN.
+        */
+       bmp_t accu = BMP_C(0);
+       unsigned long idx, size;
+       int ofs;
+
+       idx = IDX(iter);
+       ofs = OFS(iter);
+       size = SIZE(poly.length);
+
+       if(idx < size)
+               accu |= poly.bitmap[idx] >> ofs;
+       if(idx && idx <= size && ofs > 0)
+               accu |= poly.bitmap[idx - 1UL] << (BMP_BIT - ofs);
+       return(accu);
+}
+
+static bmp_t
+rev(bmp_t accu, int bits) {
+       /* Returns the bitmap word argument with the given number of
+        * least significant bits reversed and the rest cleared.
+        */
+       static const unsigned char revtab[256] = {
+               0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
+               0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
+               0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
+               0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
+               0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
+               0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
+               0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
+               0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
+               0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
+               0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
+               0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
+               0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
+               0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
+               0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
+               0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
+               0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
+               0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
+               0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
+               0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
+               0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
+               0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
+               0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
+               0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
+               0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
+               0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
+               0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
+               0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
+               0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
+               0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
+               0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
+               0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
+               0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
+       };
+       bmp_t result = BMP_C(0);
+       while(bits > 8) {
+               bits -= 8;
+               result = result << 8 | revtab[accu & 0xff];
+               accu >>= 8;
+       }
+       result = result << bits | (bmp_t) (revtab[accu & 0xff] >> (8 - bits));
+       return(result);
+}
+
+static void
+prhex(char **spp, bmp_t bits, int flags, int bperhx) {
+       /* Appends a hexadecimal string representing the bperhx least
+        * significant bits of bits to an external string.
+        * spp points to a character pointer that in turn points to the
+        * end of a hex string being built.  prhex() advances this
+        * second pointer by the number of characters written.
+        * The unused MSBs of bits MUST be cleared.
+        * Set P_UPPER in flags to write A-F in uppercase.
+        */
+       static const char hex[] = "0123456789abcdef0123456789ABCDEF";
+       const int upper = (flags & P_UPPER ? 0x10 : 0);
+       while(bperhx > 0) {
+               bperhx -= ((bperhx + 3) & 3) + 1;
+               *(*spp)++ = hex[(bits >> bperhx & BMP_C(0xf)) | upper];
+       }
+}
diff --git a/client/reveng/reveng.c b/client/reveng/reveng.c
new file mode 100644 (file)
index 0000000..3c6da12
--- /dev/null
@@ -0,0 +1,488 @@
+/* reveng.c
+ * Greg Cook, 9/Apr/2015
+ */
+
+/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Gregory Cook
+ *
+ * This file is part of CRC RevEng.
+ *
+ * CRC RevEng 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.
+ *
+ * CRC RevEng 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 CRC RevEng.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 2013-09-16: calini(), calout() work on shortest argument
+ * 2013-06-11: added sequence number to uprog() calls
+ * 2013-02-08: added polynomial range search
+ * 2013-01-18: refactored model checking to pshres(); renamed chkres()
+ * 2012-05-24: efficiently build Init contribution string
+ * 2012-05-24: removed broken search for crossed-endian algorithms
+ * 2012-05-23: rewrote engini() after Ewing; removed modini()
+ * 2011-01-17: fixed ANSI C warnings
+ * 2011-01-08: fixed calini(), modini() caters for crossed-endian algos
+ * 2011-01-04: renamed functions, added calini(), factored pshres();
+ *            rewrote engini() and implemented quick Init search
+ * 2011-01-01: reveng() initialises terminating entry, addparms()
+ *            initialises all fields
+ * 2010-12-26: renamed CRC RevEng. right results, rejects polys faster
+ * 2010-12-24: completed, first tests (unsuccessful)
+ * 2010-12-21: completed modulate(), partial sketch of reveng()
+ * 2010-12-19: started reveng
+ */
+
+/* reveng() can in theory be modified to search for polynomials shorter
+ * than the full width as well, but this imposes a heavy time burden on
+ * the full width search, which is the primary use case, as well as
+ * complicating the search range function introduced in version 1.1.0.
+ * It is more effective to search for each shorter width directly.
+ */
+
+#include <stdlib.h>
+
+#define FILE void
+#include "reveng.h"
+
+static poly_t *modpol(const poly_t init, int rflags, int args, const poly_t *argpolys);
+static void engini(int *resc, model_t **result, const poly_t divisor, int flags, int args, const poly_t *argpolys);
+static void calout(int *resc, model_t **result, const poly_t divisor, const poly_t init, int flags, int args, const poly_t *argpolys);
+static void calini(int *resc, model_t **result, const poly_t divisor, int flags, const poly_t xorout, int args, const poly_t *argpolys);
+static void chkres(int *resc, model_t **result, const poly_t divisor, const poly_t init, int flags, const poly_t xorout, int args, const poly_t *argpolys);
+
+static const poly_t pzero = PZERO;
+
+model_t *
+reveng(const model_t *guess, const poly_t qpoly, int rflags, int args, const poly_t *argpolys) {
+       /* Complete the parameters of a model by calculation or brute search. */
+       poly_t *pworks, *wptr, rem, gpoly;
+       model_t *result = NULL, *rptr;
+       int resc = 0;
+       unsigned long spin = 0, seq = 0;
+
+       if(~rflags & R_HAVEP) {
+               /* The poly is not known.
+                * Produce a list of differences between the arguments.
+                */
+               pworks = modpol(guess->init, rflags, args, argpolys);
+               if(!pworks || !plen(*pworks)) {
+                       free(pworks);
+                       goto requit;
+               }
+               /* Initialise the guessed poly to the starting value. */
+               gpoly = pclone(guess->spoly);
+               /* Clear the least significant term, to be set in the
+                * loop. qpoly does not need fixing as it is only
+                * compared with odd polys.
+                */
+               if(plen(gpoly))
+                       pshift(&gpoly, gpoly, 0UL, 0UL, plen(gpoly) - 1UL, 1UL);
+
+               while(piter(&gpoly) && (~rflags & R_HAVEQ || pcmp(&gpoly, &qpoly) < 0)) {
+                       /* For each possible poly of this size, try
+                        * dividing all the differences in the list.
+                        */
+                       if(!(spin++ & R_SPMASK)) {
+                               uprog(gpoly, guess->flags, seq++);
+                       }
+                       for(wptr = pworks; plen(*wptr); ++wptr) {
+                               /* straight divide message by poly, don't multiply by x^n */
+                               rem = pcrc(*wptr, gpoly, pzero, pzero, 0);
+                               if(ptst(rem)) {
+                                       pfree(&rem);
+                                       break;
+                               } else
+                                       pfree(&rem);
+                       }
+                       /* If gpoly divides all the differences, it is a
+                        * candidate.  Search for an Init value for this
+                        * poly or if Init is known, log the result.
+                        */
+                       if(!plen(*wptr)) {
+                               /* gpoly is a candidate poly */
+                               if(rflags & R_HAVEI && rflags & R_HAVEX)
+                                       chkres(&resc, &result, gpoly, guess->init, guess->flags, guess->xorout, args, argpolys);
+                               else if(rflags & R_HAVEI)
+                                       calout(&resc, &result, gpoly, guess->init, guess->flags, args, argpolys);
+                               else if(rflags & R_HAVEX)
+                                       calini(&resc, &result, gpoly, guess->flags, guess->xorout, args, argpolys);
+                               else
+                                       engini(&resc, &result, gpoly, guess->flags, args, argpolys);
+                       }
+                       if(!piter(&gpoly))
+                               break;
+               }
+               /* Finished with gpoly and the differences list, free them.
+                */
+               pfree(&gpoly);
+               for(wptr = pworks; plen(*wptr); ++wptr)
+                       pfree(wptr);
+               free(pworks);
+       }
+       else if(rflags & R_HAVEI && rflags & R_HAVEX)
+               /* All parameters are known!  Submit the result if we get here */
+               chkres(&resc, &result, guess->spoly, guess->init, guess->flags, guess->xorout, args, argpolys);
+       else if(rflags & R_HAVEI)
+               /* Poly and Init are known, calculate XorOut */
+               calout(&resc, &result, guess->spoly, guess->init, guess->flags, args, argpolys);
+       else if(rflags & R_HAVEX)
+               /* Poly and XorOut are known, calculate Init */
+               calini(&resc, &result, guess->spoly, guess->flags, guess->xorout, args, argpolys);
+       else
+               /* Poly is known but not Init; search for Init. */
+               engini(&resc, &result, guess->spoly, guess->flags, args, argpolys);
+
+requit:
+       if(!(result = realloc(result, ++resc * sizeof(model_t))))
+               uerror("cannot reallocate result array");
+       rptr = result + resc - 1;
+       rptr->spoly  = pzero;
+       rptr->init   = pzero;
+       rptr->flags  = 0;
+       rptr->xorout = pzero;
+       rptr->check  = pzero;
+       rptr->name   = NULL;
+
+       return(result);
+}
+
+static poly_t *
+modpol(const poly_t init, int rflags, int args, const poly_t *argpolys) {
+       /* Produce, in ascending length order, a list of differences
+        * between the arguments in the list by summing pairs of arguments.
+        * If R_HAVEI is not set in rflags, only pairs of equal length are
+        * summed.
+        * Otherwise, sums of right-aligned pairs are also returned, with
+        * the supplied init poly added to the leftmost terms of each
+        * poly of the pair.
+        */
+       poly_t work, swap, *result, *rptr, *iptr;
+       const poly_t *aptr, *bptr, *eptr = argpolys + args;
+       unsigned long alen, blen;
+
+       if(args < 2) return(NULL);
+
+       if(!(result = malloc(((((args - 1) * args) >> 1) + 1) * sizeof(poly_t))))
+               uerror("cannot allocate memory for codeword table");
+
+       rptr = result;
+
+       for(aptr = argpolys; aptr < eptr; ++aptr) {
+               alen = plen(*aptr);
+               for(bptr = aptr + 1; bptr < eptr; ++bptr) {
+                       blen = plen(*bptr);
+                       if(alen == blen) {
+                               work = pclone(*aptr);
+                               psum(&work, *bptr, 0UL);
+                       } else if(rflags & R_HAVEI && alen < blen) {
+                               work = pclone(*bptr);
+                               psum(&work, *aptr, blen - alen);
+                               psum(&work, init, 0UL);
+                               psum(&work, init, blen - alen);
+                       } else if(rflags & R_HAVEI /* && alen > blen */) {
+                               work = pclone(*aptr);
+                               psum(&work, *bptr, alen - blen);
+                               psum(&work, init, 0UL);
+                               psum(&work, init, alen - blen);
+                       } else
+                               work = pzero;
+
+                       if(plen(work))
+                               pnorm(&work);
+                       if((blen = plen(work))) {
+                               /* insert work into result[] in ascending order of length */
+                               for(iptr = result; iptr < rptr; ++iptr) {
+                                       if(plen(work) < plen(*iptr)) {
+                                               swap = *iptr;
+                                               *iptr = work;
+                                               work = swap;
+                                       }
+                                       else if(plen(*iptr) == blen && !pcmp(&work, iptr)) {
+                                               pfree(&work);
+                                               work = *--rptr;
+                                               break;
+                                       }
+                               }
+                               *rptr++ = work;
+                       }
+               }
+       }
+       *rptr = pzero;
+       return(result);
+}
+
+static void
+engini(int *resc, model_t **result, const poly_t divisor, int flags, int args, const poly_t *argpolys) {
+       /* Search for init values implied by the arguments.
+        * Method from: Ewing, Gregory C. (March 2010).
+        * "Reverse-Engineering a CRC Algorithm". Christchurch:
+        * University of Canterbury.
+        * <http://www.cosc.canterbury.ac.nz/greg.ewing/essays/
+        * CRC-Reverse-Engineering.html>
+        */
+       poly_t apoly = PZERO, bpoly, pone = PZERO, *mat, *jptr;
+       const poly_t *aptr, *bptr, *iptr;
+       unsigned long alen, blen, dlen, ilen, i, j;
+       int cy;
+
+       dlen = plen(divisor);
+
+       /* Allocate the CRC matrix */
+       if(!(mat = (poly_t *) malloc((dlen << 1) * sizeof(poly_t))))
+               uerror("cannot allocate memory for CRC matrix");
+
+       /* Find arguments of the two shortest lengths */
+       alen = blen = plen(*(aptr = bptr = iptr = argpolys));
+       for(++iptr; iptr < argpolys + args; ++iptr) {
+               ilen = plen(*iptr);
+               if(ilen < alen) {
+                       bptr = aptr; blen = alen;
+                       aptr = iptr; alen = ilen;
+               } else if(ilen > alen && (aptr == bptr || ilen < blen)) {
+                       bptr = iptr; blen = ilen;
+               }
+       }
+       if(aptr == bptr) {
+               /* if no arguments are suitable, calculate Init with an
+                * assumed XorOut of 0.  Create a padded XorOut
+                */
+               palloc(&apoly, dlen);
+               calini(resc, result, divisor, flags, apoly, args, argpolys);
+               pfree(&apoly);
+               return;
+       }
+
+       /* Find the potential contribution of the bottom bit of Init */
+       palloc(&pone, 1UL);
+       piter(&pone);
+       if(blen < (dlen << 1)) {
+               palloc(&apoly, dlen); /* >= 1 */
+               psum(&apoly, pone, (dlen << 1) - 1UL - blen); /* >= 0 */
+               psum(&apoly, pone, (dlen << 1) - 1UL - alen); /* >= 1 */
+       } else {
+               palloc(&apoly, blen - dlen + 1UL); /* > dlen */
+               psum(&apoly, pone, 0UL);
+               psum(&apoly, pone, blen - alen); /* >= 1 */
+       }
+       if(plen(apoly) > dlen) {
+               mat[dlen] = pcrc(apoly, divisor, pzero, pzero, 0);
+               pfree(&apoly);
+       } else {
+               mat[dlen] = apoly;
+       }
+
+       /* Find the actual contribution of Init */
+       apoly = pcrc(*aptr, divisor, pzero, pzero, 0);
+       bpoly = pcrc(*bptr, divisor, pzero, apoly, 0);
+
+       /* Populate the matrix */
+       palloc(&apoly, 1UL);
+       for(jptr=mat; jptr<mat+dlen; ++jptr)
+               *jptr = pzero;
+       for(iptr = jptr++; jptr < mat + (dlen << 1); iptr = jptr++)
+               *jptr = pcrc(apoly, divisor, *iptr, pzero, P_MULXN);
+       pfree(&apoly);
+
+       /* Transpose the matrix, augment with the Init contribution
+        * and convert to row echelon form
+        */
+       for(i=0UL; i<dlen; ++i) {
+               apoly = pzero;
+               iptr = mat + (dlen << 1);
+               for(j=0UL; j<dlen; ++j)
+                       ppaste(&apoly, *--iptr, i, j, j + 1UL, dlen + 1UL);
+               if(ptst(apoly))
+                       ppaste(&apoly, bpoly, i, dlen, dlen + 1UL, dlen + 1UL);
+               j = pfirst(apoly);
+               while(j < dlen && !pident(mat[j], pzero)) {
+                       psum(&apoly, mat[j], 0UL); /* pfirst(apoly) > j */
+                       j = pfirst(apoly);
+               }
+               if(j < dlen)
+                       mat[j] = apoly; /* pident(mat[j], pzero) || pfirst(mat[j]) == j */
+               else
+                       pfree(&apoly);
+       }
+       palloc(&bpoly, dlen + 1UL);
+       psum(&bpoly, pone, dlen);
+
+       /* Iterate through all solutions */
+       do {
+               /* Solve the matrix by Gaussian elimination.
+                * The parity of the result, masked by each row, should be even.
+                */
+               cy = 1;
+               apoly = pclone(bpoly);
+               jptr = mat + dlen;
+               for(i=0UL; i<dlen; ++i) {
+                       /* Compute next bit of Init */
+                       if(pmpar(apoly, *--jptr))
+                               psum(&apoly, pone, dlen - 1UL - i);
+                       /* Toggle each zero row with carry, for next iteration */
+                       if(cy) {
+                              if(pident(*jptr, pzero)) {
+                                      /* 0 to 1, no carry */
+                                      *jptr = bpoly;
+                                      cy = 0;
+                              } else if(pident(*jptr, bpoly)) {
+                                      /* 1 to 0, carry forward */
+                                      *jptr = pzero;
+                              }
+                       }
+               }
+
+               /* Trim the augment mask bit */
+               praloc(&apoly, dlen);
+
+               /* Test the Init value and add to results if correct */
+               calout(resc, result, divisor, apoly, flags, args, argpolys);
+               pfree(&apoly);
+       } while(!cy);
+       pfree(&pone);
+       pfree(&bpoly);
+
+       /* Free the matrix. */
+       for(jptr=mat; jptr < mat + (dlen << 1); ++jptr)
+               pfree(jptr);
+       free(mat);
+}
+
+static void
+calout(int *resc, model_t **result, const poly_t divisor, const poly_t init, int flags, int args, const poly_t *argpolys) {
+       /* Calculate Xorout, check it against all the arguments and
+        * add to results if consistent.
+        */
+       poly_t xorout;
+       const poly_t *aptr, *iptr;
+       unsigned long alen, ilen;
+
+       if(args < 1) return;
+
+       /* find argument of the shortest length */
+       alen = plen(*(aptr = iptr = argpolys));
+       for(++iptr; iptr < argpolys + args; ++iptr) {
+               ilen = plen(*iptr);
+               if(ilen < alen) {
+                       aptr = iptr; alen = ilen;
+               }
+       }
+
+       xorout = pcrc(*aptr, divisor, init, pzero, 0);
+       /* On little-endian algorithms, the calculations yield
+        * the reverse of the actual xorout: in the Williams
+        * model, the refout stage intervenes between init and
+        * xorout.
+        */
+       if(flags & P_REFOUT)
+               prev(&xorout);
+
+       /* Submit the model to the results table.
+        * Could skip the shortest argument but we wish to check our
+        * calculation.
+        */
+       chkres(resc, result, divisor, init, flags, xorout, args, argpolys);
+       pfree(&xorout);
+}
+
+static void
+calini(int *resc, model_t **result, const poly_t divisor, int flags, const poly_t xorout, int args, const poly_t *argpolys) {
+       /* Calculate Init, check it against all the arguments and add to
+        * results if consistent.
+        */
+       poly_t rcpdiv, rxor, arg, init;
+       const poly_t *aptr, *iptr;
+       unsigned long alen, ilen;
+
+       if(args < 1) return;
+
+       /* find argument of the shortest length */
+       alen = plen(*(aptr = iptr = argpolys));
+       for(++iptr; iptr < argpolys + args; ++iptr) {
+               ilen = plen(*iptr);
+               if(ilen < alen) {
+                       aptr = iptr; alen = ilen;
+               }
+       }
+
+       rcpdiv = pclone(divisor);
+       prcp(&rcpdiv);
+       /* If the algorithm is reflected, an ordinary CRC requires the
+        * model's XorOut to be reversed, as XorOut follows the RefOut
+        * stage.  To reverse the CRC calculation we need rxor to be the
+        * mirror image of the forward XorOut.
+        */
+       rxor = pclone(xorout);
+       if(~flags & P_REFOUT)
+               prev(&rxor);
+       arg = pclone(*aptr);
+       prev(&arg);
+
+       init = pcrc(arg, rcpdiv, rxor, pzero, 0);
+       pfree(&arg);
+       pfree(&rxor);
+       pfree(&rcpdiv);
+       prev(&init);
+
+       /* Submit the model to the results table.
+        * Could skip the shortest argument but we wish to check our
+        * calculation.
+        */
+       chkres(resc, result, divisor, init, flags, xorout, args, argpolys);
+       pfree(&init);
+}
+
+static void
+chkres(int *resc, model_t **result, const poly_t divisor, const poly_t init, int flags, const poly_t xorout, int args, const poly_t *argpolys) {
+       /* Checks a model against the argument list, and adds to the
+        * external results table if consistent.
+        * Extends the result array and update the external pointer if
+        * necessary.
+        */
+       model_t *rptr;
+       poly_t xor, crc;
+       const poly_t *aptr = argpolys, *const eptr = argpolys + args;
+
+       /* If the algorithm is reflected, an ordinary CRC requires the
+        * model's XorOut to be reversed, as XorOut follows the RefOut
+        * stage.
+        */
+       xor = pclone(xorout);
+       if(flags & P_REFOUT)
+               prev(&xor);
+
+       for(; aptr < eptr; ++aptr) {
+               crc = pcrc(*aptr, divisor, init, xor, 0);
+               if(ptst(crc)) {
+                       pfree(&crc);
+                       break;
+               } else {
+                       pfree(&crc);
+               }
+       }
+       pfree(&xor);
+       if(aptr != eptr) return;
+
+       if(!(*result = realloc(*result, ++*resc * sizeof(model_t))))
+               uerror("cannot reallocate result array");
+
+       rptr = *result + *resc - 1;
+       rptr->spoly  = pclone(divisor);
+       rptr->init   = pclone(init);
+       rptr->flags  = flags;
+       rptr->xorout = pclone(xorout);
+       rptr->name   = NULL;
+
+       /* compute check value for this model */
+       mcheck(rptr);
+
+       /* callback to notify new model */
+       ufound(rptr);
+}
diff --git a/client/reveng/reveng.h b/client/reveng/reveng.h
new file mode 100644 (file)
index 0000000..48dcb31
--- /dev/null
@@ -0,0 +1,214 @@
+/* reveng.h
+ * Greg Cook, 9/Apr/2015
+ */
+
+/* CRC RevEng, an arbitrary-precision CRC calculator and algorithm finder
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Gregory Cook
+ *
+ * This file is part of CRC RevEng.
+ *
+ * CRC RevEng 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.
+ *
+ * CRC RevEng 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 CRC RevEng.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef REVENG_H
+#define REVENG_H 1
+
+/* Configuration options */
+
+#include "config.h"
+
+#ifndef BMP_T
+#  error config.h: BMP_T must be defined as unsigned long or a longer unsigned type
+#endif
+
+#ifndef BMP_C
+#  error config.h: BMP_C() must define a BMP_T constant
+#endif
+
+#if !defined PRESETS && !defined BMPMACRO
+#  undef BMP_BIT
+#  undef BMP_SUB
+#endif
+
+#undef BMP_POF2
+
+#ifdef BMP_BIT
+#  ifndef BMP_SUB
+#    error config.h: BMP_SUB must be defined as the highest power of two that is strictly less than BMP_BIT
+#  elif BMP_BIT < 32
+#    error config.h: BMP_BIT must be at least 32
+#  elif BMP_SUB < 16
+#    error config.h: BMP_SUB must be at least 16
+#  elif (BMP_SUB >= BMP_BIT || BMP_SUB << 1 < BMP_BIT || BMP_SUB & (BMP_SUB - 1))
+#    error config.h: BMP_SUB must be defined as the highest power of two that is strictly less than BMP_BIT
+#  else /* BMP_SUB */
+#    define SETBMP()
+#  endif /* BMP_SUB */
+#  if BMP_BIT == 32
+#    define BMP_POF2 5
+#  elif BMP_BIT == 64
+#    define BMP_POF2 6
+#  elif BMP_BIT == 128
+#    define BMP_POF2 7
+#  elif BMP_BIT == 256
+#    define BMP_POF2 8
+#  elif BMP_BIT == 512
+#    define BMP_POF2 9
+#  elif BMP_BIT == 1024
+#    define BMP_POF2 10
+#  elif BMP_BIT == 2048
+#    define BMP_POF2 11
+#  elif BMP_BIT == 4096
+#    define BMP_POF2 12
+#  elif BMP_BIT == 8192
+#    define BMP_POF2 13
+#  elif BMP_BIT == 16384
+#    define BMP_POF2 14
+#  elif BMP_BIT == 32768
+#    define BMP_POF2 15
+#  elif BMP_BIT == 65536
+#    define BMP_POF2 16
+/* may extend list as required */
+#  elif (BMP_BIT & (BMP_BIT - 1)) == 0
+#    define BMP_POF2 1
+#  endif
+#else /* BMP_BIT */
+#  define BMP_BIT bmpbit
+#  define BMP_SUB bmpsub
+#  define SETBMP() setbmp()
+#endif /* BMP_BIT */
+
+/* Global definitions */
+
+/* CRC RevEng version string */
+#define VERSION "1.3.0"
+
+/* bmpbit.c */
+typedef BMP_T bmp_t;
+
+extern int bmpbit, bmpsub;
+extern void setbmp(void);
+
+/* poly.c */
+#define P_REFIN      1
+#define P_REFOUT     2
+#define P_MULXN      4
+#define P_RTJUST     8
+#define P_UPPER     16
+#define P_SPACE     32
+#define P_LTLBYT    64
+#define P_DIRECT   128
+
+/* default flags */
+#define P_BE     (P_RTJUST | P_MULXN)
+#define P_LE     (P_REFIN | P_REFOUT | P_MULXN)
+#define P_BELE   (P_REFOUT | P_MULXN)
+#define P_LEBE   (P_REFIN | P_RTJUST | P_MULXN)
+
+/* A poly_t constant representing the polynomial 0. */
+#define PZERO {0UL, (bmp_t *) 0}
+
+typedef struct {
+       unsigned long length;   /* number of significant bits */
+       bmp_t *bitmap;          /* bitmap, MSB first, */
+                               /* left-justified in each word */
+} poly_t;
+
+extern poly_t filtop(FILE *input, unsigned long length, int flags, int bperhx);
+extern poly_t strtop(const char *string, int flags, int bperhx);
+extern char *ptostr(const poly_t poly, int flags, int bperhx);
+extern char *pxsubs(const poly_t poly, int flags, int bperhx, unsigned long start, unsigned long end);
+extern poly_t pclone(const poly_t poly);
+extern void pcpy(poly_t *dest, const poly_t src);
+extern void pcanon(poly_t *poly);
+extern void pnorm(poly_t *poly);
+extern void psnorm(poly_t *poly);
+extern void pchop(poly_t *poly);
+extern void pkchop(poly_t *poly);
+extern unsigned long plen(const poly_t poly);
+extern int pcmp(const poly_t *a, const poly_t *b);
+extern int psncmp(const poly_t *a, const poly_t *b);
+extern int ptst(const poly_t poly);
+extern unsigned long pfirst(const poly_t poly);
+extern unsigned long plast(const poly_t poly);
+extern poly_t psubs(const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail);
+extern void pright(poly_t *poly, unsigned long length);
+extern void pshift(poly_t *dest, const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail);
+extern void ppaste(poly_t *dest, const poly_t src, unsigned long skip, unsigned long seek, unsigned long end, unsigned long fulllength);
+extern void pdiff(poly_t *dest, const poly_t src, unsigned long ofs);
+extern void psum(poly_t *dest, const poly_t src, unsigned long ofs);
+extern void prev(poly_t *poly);
+extern void prevch(poly_t *poly, int bperhx);
+extern void prcp(poly_t *poly);
+extern void pinv(poly_t *poly);
+extern poly_t pmod(const poly_t dividend, const poly_t divisor);
+extern poly_t pcrc(const poly_t message, const poly_t divisor, const poly_t init, const poly_t xorout, int flags);
+extern int piter(poly_t *poly);
+extern void palloc(poly_t *poly, unsigned long length);
+extern void pfree(poly_t *poly);
+extern void praloc(poly_t *poly, unsigned long length);
+extern int pmpar(const poly_t poly, const poly_t mask);
+extern int pident(const poly_t a, const poly_t b);
+
+/* model.c */
+#define M_OVERWR   256
+
+typedef struct {
+       poly_t spoly;           /* polynomial with highest-order term removed. length determines CRC width */
+       poly_t init;            /* initial register value. length == poly.length */
+       int flags;              /* P_REFIN and P_REFOUT indicate reflected input/output */
+       poly_t xorout;          /* final register XOR mask. length == poly.length */
+       poly_t check;           /* optional check value, the CRC of the UTF-8 string "123456789" */
+       const char *name;       /* optional canonical name of the model */
+} model_t;
+
+extern void mcpy(model_t *dest, const model_t *src);
+extern void mfree(model_t *model);
+extern int mcmp(const model_t *a, const model_t *b);
+extern int mbynam(model_t *dest, const char *key);
+extern void mbynum(model_t *dest, int num);
+extern int mcount(void);
+extern char *mnames(void);
+extern char *mtostr(const model_t *model);
+extern void mmatch(model_t *model, int flags);
+extern void mcanon(model_t *model);
+extern void mcheck(model_t *model);
+extern void mrev(model_t *model);
+extern void mnovel(model_t *model);
+
+/* reveng.c */
+#define R_HAVEP    512
+#define R_HAVEI   1024
+#define R_HAVERI  2048
+#define R_HAVERO  4096
+#define R_HAVEX   8192
+#define R_HAVEQ  16384
+
+#define R_SPMASK 0x7FFFFFFUL
+
+extern model_t *reveng(const model_t *guess, const poly_t qpoly, int rflags, int args, const poly_t *argpolys);
+
+/* cli.c */
+#define C_INFILE  1
+#define C_FORCE   2
+#define C_RESULT  4
+
+#define BUFFER 32768
+
+extern int reveng_main(int argc, char *argv[]);
+extern void ufound(const model_t *model);
+extern void uerror(const char *msg);
+extern void uprog(const poly_t gpoly, int flags, unsigned long seq);
+
+#endif /* REVENG_H */
index 6b26ec59ca119eeae71c2cf0b132fa50566b87e4..7576066313a575021f12a6b75b6e48438b56e70b 100644 (file)
@@ -22,6 +22,7 @@
 #include "../common/crc64.h"
 #include "../common/sha1.h"
 #include "aes.h"
+#include "cmdcrc.h"
 /**
  * The following params expected:
  *  UsbCommand c
  */
 static int l_SendCommand(lua_State *L){
 
-       /*
-        *
-        The SendCommand (native) expects the following structure:
-
-        typedef struct {
-         uint64_t cmd; //8 bytes
-         uint64_t arg[3]; // 8*3 bytes = 24 bytes
-         union {
-               uint8_t  asBytes[USB_CMD_DATA_SIZE]; // 1 byte * 512 = 512 bytes (OR)
-               uint32_t asDwords[USB_CMD_DATA_SIZE/4]; // 4 byte * 128 = 512 bytes
-         } d;
-       } PACKED UsbCommand;
-
-       ==> A 544 byte buffer will do.
-       **/
-       //Pop cmd
-       size_t size;
-       const char *data = luaL_checklstring(L, 1, &size);
-       if(size != sizeof(UsbCommand))
-       {
-               printf("Got data size %d, expected %d" , (int) size,(int) sizeof(UsbCommand));
-               lua_pushstring(L,"Wrong data size");
-               return 1;
-       }
+    /*
+     *
+     The SendCommand (native) expects the following structure:
+
+     typedef struct {
+      uint64_t cmd; //8 bytes
+      uint64_t arg[3]; // 8*3 bytes = 24 bytes
+      union {
+        uint8_t  asBytes[USB_CMD_DATA_SIZE]; // 1 byte * 512 = 512 bytes (OR)
+        uint32_t asDwords[USB_CMD_DATA_SIZE/4]; // 4 byte * 128 = 512 bytes
+      } d;
+    } PACKED UsbCommand;
+
+    ==> A 544 byte buffer will do.
+    **/
+    //Pop cmd
+    size_t size;
+    const char *data = luaL_checklstring(L, 1, &size);
+    if(size != sizeof(UsbCommand))
+    {
+        printf("Got data size %d, expected %d" , (int) size,(int) sizeof(UsbCommand));
+        lua_pushstring(L,"Wrong data size");
+        return 1;
+    }
 
 //    UsbCommand c = (*data);
-       SendCommand((UsbCommand* )data);
-       return 0; // no return values
+    SendCommand((UsbCommand* )data);
+    return 0; // no return values
 }
 /**
  * @brief The following params expected:
@@ -69,105 +70,105 @@ static int l_SendCommand(lua_State *L){
  */
 static int l_WaitForResponseTimeout(lua_State *L){
 
-       uint32_t cmd = 0;
-       size_t ms_timeout = -1;
-
-       //Check number of arguments
-       int n = lua_gettop(L);
-       if(n == 0)
-       {
-               //signal error by returning Nil, errorstring
-               lua_pushnil(L);
-               lua_pushstring(L,"You need to supply at least command to wait for");
-               return 2; // two return values
-       }
-       if(n >= 1)
-       {
-               //pop cmd
-               cmd = luaL_checkunsigned(L,1);
-       }
-       if(n >= 2)
-       {
-               //Did the user send a timeout ?
-               //Check if the current top of stack is an integer
-               ms_timeout = luaL_checkunsigned(L,2);
-               //printf("Timeout set to %dms\n" , (int) ms_timeout);
-       }
-
-       UsbCommand response;
-
-       if(WaitForResponseTimeout(cmd, &response, ms_timeout))
-       {
-               //Push it as a string
-               lua_pushlstring(L,(const char *)&response,sizeof(UsbCommand));
-
-               return 1;// return 1 to signal one return value
-       }else{
-               //Push a Nil instead
-               lua_pushnil(L);
-               return 1;// one return value
-       }
+    uint32_t cmd = 0;
+    size_t ms_timeout = -1;
+
+    //Check number of arguments
+    int n = lua_gettop(L);
+    if(n == 0)
+    {
+        //signal error by returning Nil, errorstring
+        lua_pushnil(L);
+        lua_pushstring(L,"You need to supply at least command to wait for");
+        return 2; // two return values
+    }
+    if(n >= 1)
+    {
+        //pop cmd
+        cmd = luaL_checkunsigned(L,1);
+    }
+    if(n >= 2)
+    {
+        //Did the user send a timeout ?
+        //Check if the current top of stack is an integer
+        ms_timeout = luaL_checkunsigned(L,2);
+        //printf("Timeout set to %dms\n" , (int) ms_timeout);
+    }
+
+    UsbCommand response;
+
+    if(WaitForResponseTimeout(cmd, &response, ms_timeout))
+    {
+        //Push it as a string
+         lua_pushlstring(L,(const char *)&response,sizeof(UsbCommand));
+
+        return 1;// return 1 to signal one return value
+    }else{
+        //Push a Nil instead
+        lua_pushnil(L);
+        return 1;// one return value
+    }
 }
 
 static int returnToLuaWithError(lua_State *L, const char* fmt, ...)
 {
-       char buffer[200];
-       va_list args;
-       va_start(args,fmt);
-       vsnprintf(buffer, sizeof(buffer), fmt,args);
-       va_end(args);
-
-       lua_pushnil(L);
-       lua_pushstring(L,buffer);
-       return 2;
+    char buffer[200];
+    va_list args;
+    va_start(args,fmt);
+    vsnprintf(buffer, sizeof(buffer), fmt,args);
+    va_end(args);
+
+    lua_pushnil(L);
+    lua_pushstring(L,buffer);
+    return 2;
 }
 
 static int l_nonce2key(lua_State *L){
 
-       size_t size;
-       const char *p_uid = luaL_checklstring(L, 1, &size);
-       if(size != 4)  return returnToLuaWithError(L,"Wrong size of uid, got %d bytes, expected 4", (int) size);
+    size_t size;
+    const char *p_uid = luaL_checklstring(L, 1, &size);
+    if(size != 4)  return returnToLuaWithError(L,"Wrong size of uid, got %d bytes, expected 4", (int) size);
 
-       const char *p_nt = luaL_checklstring(L, 2, &size);
-       if(size != 4)  return returnToLuaWithError(L,"Wrong size of nt, got %d bytes, expected 4", (int) size);
+    const char *p_nt = luaL_checklstring(L, 2, &size);
+    if(size != 4)  return returnToLuaWithError(L,"Wrong size of nt, got %d bytes, expected 4", (int) size);
 
-       const char *p_nr = luaL_checklstring(L, 3, &size);
-       if(size != 4)  return returnToLuaWithError(L,"Wrong size of nr, got %d bytes, expected 4", (int) size);
+    const char *p_nr = luaL_checklstring(L, 3, &size);
+    if(size != 4)  return returnToLuaWithError(L,"Wrong size of nr, got %d bytes, expected 4", (int) size);
 
-       const char *p_par_info = luaL_checklstring(L, 4, &size);
-       if(size != 8)  return returnToLuaWithError(L,"Wrong size of par_info, got %d bytes, expected 8", (int) size);
+    const char *p_par_info = luaL_checklstring(L, 4, &size);
+    if(size != 8)  return returnToLuaWithError(L,"Wrong size of par_info, got %d bytes, expected 8", (int) size);
 
-       const char *p_pks_info = luaL_checklstring(L, 5, &size);
-       if(size != 8)  return returnToLuaWithError(L,"Wrong size of ks_info, got %d bytes, expected 8", (int) size);
+    const char *p_pks_info = luaL_checklstring(L, 5, &size);
+    if(size != 8)  return returnToLuaWithError(L,"Wrong size of ks_info, got %d bytes, expected 8", (int) size);
 
 
-       uint32_t uid = bytes_to_num(( uint8_t *)p_uid,4);
-       uint32_t nt = bytes_to_num(( uint8_t *)p_nt,4);
+    uint32_t uid = bytes_to_num(( uint8_t *)p_uid,4);
+    uint32_t nt = bytes_to_num(( uint8_t *)p_nt,4);
 
-       uint32_t nr = bytes_to_num(( uint8_t*)p_nr,4);
-       uint64_t par_info = bytes_to_num(( uint8_t *)p_par_info,8);
-       uint64_t ks_info = bytes_to_num(( uint8_t *)p_pks_info,8);
+    uint32_t nr = bytes_to_num(( uint8_t*)p_nr,4);
+    uint64_t par_info = bytes_to_num(( uint8_t *)p_par_info,8);
+    uint64_t ks_info = bytes_to_num(( uint8_t *)p_pks_info,8);
 
-       uint64_t key = 0;
+    uint64_t key = 0;
 
-       int retval = nonce2key(uid,nt, nr, par_info,ks_info, &key);
+    int retval = nonce2key(uid,nt, nr, par_info,ks_info, &key);
 
-       //Push the retval on the stack
-       lua_pushinteger(L,retval);
+    //Push the retval on the stack
+    lua_pushinteger(L,retval);
 
-       //Push the key onto the stack
-       uint8_t dest_key[8];
-       num_to_bytes(key,sizeof(dest_key),dest_key);
+    //Push the key onto the stack
+    uint8_t dest_key[8];
+    num_to_bytes(key,sizeof(dest_key),dest_key);
 
-       //printf("Pushing to lua stack: %012"llx"\n",key);
-       lua_pushlstring(L,(const char *) dest_key,sizeof(dest_key));
+    //printf("Pushing to lua stack: %012"llx"\n",key);
+    lua_pushlstring(L,(const char *) dest_key,sizeof(dest_key));
 
-       return 2; //Two return values
+    return 2; //Two return values
 }
 //static int l_PrintAndLog(lua_State *L){ return CmdHF14AMfDump(luaL_checkstring(L, 1));}
 static int l_clearCommandBuffer(lua_State *L){
-       clearCommandBuffer();
-       return 0;
+    clearCommandBuffer();
+    return 0;
 }
 /**
  * @brief l_foobar is a dummy function to test lua-integration with
@@ -176,23 +177,23 @@ static int l_clearCommandBuffer(lua_State *L){
  */
 static int l_foobar(lua_State *L)
 {
-       //Check number of arguments
-       int n = lua_gettop(L);
-       printf("foobar called with %d arguments" , n);
-       lua_settop(L, 0);
-       printf("Arguments discarded, stack now contains %d elements", lua_gettop(L));
-
-       // todo: this is not used, where was it intended for?
-       // UsbCommand response =  {CMD_MIFARE_READBL, {1337, 1338, 1339}};
-
-       printf("Now returning a uint64_t as a string");
-       uint64_t x = 0xDEADBEEF;
-       uint8_t destination[8];
-       num_to_bytes(x,sizeof(x),destination);
-       lua_pushlstring(L,(const char *)&x,sizeof(x));
-       lua_pushlstring(L,(const char *)destination,sizeof(destination));
-
-       return 2;
+    //Check number of arguments
+    int n = lua_gettop(L);
+    printf("foobar called with %d arguments" , n);
+    lua_settop(L, 0);
+    printf("Arguments discarded, stack now contains %d elements", lua_gettop(L));
+
+    // todo: this is not used, where was it intended for?
+    // UsbCommand response =  {CMD_MIFARE_READBL, {1337, 1338, 1339}};
+
+    printf("Now returning a uint64_t as a string");
+    uint64_t x = 0xDEADBEEF;
+    uint8_t destination[8];
+    num_to_bytes(x,sizeof(x),destination);
+    lua_pushlstring(L,(const char *)&x,sizeof(x));
+    lua_pushlstring(L,(const char *)destination,sizeof(destination));
+
+    return 2;
 }
 
 
@@ -203,8 +204,8 @@ static int l_foobar(lua_State *L)
  */
 static int l_ukbhit(lua_State *L)
 {
-       lua_pushboolean(L,ukbhit() ? true : false);
-       return 1;
+    lua_pushboolean(L,ukbhit() ? true : false);
+    return 1;
 }
 /**
  * @brief Calls the command line parser to deal with the command. This enables
@@ -214,18 +215,18 @@ static int l_ukbhit(lua_State *L)
  */
 static int l_CmdConsole(lua_State *L)
 {
-       CommandReceived((char *)luaL_checkstring(L, 1));
-       return 0;
+    CommandReceived((char *)luaL_checkstring(L, 1));
+    return 0;
 }
 
 static int l_iso15693_crc(lua_State *L)
 {
-       //    uint16_t Iso15693Crc(uint8_t *v, int n);
-       size_t size;
-       const char *v = luaL_checklstring(L, 1, &size);
-       uint16_t retval = Iso15693Crc((uint8_t *) v, size);
-       lua_pushinteger(L, (int) retval);
-       return 1;
+    //    uint16_t Iso15693Crc(uint8_t *v, int n);
+    size_t size;
+    const char *v = luaL_checklstring(L, 1, &size);
+    uint16_t retval = Iso15693Crc((uint8_t *) v, size);
+    lua_pushinteger(L, (int) retval);
+    return 1;
 }
 
 /*
@@ -236,15 +237,15 @@ static int l_aes128decrypt_cbc(lua_State *L)
 {
        //Check number of arguments
        int i;
-       size_t size;
-       const char *p_key = luaL_checklstring(L, 1, &size);
-       if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
+    size_t size;
+    const char *p_key = luaL_checklstring(L, 1, &size);
+    if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
 
-       const char *p_encTxt = luaL_checklstring(L, 2, &size);
+    const char *p_encTxt = luaL_checklstring(L, 2, &size);
 
        unsigned char indata[16] = {0x00};
        unsigned char outdata[16] = {0x00};
-       unsigned char aes_key[16] = {0x00};
+    unsigned char aes_key[16] = {0x00};
        unsigned char iv[16] = {0x00};
 
        // convert key to bytearray and convert input to bytearray
@@ -253,11 +254,11 @@ static int l_aes128decrypt_cbc(lua_State *L)
                sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
        }
 
-       aes_context ctx;
-       aes_init(&ctx);
+    aes_context ctx;
+    aes_init(&ctx);
        aes_setkey_dec(&ctx, aes_key, 128);
-       aes_crypt_cbc(&ctx,AES_DECRYPT,sizeof(indata), iv, indata,outdata );
-       //Push decrypted array as a string
+       aes_crypt_cbc(&ctx, AES_DECRYPT, sizeof(indata), iv, indata, outdata );
+    //Push decrypted array as a string
        lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
        return 1;// return 1 to signal one return value
 }
@@ -265,27 +266,27 @@ static int l_aes128decrypt_ecb(lua_State *L)
 {
        //Check number of arguments
        int i;
-       size_t size;
-       const char *p_key = luaL_checklstring(L, 1, &size);
-       if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
+    size_t size;
+    const char *p_key = luaL_checklstring(L, 1, &size);
+    if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
 
-       const char *p_encTxt = luaL_checklstring(L, 2, &size);
+    const char *p_encTxt = luaL_checklstring(L, 2, &size);
 
        unsigned char indata[16] = {0x00};
        unsigned char outdata[16] = {0x00};
-       unsigned char aes_key[16] = {0x00};
+    unsigned char aes_key[16] = {0x00};
 
        // convert key to bytearray and convert input to bytearray
        for (i = 0; i < 32; i += 2) {
                sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]);
                sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
        }
-       aes_context ctx;
-       aes_init(&ctx);
+    aes_context ctx;
+    aes_init(&ctx);
        aes_setkey_dec(&ctx, aes_key, 128);
        aes_crypt_ecb(&ctx, AES_DECRYPT, indata, outdata );
 
-       //Push decrypted array as a string
+    //Push decrypted array as a string
        lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
        return 1;// return 1 to signal one return value
 }
@@ -294,15 +295,15 @@ static int l_aes128encrypt_cbc(lua_State *L)
 {
        //Check number of arguments
        int i;
-       size_t size;
-       const char *p_key = luaL_checklstring(L, 1, &size);
-       if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
-
-       const char *p_txt = luaL_checklstring(L, 2, &size);
+    size_t size;
+    const char *p_key = luaL_checklstring(L, 1, &size);
+    if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
 
+    const char *p_txt = luaL_checklstring(L, 2, &size);
+    
        unsigned char indata[16] = {0x00};
        unsigned char outdata[16] = {0x00};
-       unsigned char aes_key[16] = {0x00};
+    unsigned char aes_key[16] = {0x00};
        unsigned char iv[16] = {0x00};
        
        for (i = 0; i < 32; i += 2) {
@@ -310,8 +311,8 @@ static int l_aes128encrypt_cbc(lua_State *L)
                sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
        }
 
-       aes_context ctx;
-       aes_init(&ctx);
+    aes_context ctx;
+    aes_init(&ctx);
        aes_setkey_enc(&ctx, aes_key, 128);
        aes_crypt_cbc(&ctx, AES_ENCRYPT, sizeof(indata), iv, indata, outdata );
        //Push encrypted array as a string
@@ -323,22 +324,22 @@ static int l_aes128encrypt_ecb(lua_State *L)
 {
        //Check number of arguments
        int i;
-       size_t size;
-       const char *p_key = luaL_checklstring(L, 1, &size);
-       if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
-
-       const char *p_txt = luaL_checklstring(L, 2, &size);
+    size_t size;
+    const char *p_key = luaL_checklstring(L, 1, &size);
+    if(size != 32)  return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
 
+    const char *p_txt = luaL_checklstring(L, 2, &size);
+    
        unsigned char indata[16] = {0x00};
        unsigned char outdata[16] = {0x00};
-       unsigned char aes_key[16] = {0x00};
-
+    unsigned char aes_key[16] = {0x00};
+       
        for (i = 0; i < 32; i += 2) {
                sscanf(&p_txt[i], "%02x", (unsigned int *)&indata[i / 2]);
                sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
-       }
-       aes_context ctx;
-       aes_init(&ctx);
+       }       
+    aes_context ctx;
+    aes_init(&ctx);
        aes_setkey_enc(&ctx, aes_key, 128);
        aes_crypt_ecb(&ctx, AES_ENCRYPT, indata, outdata );
        //Push encrypted array as a string
@@ -352,8 +353,8 @@ static int l_crc16(lua_State *L)
        const char *p_str = luaL_checklstring(L, 1, &size);
 
        uint16_t retval = crc16_ccitt( (uint8_t*) p_str, size);
-       lua_pushinteger(L, (int) retval);
-       return 1;
+    lua_pushinteger(L, (int) retval);
+    return 1;
 }
 
 static int l_crc64(lua_State *L)
@@ -381,10 +382,66 @@ static int l_crc64(lua_State *L)
 static int l_sha1(lua_State *L)
 {
        size_t size;
-       const char *p_str = luaL_checklstring(L, 1, &size);
-       unsigned char outdata[20] = {0x00};
-       sha1( (uint8_t*) p_str, size, outdata);
-       lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
+       const char *p_str = luaL_checklstring(L, 1, &size);     
+       unsigned char outdata[20] = {0x00};                                                                                                                                                                     
+    sha1( (uint8_t*) p_str, size, outdata);                                                                                                                                                                 
+    lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
+    return 1;  
+}
+
+static int l_reveng_models(lua_State *L){
+
+       char *models[80];
+       int count = 0;
+       int in_width = luaL_checkinteger(L, 1);
+       
+       if( in_width > 89 ) return returnToLuaWithError(L,"Width cannot exceed 89, got %d", in_width);
+
+       uint8_t width[80];
+       width[0] = (uint8_t)in_width;
+       int ans = GetModels(models, &count, width);
+       if (!ans) return 0;
+       
+       lua_newtable(L);
+       
+       for (int i = 0; i < count; i++){
+               lua_pushstring(L,  (const char*)models[i]);
+               lua_rawseti(L,-2,i+1);
+               free(models[i]);
+       }
+
+       return 1;
+}
+
+//Called with 4 parameters.
+// inModel   ,string containing the crc model name: 'CRC-8'
+// inHexStr  ,string containing the hex representation of the data that will be used for CRC calculations.
+// reverse   ,int 0/1  (bool) if 1, calculate the reverse CRC
+// endian    ,char,  'B','b','L','l','t','r' describing if Big-Endian or Little-Endian should be used in different combinations.
+//
+// outputs:  string with hex representation of the CRC result
+static int l_reveng_RunModel(lua_State *L){
+       //-c || -v
+       //inModel = valid model name string - CRC-8
+       //inHexStr = input hex string to calculate crc on
+       //reverse = reverse calc option if true
+       //endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified
+       //          l = little endian input and output, L = little endian output only, t = left justified}
+       //result = calculated crc hex string    
+       char result[50];
+       
+       const char *inModel = luaL_checkstring(L, 1);
+       const char *inHexStr = luaL_checkstring(L, 2);
+    bool reverse =  lua_toboolean(L, 3);
+       const char endian = luaL_checkstring(L, 4)[0];
+
+       //PrintAndLog("mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse);
+       //    int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result)
+       int ans = RunModel( (char *)inModel, (char *)inHexStr, reverse, endian, result);
+       if (!ans)       
+               return returnToLuaWithError(L,"Reveng failed");
+
+       lua_pushstring(L, (const char*)result); 
        return 1;
 }
 
@@ -398,16 +455,16 @@ static int l_sha1(lua_State *L)
  */
 int setLuaPath( lua_State* L, const char* path )
 {
-       lua_getglobal( L, "package" );
-       lua_getfield( L, -1, "path" ); // get field "path" from table at top of stack (-1)
-       const char* cur_path = lua_tostring( L, -1 ); // grab path string from top of stack
-       int requiredLength = strlen(cur_path)+ strlen(path)+10; //A few bytes too many, whatever we can afford it
-       char * buf = malloc(requiredLength);
-       snprintf(buf, requiredLength, "%s;%s", cur_path, path);
-       lua_pop( L, 1 ); // get rid of the string on the stack we just pushed on line 5
-       lua_pushstring( L, buf ); // push the new one
-       lua_setfield( L, -2, "path" ); // set the field "path" in table at -2 with value at top of stack
-       lua_pop( L, 1 ); // get rid of package table from top of stack
+    lua_getglobal( L, "package" );
+    lua_getfield( L, -1, "path" ); // get field "path" from table at top of stack (-1)
+    const char* cur_path = lua_tostring( L, -1 ); // grab path string from top of stack
+    int requiredLength = strlen(cur_path)+ strlen(path)+10; //A few bytes too many, whatever we can afford it
+    char * buf = malloc(requiredLength);
+    snprintf(buf, requiredLength, "%s;%s", cur_path, path);
+    lua_pop( L, 1 ); // get rid of the string on the stack we just pushed on line 5
+    lua_pushstring( L, buf ); // push the new one
+    lua_setfield( L, -2, "path" ); // set the field "path" in table at -2 with value at top of stack
+    lua_pop( L, 1 ); // get rid of package table from top of stack
        free(buf);
        return 0; // all done!
 }
@@ -416,45 +473,47 @@ int setLuaPath( lua_State* L, const char* path )
 int set_pm3_libraries(lua_State *L)
 {
 
-       static const luaL_Reg libs[] = {
-               {"SendCommand",                 l_SendCommand},
-               {"WaitForResponseTimeout",      l_WaitForResponseTimeout},
-               {"nonce2key",                   l_nonce2key},
-               //{"PrintAndLog",                 l_PrintAndLog},
-               {"foobar",                      l_foobar},
-               {"ukbhit",                      l_ukbhit},
-               {"clearCommandBuffer",          l_clearCommandBuffer},
+    static const luaL_Reg libs[] = {
+        {"SendCommand",                 l_SendCommand},
+        {"WaitForResponseTimeout",      l_WaitForResponseTimeout},
+        {"nonce2key",                   l_nonce2key},
+        //{"PrintAndLog",                 l_PrintAndLog},
+        {"foobar",                      l_foobar},
+        {"ukbhit",                      l_ukbhit},
+        {"clearCommandBuffer",          l_clearCommandBuffer},
                {"console",                     l_CmdConsole},
                {"iso15693_crc",                l_iso15693_crc},
                {"aes128_decrypt",              l_aes128decrypt_cbc},
                {"aes128_decrypt_ecb",          l_aes128decrypt_ecb},
-               {"aes128_encrypt",              l_aes128encrypt_cbc},
+               {"aes128_encrypt",              l_aes128encrypt_cbc},           
                {"aes128_encrypt_ecb",          l_aes128encrypt_ecb},
                {"crc16",                       l_crc16},
                {"crc64",                       l_crc64},
-               {"sha1",                        l_sha1},
-               {NULL, NULL}
-       };
-
-       lua_pushglobaltable(L);
-       // Core library is in this table. Contains '
-       //this is 'pm3' table
-       lua_newtable(L);
-
-       //Put the function into the hash table.
-       for (int i = 0; libs[i].name; i++) {
-               lua_pushcfunction(L, libs[i].func);
-               lua_setfield(L, -2, libs[i].name);//set the name, pop stack
-       }
-       //Name of 'core'
-       lua_setfield(L, -2, "core");
-
-       //-- remove the global environment table from the stack
-       lua_pop(L, 1);
-
-       //-- Last but not least, add to the LUA_PATH (package.path in lua)
-       // so we can load libraries from the ./lualib/ - directory
-       setLuaPath(L,"./lualibs/?.lua");
-
-       return 1;
+               {"sha1",                                                l_sha1},
+               {"reveng_models",                               l_reveng_models},
+               {"reveng_runmodel",                             l_reveng_RunModel},
+        {NULL, NULL}
+    };
+
+    lua_pushglobaltable(L);
+    // Core library is in this table. Contains '
+    //this is 'pm3' table
+    lua_newtable(L);
+
+    //Put the function into the hash table.
+    for (int i = 0; libs[i].name; i++) {
+        lua_pushcfunction(L, libs[i].func);
+        lua_setfield(L, -2, libs[i].name);//set the name, pop stack
+    }
+    //Name of 'core'
+    lua_setfield(L, -2, "core");
+
+    //-- remove the global environment table from the stack
+    lua_pop(L, 1);
+
+    //-- Last but not least, add to the LUA_PATH (package.path in lua)
+    // so we can load libraries from the ./lualib/ - directory
+    setLuaPath(L,"./lualibs/?.lua");
+
+    return 1;
 }
index 2386d42d9e7c3c385bc912aee301ded73c762507..114d9ef484f04a5d7c098ba0f519064107bf2146 100644 (file)
@@ -14,6 +14,7 @@ This is a script to dump and decrypt the data of a specific type of Mifare Mini
 
 Arguments:
        -h             : this help
+       -t                         : selftest
        -k <key>       : Mifare Key A.
 ]]
 
@@ -364,14 +365,22 @@ end
 local function selftest()
        local testdata = '000F42430D0A14000001D11F'..'5D738517'
        local chksum = getChecksum(testdata)
-       local calc = calculateChecksum( utils.ConvertHexToBytes(testdata:sub(1,24)))    
-       print  ('TESTDATA    :: '..testdata)
-       print  ('DATA        :: '..testdata:sub(1,24))
-       print (('CHKSUM      :: %X'):format(chksum))    
-       print (('CHKSUM CALC :: %X'):format(calc))      
-       print ('UPDATE CHKSUM :: '..updateChecksum(testdata))
-       
-       
+       local calc = calculateChecksum( utils.ConvertHexToBytes(testdata:sub(1,24)))
+       local isValid = false
+       local validStr = "FAIL"
+       if calc == chksum then
+               isValid = true
+               validStr = "OK"
+       end     
+       local newtestdata = updateChecksum(testdata)
+       local revalidated = "FAIL"
+       if newtestdata == testdata then
+               revalidated = "OK"
+       end     
+       print  ('TESTDATA      :: '..testdata)
+       print  ('DATA          :: '..testdata:sub(1,24))        
+       print (('VALID CHKSUM  :: %s'):format(validStr ))       
+       print (('UPDATE CHKSUM :: %s'):format(revalidated))     
 end
 --- 
 -- The main entry point
@@ -382,18 +391,15 @@ function main(args)
 
        local cmd, result, err, blockNo, keyA
        local blocks = {}
-       local decryptkey = ''
+       local magic = ''
        
        -- Read the parameters
-       for o, a in getopt.getopt(args, 'hk:') do
+       for o, a in getopt.getopt(args, 'hk:t') do
                if o == "h" then help() return end
                if o == "k" then keyA = a end
+               if o == "t" then return selftest() end
        end
        
-       selftest()
-       
-       local tst2 = '00100100030209094312356432324E34B79A349B'
-       
        -- validate input args.
        keyA =  keyA or '6dd747e86975'
        if #(keyA) ~= 12 then
@@ -410,15 +416,7 @@ function main(args)
        if not result then
                return oops(err)
        end
-
        core.clearCommandBuffer()
-
-       print(result.uid, keyA)
-
-       local my = result.uid
-       if 1 == 1 then 
-               return
-       end
        
        -- Show tag info
        print((' Found tag %s'):format(result.name))
@@ -426,11 +424,10 @@ function main(args)
        local longrandom = RANDOM..result.uid
        local res = utils.Sha1Hex(longrandom)
        res  = utils.ConvertBytesToHex(utils.ConvertAsciiToBytes(res:sub(1,16)))
-       decryptkey = utils.SwapEndiannessStr(res:sub(1,8) , 32)
-       decryptkey = decryptkey..utils.SwapEndiannessStr( res:sub(9,16),32)
-       decryptkey = decryptkey..utils.SwapEndiannessStr( res:sub(17,24),32)
-       decryptkey = decryptkey..utils.SwapEndiannessStr( res:sub(25,32),32)
-       print('Decrypt key::',decryptkey)
+       magic = utils.SwapEndiannessStr(res:sub(1,8) , 32)
+       magic = magic..utils.SwapEndiannessStr( res:sub(9,16),32)
+       magic = magic..utils.SwapEndiannessStr( res:sub(17,24),32)
+       magic = magic..utils.SwapEndiannessStr( res:sub(25,32),32)
        print('Reading card data')
        print('Raw','Decrypted')
        for blockNo = 0, numBlocks-1, 1 do
@@ -452,7 +449,7 @@ function main(args)
                        if string.find(blockdata, '^0+$') then
                                print(blockdata, blockdata)
                        else
-                               local aes = core.aes128_decrypt_ecb(decryptkey, blockdata)
+                               local aes = core.aes128_decrypt_ecb(magic, blockdata)
                                local bytes =  utils.ConvertAsciiToBytes(aes)
                                local hex = utils.ConvertBytesToHex(bytes)
                                print(blockdata , hex)
@@ -465,9 +462,6 @@ function main(args)
                        print(sectortrailer, sectortrailer, blockdata:sub(13,20))
                end
        end
-       -- checksum fyra sista bytes i varje rad.  (kanske inte för s0)
-       -- s0b1,s1b0,s2b0,s3b0
-       -- 
 end
 
 main(args)
diff --git a/client/scripts/e.lua b/client/scripts/e.lua
new file mode 100644 (file)
index 0000000..a20b8e4
--- /dev/null
@@ -0,0 +1,72 @@
+local getopt = require('getopt')
+local utils = require('utils')
+
+example = "script calculates many different checksums (CRC) over the provided hex input"
+author = "Iceman"
+desc =
+[[
+This script calculates many checksums (CRC) over the provided hex input. 
+
+Arguments:
+       -b                              data in hex
+       -w                              bitwidth of the CRC family of algorithm. <optional> defaults to all known CRC presets.
+Examples : 
+       script run e -b 010203040506070809
+       script run e -b 010203040506070809 -w 16
+]]
+
+--- 
+-- A debug printout-function
+function dbg(args)
+       if DEBUG then
+               print("###", args)
+       end
+end 
+--- 
+-- This is only meant to be used when errors occur
+function oops(err)
+       print("ERROR: ",err)
+       return nil,err
+end
+--- 
+-- Usage help
+function help()
+       print(desc)
+       print("Example usage")
+       print(example)
+end
+--- 
+-- The main entry point
+function main(args)
+
+       local data
+       local width = 0
+
+       -- Read the parameters
+       for o, a in getopt.getopt(args, 'hb:w:') do
+               if o == "h" then return help() end
+               if o == "b" then data = a end
+               if o == "w" then width = a end
+       end
+
+       data = data or '01020304'
+       
+       print( string.rep('-',60) )
+       print('Bit width of CRC | '..width)
+       print('Bytes            | '..data)
+       print('')
+       print( ('%-20s| %-16s| %s'):format('Model','CRC', 'CRC reverse'))
+       print( string.rep('-',60) )
+       local lists = core.reveng_models(width)
+       for _,i in pairs(lists) do
+               local a1 = core.reveng_runmodel(i, data, false, '0')
+               local a2 = core.reveng_runmodel(i, data, true, '0')
+               local a3 = core.reveng_runmodel(i, data, false, 'b')
+               local a4 = core.reveng_runmodel(i, data, false, 'B')
+               local a5 = core.reveng_runmodel(i, data, false, 'l')
+               local a6 = core.reveng_runmodel(i, data, false, 'L')            
+               print( ('%-20s| %-16s| %-16s| %-16s| %-16s| %-16s| %-16s'):format(i, a1:upper(), a2:upper(),a3:upper(),a4:upper(),a5:upper(),a6:upper() ) )
+       end
+end
+
+main(args)
\ No newline at end of file
diff --git a/client/scripts/test.lua b/client/scripts/test.lua
deleted file mode 100644 (file)
index 76adc98..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-local foo = "This shows how to use some standard libraries"
-print(foo)
-local answer
-repeat
-       io.write("Continue with this operation (y/n)? ")
-       io.flush()
-       answer=io.read()
-until answer=="y" or answer=="n"
-local x = "Ok then, %s"
-print (x:format("whatever"))
\ No newline at end of file
index f8990b159536dc9225832ad5920f6e1f37d2b37f..153a01ba974077047f34f926e32278f4d230faad 100644 (file)
@@ -27,8 +27,8 @@ The outlined procedure is as following:
 
 Loop:
        change the configuretion block 0 with:
-    -xx 00 xxxx = RF/8 
-    -xx 04 xxxx = RF/16
+       -xx 00 xxxx = RF/8 
+       -xx 04 xxxx = RF/16
        -xx 08 xxxx = RF/32
        -xx 0C xxxx = RF/40
        -xx 10 xxxx = RF/50
index c0d01bc32983a2efb313f99640d745ce3af8cde9..6645a99ea5e5f7519380a6d2dc306c1cc9ae879f 100644 (file)
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <time.h>
 #include <readline/readline.h>
 #include <pthread.h>
-
+#include "loclass/cipherutils.h"
 #include "ui.h"
+#include "cmdmain.h"
+#include "cmddata.h"
+#include "graph.h"
+//#include <liquid/liquid.h>
+#define M_PI 3.14159265358979323846264338327
 
 double CursorScaleFactor;
 int PlotGridX, PlotGridY, PlotGridXdefault= 64, PlotGridYdefault= 64;
 int offline;
-int flushAfterWrite = 0;  //buzzy
+int flushAfterWrite = 0;
 extern pthread_mutex_t print_lock;
 
 static char *logfilename = "proxmark3.log";
@@ -32,13 +38,13 @@ void PrintAndLog(char *fmt, ...)
        int saved_point;
        va_list argptr, argptr2;
        static FILE *logfile = NULL;
-       static int logging=1;
+       static int logging = 1;
 
        // lock this section to avoid interlacing prints from different threats
        pthread_mutex_lock(&print_lock);
   
        if (logging && !logfile) {
-               logfile=fopen(logfilename, "a");
+               logfile = fopen(logfilename, "a");
                if (!logfile) {
                        fprintf(stderr, "Can't open logfile, logging disabled!\n");
                        logging=0;
@@ -77,16 +83,399 @@ void PrintAndLog(char *fmt, ...)
        }
        va_end(argptr2);
 
-       if (flushAfterWrite == 1)  //buzzy
-       {
+       if (flushAfterWrite == 1) {
                fflush(NULL);
        }
        //release lock
        pthread_mutex_unlock(&print_lock);  
 }
 
-
 void SetLogFilename(char *fn)
 {
   logfilename = fn;
 }
+
+int manchester_decode( int * data, const size_t len, uint8_t * dataout,  size_t dataoutlen){
+       
+       int bitlength = 0;
+       int clock, high, low, startindex;
+       low = startindex = 0;
+       high = 1;
+       uint8_t * bitStream =  (uint8_t* ) malloc(sizeof(uint8_t) * dataoutlen);        
+       memset(bitStream, 0x00, dataoutlen);    
+       
+       /* Detect high and lows */
+       DetectHighLowInGraph(&high, &low, TRUE); 
+
+       /* get clock */
+       clock = GetAskClock("",false, false);
+
+       startindex = DetectFirstTransition(data, len, high);
+  
+       if (high != 1)
+               // decode "raw"
+               bitlength = ManchesterConvertFrom255(data, len, bitStream, dataoutlen, high, low, clock, startindex);
+       else
+               // decode manchester
+               bitlength = ManchesterConvertFrom1(data, len, bitStream, dataoutlen, clock, startindex);
+
+       memcpy(dataout, bitStream, bitlength);
+       free(bitStream);
+       return bitlength;
+}
+ int DetectFirstTransition(const int * data, const size_t len, int threshold){
+
+       int i = 0;
+       /* now look for the first threshold */
+       for (; i < len; ++i) {
+               if (data[i] == threshold) {
+                       break;
+               }
+       }
+       return i;
+ }
+
+ int ManchesterConvertFrom255(const int * data, const size_t len, uint8_t * dataout, int dataoutlen, int high, int low, int clock, int startIndex){
+
+       int i, j, z, hithigh, hitlow, bitIndex, startType;
+       i = 0;
+       bitIndex = 0;
+       
+       int isDamp = 0;
+       int damplimit = (int)((high / 2) * 0.3);
+       int dampHi =  (high/2)+damplimit;
+       int dampLow = (high/2)-damplimit;
+       int firstST = 0;
+
+       // i = clock frame of data
+       for (; i < (int)(len/clock); i++)
+       {
+               hithigh = 0;
+               hitlow = 0;
+               startType = -1;
+               z = startIndex + (i*clock);
+               isDamp = 0;
+                       
+               /* Find out if we hit both high and low peaks */
+               for (j = 0; j < clock; j++)
+               {               
+                       if (data[z+j] == high){
+                               hithigh = 1;
+                               if ( startType == -1)
+                                       startType = 1;
+                       }
+                       
+                       if (data[z+j] == low ){
+                               hitlow = 1;
+                               if ( startType == -1)
+                                       startType = 0;
+                       } 
+               
+                       if (hithigh && hitlow)
+                         break;
+               }
+               
+               // No high value found, are we in a dampening field?
+               if ( !hithigh ) {
+                       //PrintAndLog(" # Entering damp test at index : %d (%d)", z+j, j);
+                       for (j = 0; j < clock; j++) {
+                               if ( 
+                                    (data[z+j] <= dampHi && data[z+j] >= dampLow)
+                                  ){
+                                  isDamp++;
+                               }
+                       }
+               }
+
+               /*  Manchester Switching..
+                       0: High -> Low   
+                       1: Low -> High  
+               */
+               if (startType == 0)
+                       dataout[bitIndex++] = 1;
+               else if (startType == 1) 
+                       dataout[bitIndex++] = 0;
+               else
+                       dataout[bitIndex++] = 2;
+                       
+               if ( isDamp > clock/2 ) {
+                       firstST++;
+               }
+               
+               if ( firstST == 4)
+                       break;
+               if ( bitIndex >= dataoutlen-1 )
+                       break;
+       }
+       return bitIndex;
+ }
+ int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout,int dataoutlen, int clock, int startIndex){
+
+       int i,j, bitindex, lc, tolerance, warnings;
+       warnings = 0;
+       int upperlimit = len*2/clock+8;
+       i = startIndex;
+       j = 0;
+       tolerance = clock/4;
+       uint8_t decodedArr[len];
+       
+       /* Detect duration between 2 successive transitions */
+       for (bitindex = 1; i < len; i++) {
+       
+               if (data[i-1] != data[i]) {
+                       lc = i - startIndex;
+                       startIndex = i;
+
+                       // Error check: if bitindex becomes too large, we do not
+                       // have a Manchester encoded bitstream or the clock is really wrong!
+                       if (bitindex > upperlimit ) {
+                               PrintAndLog("Error: the clock you gave is probably wrong, aborting.");
+                               return 0;
+                       }
+                       // Then switch depending on lc length:
+                       // Tolerance is 1/4 of clock rate (arbitrary)
+                       if (abs((lc-clock)/2) < tolerance) {
+                               // Short pulse : either "1" or "0"
+                               decodedArr[bitindex++] = data[i-1];
+                       } else if (abs(lc-clock) < tolerance) {
+                               // Long pulse: either "11" or "00"
+                               decodedArr[bitindex++] = data[i-1];
+                               decodedArr[bitindex++] = data[i-1];
+                       } else {
+                               ++warnings;
+                               PrintAndLog("Warning: Manchester decode error for pulse width detection.");
+                               if (warnings > 10) {
+                                       PrintAndLog("Error: too many detection errors, aborting.");
+                                       return 0; 
+                               }
+                       }
+               }
+       }
+       
+       /* 
+       * We have a decodedArr of "01" ("1") or "10" ("0")
+       * parse it into final decoded dataout
+    */ 
+    for (i = 0; i < bitindex; i += 2) {
+
+           if ((decodedArr[i] == 0) && (decodedArr[i+1] == 1)) {
+                       dataout[j++] = 1;
+               } else if ((decodedArr[i] == 1) && (decodedArr[i+1] == 0)) {
+                       dataout[j++] = 0;
+               } else {
+                       i++;
+                       warnings++;
+                       PrintAndLog("Unsynchronized, resync...");
+                       PrintAndLog("(too many of those messages mean the stream is not Manchester encoded)");
+
+                       if (warnings > 10) {    
+                               PrintAndLog("Error: too many decode errors, aborting.");
+                               return 0;
+                       }
+               }
+    }
+       
+       PrintAndLog("%s", sprint_hex(dataout, j));
+       return j;
+ }
+ void ManchesterDiffDecodedString(const uint8_t* bitstream, size_t len, uint8_t invert){
+       /* 
+       * We have a bitstream of "01" ("1") or "10" ("0")
+       * parse it into final decoded bitstream
+    */ 
+       int i, j, warnings; 
+       uint8_t decodedArr[(len/2)+1];
+
+       j = warnings = 0;
+       
+       uint8_t lastbit = 0;
+       
+    for (i = 0; i < len; i += 2) {
+       
+               uint8_t first = bitstream[i];
+               uint8_t second = bitstream[i+1];
+
+               if ( first == second ) {
+                       ++i;
+                       ++warnings;
+                       if (warnings > 10) {
+                               PrintAndLog("Error: too many decode errors, aborting.");
+                               return;
+                       }
+               } 
+               else if ( lastbit != first ) {
+                       decodedArr[j++] = 0 ^ invert;
+               }
+               else {
+                       decodedArr[j++] = 1 ^ invert;
+               }
+               lastbit = second;
+    }
+       
+       PrintAndLog("%s", sprint_hex(decodedArr, j));
+}
+void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){
+
+       PrintAndLog(" Manchester decoded  : %d bits", len);
+         
+       uint8_t mod = len % blocksize;
+       uint8_t div = len / blocksize;
+       int i;
+  
+       // Now output the bitstream to the scrollback by line of 16 bits
+       for (i = 0; i < div*blocksize; i+=blocksize) {
+               PrintAndLog(" %s", sprint_bin(bitStream+i,blocksize) );
+       }
+       
+       if ( mod > 0 )
+               PrintAndLog(" %s", sprint_bin(bitStream+i, mod) );      
+}
+
+/* Sliding DFT
+   Smooths out 
+*/ 
+void iceFsk2(int * data, const size_t len){
+
+       int i, j;
+       int * output =  (int* ) malloc(sizeof(int) * len);      
+       memset(output, 0x00, len);
+
+       // for (i=0; i<len-5; ++i){
+               // for ( j=1; j <=5; ++j) {
+                       // output[i] += data[i*j];
+               // }
+               // output[i] /= 5;
+       // }
+       int rest = 127;
+       int tmp =0;
+       for (i=0; i<len; ++i){
+               if ( data[i] < 127)
+                       output[i] = 0;
+               else {
+                       tmp =  (100 * (data[i]-rest)) / rest;
+                       output[i] = (tmp > 60)? 100:0;
+               }
+       }
+       
+       for (j=0; j<len; ++j)
+               data[j] = output[j];
+               
+       free(output);
+}
+
+void iceFsk3(int * data, const size_t len){
+
+       int i,j;
+       
+       int * output =  (int* ) malloc(sizeof(int) * len);      
+       memset(output, 0x00, len);
+       float fc           = 0.1125f;          // center frequency
+       size_t adjustedLen = len;
+       
+    // create very simple low-pass filter to remove images (2nd-order Butterworth)
+    float complex iir_buf[3] = {0,0,0};
+    float b[3] = {0.003621681514929,  0.007243363029857, 0.003621681514929};
+    float a[3] = {1.000000000000000, -1.822694925196308, 0.837181651256023};
+    
+    float sample           = 0;      // input sample read from file
+    float complex x_prime  = 1.0f;   // save sample for estimating frequency
+    float complex x;
+               
+       for (i=0; i<adjustedLen; ++i) {
+
+               sample = data[i]+128;
+               
+        // remove DC offset and mix to complex baseband
+        x = (sample - 127.5f) * cexpf( _Complex_I * 2 * M_PI * fc * i );
+
+        // apply low-pass filter, removing spectral image (IIR using direct-form II)
+        iir_buf[2] = iir_buf[1];
+        iir_buf[1] = iir_buf[0];
+        iir_buf[0] = x - a[1]*iir_buf[1] - a[2]*iir_buf[2];
+        x          = b[0]*iir_buf[0] +
+                     b[1]*iir_buf[1] +
+                     b[2]*iir_buf[2];
+                                        
+        // compute instantaneous frequency by looking at phase difference
+        // between adjacent samples
+        float freq = cargf(x*conjf(x_prime));
+        x_prime = x;    // retain this sample for next iteration
+
+               output[i] =(freq > 0)? 10 : -10;
+    } 
+
+       // show data
+       for (j=0; j<adjustedLen; ++j)
+               data[j] = output[j];
+               
+       CmdLtrim("30");
+       adjustedLen -= 30;
+       
+       // zero crossings.
+       for (j=0; j<adjustedLen; ++j){
+               if ( data[j] == 10) break;
+       }
+       int startOne =j;
+       
+       for (;j<adjustedLen; ++j){
+               if ( data[j] == -10 ) break;
+       }
+       int stopOne = j-1;
+       
+       int fieldlen = stopOne-startOne;
+       
+       fieldlen = (fieldlen == 39 || fieldlen == 41)? 40 : fieldlen;
+       fieldlen = (fieldlen == 59 || fieldlen == 51)? 50 : fieldlen;
+       if ( fieldlen != 40 && fieldlen != 50){
+               printf("Detected field Length: %d \n", fieldlen);
+               printf("Can only handle 40 or 50.  Aborting...\n");
+               return;
+       }
+       
+       // FSK sequence start == 000111
+       int startPos = 0;
+       for (i =0; i<adjustedLen; ++i){
+               int dec = 0;
+               for ( j = 0; j < 6*fieldlen; ++j){
+                       dec += data[i + j];
+               }
+               if (dec == 0) {
+                       startPos = i;
+                       break;
+               }
+       }
+       
+       printf("000111 position: %d \n", startPos);
+
+       startPos += 6*fieldlen+5;
+       
+       int bit =0;
+       printf("BINARY\n");
+       printf("R/40 :  ");
+       for (i =startPos ; i < adjustedLen; i += 40){
+               bit = data[i]>0 ? 1:0;
+               printf("%d", bit );
+       }
+       printf("\n");   
+       
+       printf("R/50 :  ");
+       for (i =startPos ; i < adjustedLen; i += 50){
+               bit = data[i]>0 ? 1:0;
+               printf("%d", bit );     }
+       printf("\n");   
+       
+       free(output);
+}
+
+float complex cexpf (float complex Z)
+{
+  float complex  Res;
+  double rho = exp (__real__ Z);
+  __real__ Res = rho * cosf(__imag__ Z);
+  __imag__ Res = rho * sinf(__imag__ Z);
+  return Res;
+}
index a45799d5c430dcad8094354a702cf81c9a7f47cb..6a45fcfdabb65a545478bcf77d5f9a31a41331b0 100644 (file)
 #ifndef UI_H__
 #define UI_H__
 
+#include <math.h>
+#include <complex.h>
+#include "util.h"
+
 void ShowGui(void);
 void HideGraphWindow(void);
 void ShowGraphWindow(void);
@@ -23,4 +27,13 @@ extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault;
 extern int offline;
 extern int flushAfterWrite;   //buzzy
 
+int manchester_decode( int * data, const size_t len, uint8_t * dataout,  size_t dataoutlen);
+int GetT55x7Clock( const int * data, const size_t len, int high );
+int DetectFirstTransition(const int * data, const size_t len, int low);
+void PrintPaddedManchester( uint8_t * bitStream, size_t len, size_t blocksize);
+void ManchesterDiffDecodedString( const uint8_t *bitStream, size_t len, uint8_t invert );
+int ManchesterConvertFrom255(const int * data, const size_t len, uint8_t * dataout,int dataoutlen, int high, int low, int clock, int startIndex);
+int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout, int dataoutlen, int clock, int startIndex);
+void iceFsk2(int * data, const size_t len);
+void iceFsk3(int * data, const size_t len);
 #endif
index 9f2142c6a4114d7c2e6f50f6ac97fca70c709522..797a93927e16ae57a6598ee905840bcfc3962ca8 100644 (file)
@@ -113,11 +113,11 @@ char *sprint_hex(const uint8_t *data, const size_t len) {
        int maxLen = ( len > 1024/3) ? 1024/3 : len;
        static char buf[1024];
        memset(buf, 0x00, 1024);
-       char *tmp = buf;
+       char * tmp = buf;
        size_t i;
 
        for (i=0; i < maxLen; ++i, tmp += 3)
-               sprintf(tmp, "%02x ", data[i]);
+               sprintf(tmp, "%02X ", data[i]);
 
        return buf;
 }
@@ -248,7 +248,7 @@ char param_getchar(const char *line, int paramnum)
 
 uint8_t param_get8(const char *line, int paramnum)
 {
-       return param_get8ex(line, paramnum, 10, 0);
+       return param_get8ex(line, paramnum, 0, 10);
 }
 
 /**
@@ -394,7 +394,7 @@ int hextobinstring(char *target, char *source)
 
 // convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source)
 // return number of bits converted
-int binarraytohex(char *target,char *source, int length)
+int binarraytohex(char *target, char *source, int length)
 {
     unsigned char i, x;
     int j = length;
@@ -445,7 +445,7 @@ void wiegand_add_parity(char *target, char *source, char length)
     *(target)= GetParity(source + length / 2, ODD, length / 2);
 }
 
-void xor(unsigned char *dst, unsigned char *src, size_t len) {
+void xor(unsigned char * dst, unsigned char * src, size_t len) {
    for( ; len > 0; len--,dst++,src++)
        *dst ^= *src;
 }
@@ -453,3 +453,18 @@ void xor(unsigned char *dst, unsigned char *src, size_t len) {
 int32_t le24toh (uint8_t data[3]) {
     return (data[2] << 16) | (data[1] << 8) | data[0];
 }
+
+
+uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits) {
+       
+       int i = start;
+       int j = len-1;
+
+       if (len > 32) return 0;
+
+       uint32_t tmp = 0;
+       for (; j >= 0; --j, ++i)
+               tmp     |= bits[i] << j;
+
+       return tmp;
+}
index 2d2beaf42cd12169babe5b12c603ef7680a4c3b4..a57daf82c9dc8d5e8221edec02f1727801c8830a 100644 (file)
@@ -63,5 +63,6 @@ void binarraytobinstring(char *target,  char *source,  int length);
 uint8_t GetParity( char *string, uint8_t type,  int length);
 void wiegand_add_parity(char *target, char *source, char length);
 
-void xor(unsigned char *dst, unsigned char *src, size_t len);
-int32_t le24toh(uint8_t data[3]);
+void xor(unsigned char * dst, unsigned char * src, size_t len);
+int32_t le24toh (uint8_t data[3]);
+uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits);
index 2b2bb2fbd7c47fa514d5d2c05dadd890b9a69400..b933361048b6d3756e4c3e843976ce81fb360faf 100644 (file)
@@ -66,7 +66,9 @@ VPATH = . ../common/ ../fpga/
 
 INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/usb_cmd.h $(APP_INCLUDES)
 
-CFLAGS =  -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 $(APP_CFLAGS) -Os
+# compile hint: -flto to minimise size.
+CFLAGS =  -c $(INCLUDE) -Wall -Werror  -fdata-sections -ffunction-sections -pedantic -std=c99 -Os $(APP_CFLAGS)
+#CFLAGS =  -c $(INCLUDE) -Wall -Werror  -pedantic -std=c99 -Os $(APP_CFLAGS)
 LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n
 
 LIBS = -lgcc
index a37f1d7e35f69e63e6fba2259f0a011b8f1bf4ec..07090fc6fbbeec4f56300dbb6246c4a5adf74041 100644 (file)
@@ -7,45 +7,46 @@
 //-----------------------------------------------------------------------------
 
 #include "crc16.h"
+#define CRC16_MASK_CCITT 0x1021
 
 unsigned short update_crc16( unsigned short crc, unsigned char c )
 {
-       unsigned short i, v, tcrc = 0;
+  unsigned short i, v, tcrc = 0;
 
-       v = (crc ^ c) & 0xff;
-       for (i = 0; i < 8; i++) {
-               tcrc = ( (tcrc ^ v) & 1 ) ? ( tcrc >> 1 ) ^ 0x8408 : tcrc >> 1;
-               v >>= 1;
-       }
+  v = (crc ^ c) & 0xff;
+  for (i = 0; i < 8; i++) {
+      tcrc = ( (tcrc ^ v) & 1 ) ? ( tcrc >> 1 ) ^ 0x8408 : tcrc >> 1;
+      v >>= 1;
+  }
 
-       return ((crc >> 8) ^ tcrc)&0xffff;
+  return ((crc >> 8) ^ tcrc)&0xffff;
 }
 
 uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial) {
-
-       if (length == 0) return (~remainder);
-
-       for (int byte = 0; byte < length; ++byte) {
-               remainder ^= (message[byte] << 8);
-               for (uint8_t bit = 8; bit > 0; --bit) {
-                       if (remainder & 0x8000) {
-                               remainder = (remainder << 1) ^ polynomial;
-                       } else {
-                               remainder = (remainder << 1);
-                       }
-               }
-       }
-       return remainder;
+    
+       if (length == 0)
+        return (~remainder);
+                       
+    for (int byte = 0; byte < length; ++byte) {
+        remainder ^= (message[byte] << 8);
+        for (uint8_t bit = 8; bit > 0; --bit) {
+            if (remainder & 0x8000) {
+                remainder = (remainder << 1) ^ polynomial;
+            } else {
+                remainder = (remainder << 1);
+            }
+        }
+    }
+    return remainder;
 }
 
 uint16_t crc16_ccitt(uint8_t const *message, int length) {
-       return crc16(message, length, 0xffff, 0x1021);
+    return crc16(message, length, 0xffff, CRC16_MASK_CCITT);
 }
 
 uint16_t crc16_ccitt_kermit(uint8_t const *message, int length) {
-       return bit_reverse_uint16(crc16(message, length, 0x0000, 0x1021));
+    return bit_reverse_uint16(crc16(message, length, 0x0000, CRC16_MASK_CCITT));
 }
-
 uint16_t bit_reverse_uint16 (uint16_t value) {
        const uint16_t mask0 = 0x5555;
        const uint16_t mask1 = 0x3333;
diff --git a/common/desfire.h b/common/desfire.h
new file mode 100644 (file)
index 0000000..c163c5c
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef __DESFIRE_H
+#define __DESFIRE_H
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "aes.h"
+
+#define MAX_CRYPTO_BLOCK_SIZE 16
+/* Mifare DESFire EV1 Application crypto operations */
+#define APPLICATION_CRYPTO_DES    0x00
+#define APPLICATION_CRYPTO_3K3DES 0x40
+#define APPLICATION_CRYPTO_AES    0x80
+
+#define MAC_LENGTH 4
+#define CMAC_LENGTH 8
+
+typedef enum {
+    MCD_SEND,
+    MCD_RECEIVE
+} MifareCryptoDirection;
+
+typedef enum {
+    MCO_ENCYPHER,
+    MCO_DECYPHER
+} MifareCryptoOperation;
+
+#define MDCM_MASK 0x000F
+
+#define CMAC_NONE 0
+
+// Data send to the PICC is used to update the CMAC
+#define CMAC_COMMAND 0x010
+// Data received from the PICC is used to update the CMAC
+#define CMAC_VERIFY  0x020
+
+// MAC the command (when MDCM_MACED)
+#define MAC_COMMAND 0x100
+// The command returns a MAC to verify (when MDCM_MACED)
+#define MAC_VERIFY  0x200
+
+#define ENC_COMMAND 0x1000
+#define NO_CRC      0x2000
+
+#define MAC_MASK   0x0F0
+#define CMAC_MACK  0xF00
+
+/* Communication mode */
+#define MDCM_PLAIN      0x00
+#define MDCM_MACED      0x01
+#define MDCM_ENCIPHERED 0x03
+
+/* Error code managed by the library */
+#define CRYPTO_ERROR            0x01
+
+
+enum DESFIRE_AUTH_SCHEME {
+       AS_LEGACY,
+       AS_NEW
+};
+
+enum DESFIRE_CRYPTOALGO {
+       T_DES = 0x00,
+       T_3DES = 0x01,
+       T_3K3DES = 0x02,
+       T_AES = 0x03
+};
+
+
+#define DESFIRE_KEY(key) ((struct desfire_key *) key)
+struct desfire_key {
+    enum DESFIRE_CRYPTOALGO type;
+    uint8_t data[24];
+    // DES_key_schedule ks1;
+    // DES_key_schedule ks2;
+    // DES_key_schedule ks3;
+       AesCtx aes_ks;
+    uint8_t cmac_sk1[24];
+    uint8_t cmac_sk2[24];
+    uint8_t aes_version;
+};
+typedef struct desfire_key *desfirekey_t;
+
+#define DESFIRE(tag) ((struct desfire_tag *) tag)
+struct desfire_tag {
+    iso14a_card_select_t info;
+    int active;
+    uint8_t last_picc_error;
+    uint8_t last_internal_error;
+    uint8_t last_pcd_error;
+    desfirekey_t session_key;
+       enum DESFIRE_AUTH_SCHEME authentication_scheme;
+    uint8_t authenticated_key_no;
+    
+       uint8_t ivect[MAX_CRYPTO_BLOCK_SIZE];
+    uint8_t cmac[16];
+    uint8_t *crypto_buffer;
+    size_t crypto_buffer_size;
+    uint32_t selected_application;
+};
+typedef struct desfire_tag *desfiretag_t;
+
+
+/* File types */
+enum DESFIRE_FILE_TYPES {
+    MDFT_STANDARD_DATA_FILE             = 0x00,
+    MDFT_BACKUP_DATA_FILE               = 0x01,
+    MDFT_VALUE_FILE_WITH_BACKUP         = 0x02,
+    MDFT_LINEAR_RECORD_FILE_WITH_BACKUP = 0x03,
+    MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP = 0x04
+};
+
+
+
+enum DESFIRE_STATUS {
+    OPERATION_OK                               = 0x00,
+    NO_CHANGES                                         = 0x0c,
+    OUT_OF_EEPROM_ERROR                = 0x0e,
+    ILLEGAL_COMMAND_CODE               = 0x1c,
+    INTEGRITY_ERROR                    = 0x1e,
+    NO_SUCH_KEY                                = 0x40,
+    LENGTH_ERROR                               = 0x7e,
+    PERMISSION_DENIED                  = 0x9d,
+    PARAMETER_ERROR                    = 0x9e,
+    APPLICATION_NOT_FOUND              = 0xa0,
+    APPL_INTEGRITY_ERROR               = 0xa1,
+    AUTHENTICATION_ERROR               = 0xae,
+    ADDITIONAL_FRAME                   = 0xaf,
+    BOUNDARY_ERROR                             = 0xbe,
+    PICC_INTEGRITY_ERROR               = 0xc1,
+    COMMAND_ABORTED                    = 0xca,
+    PICC_DISABLED_ERROR                = 0xcd,
+    COUNT_ERROR                                = 0xce,
+    DUPLICATE_ERROR                    = 0xde,
+    EEPROM_ERROR                               = 0xee,
+    FILE_NOT_FOUND                             = 0xf0,
+    FILE_INTEGRITY_ERROR               = 0xf1
+};
+
+enum DESFIRE_CMD {
+    CREATE_APPLICATION                         = 0xca,
+    DELETE_APPLICATION                         = 0xda,
+    GET_APPLICATION_IDS                = 0x6a,
+    SELECT_APPLICATION                         = 0x5a,
+    FORMAT_PICC                                = 0xfc,
+    GET_VERSION                                = 0x60,
+    READ_DATA                                  = 0xbd,
+    WRITE_DATA                                 = 0x3d,
+    GET_VALUE                                  = 0x6c,
+    CREDIT                                             = 0x0c,
+    DEBIT                                              = 0xdc,
+    LIMITED_CREDIT                             = 0x1c,
+    WRITE_RECORD                               = 0x3b,
+    READ_RECORDS                               = 0xbb,
+    CLEAR_RECORD_FILE                  = 0xeb,
+    COMMIT_TRANSACTION                         = 0xc7,
+    ABORT_TRANSACTION                  = 0xa7,
+    GET_FREE_MEMORY             = 0x6e,
+       GET_FILE_IDS                            = 0x6f,
+    GET_FILE_SETTINGS                  = 0xf5,
+    CHANGE_FILE_SETTINGS               = 0x5f,
+    CREATE_STD_DATA_FILE               = 0xcd,
+    CREATE_BACKUP_DATA_FILE    = 0xcb,
+    CREATE_VALUE_FILE                  = 0xcc,
+    CREATE_LINEAR_RECORD_FILE  = 0xc1,
+    CREATE_CYCLIC_RECORD_FILE  = 0xc0,
+    DELETE_FILE                                = 0xdf,
+    AUTHENTICATE                               = 0x0a,  // AUTHENTICATE_NATIVE
+       AUTHENTICATE_ISO                        = 0x1a,  // AUTHENTICATE_STANDARD
+       AUTHENTICATE_AES                        = 0xaa,
+    CHANGE_KEY_SETTINGS                = 0x54,
+    GET_KEY_SETTINGS                   = 0x45,
+    CHANGE_KEY                                         = 0xc4,
+    GET_KEY_VERSION                    = 0x64,
+    AUTHENTICATION_FRAME               = 0xAF
+};
+
+#endif
+
index a6def1a91be2df84675660c67ec636ecc3ba4b55..851546ae239df0d728ecd73bf0367fae1c82e0fe 100644 (file)
@@ -6,7 +6,7 @@
 // ISO14443 CRC calculation code.
 //-----------------------------------------------------------------------------
 
-#include "iso14443crc.h"
+#include "../common/iso14443crc.h"
 
 static unsigned short UpdateCrc14443(unsigned char ch, unsigned short *lpwCrc)
 {
index 87347714dbe6be95f1570320efe2512e0f79d05f..80941116332a81430091eadb7c08b5cc39d57a91 100644 (file)
@@ -8,7 +8,7 @@
 
 #ifndef __ISO14443CRC_H
 #define __ISO14443CRC_H
-#include "common.h"
+#include "../include/common.h"
 
 //-----------------------------------------------------------------------------
 // Routines to compute the CRCs (two different flavours, just for confusion)
index 26e636ca7b0c27d90dee14bf3f79d70168fd546c..0ec5492b996d8897513b34e3a85b7f2adf9fd3d8 100644 (file)
@@ -7,7 +7,7 @@
 //-----------------------------------------------------------------------------
 
 
-#include "proxmark3.h"
+#include "../include/proxmark3.h"
 #include <stdint.h>
 #include <stdlib.h>
 //#include "iso15693tools.h"
index 4f3b1ffee1167ab51a067502451cb4e634c88cef..322429ad716266924d72507ce02c248ac654dd38 100644 (file)
@@ -6,7 +6,7 @@
 // LEFIC's obfuscation function
 //-----------------------------------------------------------------------------
 
-#include "legic_prng.h"
+#include "../include/legic_prng.h"
 
 struct lfsr {
   uint8_t  a;
index f13a567c6fe8cda87b1cf70248cd201603fe023f..94e08ffa7563ad3569f2473057b476bf041db6cb 100644 (file)
@@ -526,7 +526,7 @@ int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, ui
        return (int)startIdx;
 }
 
-uint32_t bytebits_to_byte(uint8_t *src, size_t numbits)
+uint32_t bytebits_to_byte(uint8_tsrc, size_t numbits)
 {
        uint32_t num = 0;
        for(int i = 0 ; i < numbits ; i++)
@@ -593,7 +593,7 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p
                j--;
                // if parity fails then return 0
                if (pType != 2) {
-                       if (parityTest(parityWd, pLen, pType) == 0) return -1;
+               if (parityTest(parityWd, pLen, pType) == 0) return -1;
                }
                bitCnt+=(pLen-1);
                parityWd = 0;
index 580342728b866ee7f76d3f09537580da1c43c72d..466e84f1b169e83d5aebb11a34a89702ccedaab6 100644 (file)
@@ -109,7 +109,7 @@ NXP/Philips CUSTOM COMMANDS
 #define ISO14443A_CMD_WUPA       0x52
 #define ISO14443A_CMD_ANTICOLL_OR_SELECT     0x93
 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_2   0x95
-#define ISO14443A_CMD_WRITEBLOCK 0xA0 // or 0xA2 ?
+#define ISO14443A_CMD_WRITEBLOCK 0xA0
 #define ISO14443A_CMD_HALT       0x50
 #define ISO14443A_CMD_RATS       0xE0
 
@@ -128,16 +128,14 @@ NXP/Philips CUSTOM COMMANDS
 #define MIFARE_ULC_AUTH_1       0x1A
 #define MIFARE_ULC_AUTH_2       0xAF
 
-#define MIFARE_ULEV1_AUTH       0x1B
-#define MIFARE_ULEV1_VERSION    0x60
-#define MIFARE_ULEV1_FASTREAD   0x3A
-//#define MIFARE_ULEV1_WRITE      0xA2
-//#define MIFARE_ULEV1_COMP_WRITE 0xA0
-#define MIFARE_ULEV1_READ_CNT   0x39
-#define MIFARE_ULEV1_INCR_CNT   0xA5
-#define MIFARE_ULEV1_READSIG    0x3C
-#define MIFARE_ULEV1_CHECKTEAR  0x3E
-#define MIFARE_ULEV1_VCSL       0x4B
+#define MIFARE_ULEV1_AUTH              0x1B
+#define MIFARE_ULEV1_VERSION   0x60
+#define MIFARE_ULEV1_FASTREAD  0x3A
+#define MIFARE_ULEV1_READ_CNT  0x39
+#define MIFARE_ULEV1_INCR_CNT  0xA5
+#define MIFARE_ULEV1_READSIG   0x3C
+#define MIFARE_ULEV1_CHECKTEAR 0x3E
+#define MIFARE_ULEV1_VCSL              0x4B
 
 /**
 06 00 = INITIATE
@@ -180,9 +178,25 @@ NXP/Philips CUSTOM COMMANDS
 #define ISO15693_READ_MULTI_SECSTATUS 0x2C
 
 
+// Topaz command set:
+#define        TOPAZ_REQA                                              0x26    // Request
+#define        TOPAZ_WUPA                                              0x52    // WakeUp
+#define        TOPAZ_RID                                               0x78    // Read ID
+#define        TOPAZ_RALL                                              0x00    // Read All (all bytes)
+#define        TOPAZ_READ                                              0x01    // Read (a single byte)
+#define        TOPAZ_WRITE_E                                   0x53    // Write-with-erase (a single byte)
+#define        TOPAZ_WRITE_NE                                  0x1a    // Write-no-erase (a single byte)
+// additional commands for Dynamic Memory Model
+#define TOPAZ_RSEG                                             0x10    // Read segment
+#define TOPAZ_READ8                                            0x02    // Read (eight bytes)
+#define TOPAZ_WRITE_E8                                 0x54    // Write-with-erase (eight bytes)
+#define TOPAZ_WRITE_NE8                                        0x1B    // Write-no-erase (eight bytes)
+
+
 #define ISO_14443A 0
 #define ICLASS     1
 #define ISO_14443B 2
+#define TOPAZ          3
 
 //-- Picopass fuses
 #define FUSE_FPERS   0x80
index d20c54a429288cef97fc178ae8b55c4d4d770c94..3cd2e055598984a5d11218092b3e8f5d5d005eb9 100644 (file)
@@ -2,6 +2,7 @@
  *  FIPS-180-1 compliant SHA-1 implementation
  *
  *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
+ *
  *  This file is part of mbed TLS (https://tls.mbed.org)
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -662,4 +663,3 @@ exit:
 #endif /* POLARSSL_SELF_TEST */
 
 #endif /* POLARSSL_SHA1_C */
-
diff --git a/cp2tau b/cp2tau
new file mode 100644 (file)
index 0000000..8b6ee4b
--- /dev/null
+++ b/cp2tau
@@ -0,0 +1,4 @@
+cp armsrc/obj/*.elf /z
+cp armsrc/obj/*.s19 /z
+cp bootrom/obj/*.elf /z
+cp bootrom/obj/*.s19 /z
index 20fb2bd4401254d899d6273451bfccbd827f562b..53078a782422c09596f006d95c85ae45da20072d 100644 (file)
Binary files a/fpga/fpga_hf.bit and b/fpga/fpga_hf.bit differ
index dece2db3195844ce9ce2d371d09a1ff7df0069bf..06142637bc2573bb5138a1f922e88675c4380fcc 100644 (file)
@@ -99,8 +99,10 @@ end
 reg [5:0] corr_i_cnt;
 reg [5:0] corr_q_cnt;
 // And a couple of registers in which to accumulate the correlations.
-reg signed [15:0] corr_i_accum;
-reg signed [15:0] corr_q_accum;
+// we would add at most 32 times adc_d, the result can be held in 13 bits. 
+// Need one additional bit because it can be negative as well
+reg signed [13:0] corr_i_accum;
+reg signed [13:0] corr_q_accum;
 reg signed [7:0] corr_i_out;
 reg signed [7:0] corr_q_out;
 
@@ -114,12 +116,13 @@ begin
     begin
         if(snoop)
         begin
-            corr_i_out <= {corr_i_accum[12:6], after_hysteresis_prev};
-            corr_q_out <= {corr_q_accum[12:6], after_hysteresis};
+                       // highest 7 significant bits of tag signal (signed), 1 bit reader signal:
+            corr_i_out <= {corr_i_accum[13:7], after_hysteresis_prev};
+            corr_q_out <= {corr_q_accum[13:7], after_hysteresis};
         end
         else
         begin
-            // Only correlations need to be delivered.
+            // highest 8 significant bits of tag signal
             corr_i_out <= corr_i_accum[13:6];
             corr_q_out <= corr_q_accum[13:6];
         end
@@ -168,7 +171,9 @@ begin
         end
     end
 
-    if(corr_i_cnt[5:2] == 4'b000 || corr_i_cnt[5:2] == 4'b1000)
+       // set ssp_frame signal for corr_i_cnt = 0..3 and corr_i_cnt = 32..35
+       // (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;
diff --git a/iceman.txt b/iceman.txt
new file mode 100644 (file)
index 0000000..e69de29
index e2b7a7c5548e2fd37dde3864173cfe08ea95a8b7..89ff758e20727266698385204dc05e2f5b60c0e7 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _MIFARE_H_
 #define _MIFARE_H_
 
-#include "common.h"
+#include "../include/common.h"
 
 //-----------------------------------------------------------------------------
 // ISO 14443A
@@ -26,14 +26,15 @@ typedef struct {
 } __attribute__((__packed__)) iso14a_card_select_t;
 
 typedef enum ISO14A_COMMAND {
-       ISO14A_CONNECT = 1,
-       ISO14A_NO_DISCONNECT = 2,
-       ISO14A_APDU = 4,
-       ISO14A_RAW = 8,
-       ISO14A_REQUEST_TRIGGER = 0x10,
-       ISO14A_APPEND_CRC = 0x20,
-       ISO14A_SET_TIMEOUT = 0x40,
-       ISO14A_NO_SELECT = 0x80
+       ISO14A_CONNECT =                        (1 << 0),
+       ISO14A_NO_DISCONNECT =          (1 << 1),
+       ISO14A_APDU =                           (1 << 2),
+       ISO14A_RAW =                            (1 << 3),
+       ISO14A_REQUEST_TRIGGER =        (1 << 4),
+       ISO14A_APPEND_CRC =                     (1 << 5),
+       ISO14A_SET_TIMEOUT =            (1 << 6),
+       ISO14A_NO_SELECT =                      (1 << 7),
+       ISO14A_TOPAZMODE =                      (1 << 8)
 } iso14a_command_t;
 
 #endif // _MIFARE_H_
index 357395d43f3103eb01a66144648dbd2e97d001e9..345793eca48f8cd5cdd80e634a1f536a6af85a14 100644 (file)
@@ -128,12 +128,13 @@ typedef struct{
 #define CMD_READER_LEGIC_RF                                               0x0388
 #define CMD_WRITER_LEGIC_RF                                               0x0389
 #define CMD_EPA_PACE_COLLECT_NONCE                                        0x038A
+//#define CMD_EPA_                                                          0x038B
 
 #define CMD_SNOOP_ICLASS                                                  0x0392
 #define CMD_SIMULATE_TAG_ICLASS                                           0x0393
 #define CMD_READER_ICLASS                                                 0x0394
 #define CMD_READER_ICLASS_REPLAY                                          0x0395
-#define CMD_ICLASS_ISO14443A_WRITE                                        0x0397
+#define CMD_ICLASS_ISO14443A_WRITE                                                                               0x0397
 #define CMD_ICLASS_EML_MEMSET                                             0x0398
 
 // For measurements of the antenna tuning
@@ -167,8 +168,8 @@ typedef struct{
 #define CMD_MIFARE_READSC                                                 0x0621
 #define CMD_MIFAREU_READCARD                                              0x0721
 #define CMD_MIFARE_WRITEBL                                                0x0622
-#define CMD_MIFAREU_WRITEBL                                               0x0722
-#define CMD_MIFAREU_WRITEBL_COMPAT                                        0x0723
+#define CMD_MIFAREU_WRITEBL                                                                      0x0722
+#define CMD_MIFAREU_WRITEBL_COMPAT                                                           0x0723
 
 #define CMD_MIFARE_CHKKEYS                                                0x0623
 
@@ -188,6 +189,8 @@ typedef struct{
 #define CMD_MIFARE_DESFIRE_INFO                                           0x072d
 #define CMD_MIFARE_DESFIRE                                                0x072e
 
+#define CMD_MIFARE_COLLECT_NONCES                                                                                0x072f
+
 #define CMD_UNKNOWN                                                       0xFFFF
 
 
@@ -199,11 +202,11 @@ typedef struct{
 
 
 //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
-#define FLAG_ICLASS_READER_AA           0x10
+#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
+#define FLAG_ICLASS_READER_AA          0x10
 #define FLAG_ICLASS_READER_ONE_TRY      0x20
 
 
index 0e64a3e8e02b1c56f626432630ffc7e58063358e..0af15cdcd6d51cf439d71ab5ad0cd288e4a4d71e 100755 (executable)
@@ -62,9 +62,8 @@ int main (int argc, char *argv[]) {
                crypto1_word(t, uid ^ nt, 0);
                crypto1_word(t, nr1_enc, 1);
                if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt, 64))) {
-      printf("\nFound Key: [%012"llx"]\n\n",key);
-                       break;
-               }
+                       printf("\nFound Key: [%012"llx"]\n\n",key);
+                       break;}
        }
   free(s);
 
index 19616441ad15e0338e688b02c6d8be84bb7f9ace..e12dd4472c4c6df0ff9a21bece88b037a199a59e 100644 (file)
@@ -16,7 +16,7 @@ my $gitbranch = `git rev-parse --abbrev-ref HEAD`;
 my $clean = 2;
 my @compiletime = gmtime();
 
-my $fullgitinfo = $gitbranch . '/' . $gitversion;
+my $fullgitinfo = 'iceman' . $gitbranch . '/' . $gitversion;
 
 $fullgitinfo =~ s/(\s)//g;
 
Impressum, Datenschutz