From 4a79e52c0b9530242d728d182ede1bfdb9625cdc Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 11 Sep 2014 22:33:43 +0200 Subject: [PATCH 01/78] Added piwis patch, first version of finding out the card size. Experimental. --- armsrc/mifarecmd.c | 34 ++-------------------------------- client/cmdhfmf.c | 15 ++++++++++----- 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 42dee56e..6be5b383 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -36,8 +36,6 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // clear trace iso14a_clear_trace(); -// iso14a_set_tracing(false); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); LED_A_ON(); @@ -78,10 +76,8 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); LED_B_OFF(); - // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); -// iso14a_set_tracing(TRUE); } @@ -126,15 +122,9 @@ void MifareUReadBlock(uint8_t arg0,uint8_t *datain) if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); LED_B_OFF(); - - - // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -153,7 +143,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) ui64Key = bytes_to_num(datain, 6); // variables - byte_t isOK; + byte_t isOK = 0; byte_t dataoutbuf[16 * 16]; uint8_t uid[10]; uint32_t cuid; @@ -163,7 +153,6 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // clear trace iso14a_clear_trace(); -// iso14a_set_tracing(false); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -195,7 +184,6 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); } - // ----------------------------- crypto1 destroy crypto1_destroy(pcs); @@ -208,7 +196,6 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); -// iso14a_set_tracing(TRUE); } @@ -225,7 +212,6 @@ void MifareUReadCard(uint8_t arg0, uint8_t *datain) // clear trace iso14a_clear_trace(); -// iso14a_set_tracing(false); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -291,7 +277,6 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // clear trace iso14a_clear_trace(); -// iso14a_set_tracing(false); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -337,11 +322,8 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); -// iso14a_set_tracing(TRUE); - } - void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) { // params @@ -358,7 +340,6 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) // clear trace iso14a_clear_trace(); - // iso14a_set_tracing(false); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -399,7 +380,6 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) // iso14a_set_tracing(TRUE); } - void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) { // params @@ -415,7 +395,6 @@ void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) // clear trace iso14a_clear_trace(); - // iso14a_set_tracing(false); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -449,15 +428,11 @@ void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) cmd_send(CMD_ACK,isOK,0,0,0,0); LED_B_OFF(); - // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); -// iso14a_set_tracing(TRUE); - } - // Return 1 if the nonce is invalid else return 0 int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ @@ -757,7 +732,6 @@ void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai Dbprintf("Debug level: %d", MF_DBGLEVEL); } - //----------------------------------------------------------------------------- // Work with emulator memory // @@ -766,14 +740,11 @@ void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) emlClearMem(); } - void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ emlSetMem(datain, arg0, arg1); // data, block num, blocks count } - void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - byte_t buf[48]; emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4) @@ -782,7 +753,6 @@ void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) LED_B_OFF(); } - //----------------------------------------------------------------------------- // Load a card into the emulator memory // diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 7fbcad24..eb3b4bf1 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -771,7 +771,7 @@ int CmdHF14AMfNested(const char *Cmd) uint8_t trgKeyType = 0; uint8_t SectorsCnt = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - uint8_t keyBlock[6*6]; + uint8_t keyBlock[13*6]; uint64_t key64 = 0; bool transferToEml = false; @@ -882,6 +882,14 @@ int CmdHF14AMfNested(const char *Cmd) num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 3 * 6)); num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 4 * 6)); num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6)); + num_to_bytes(0x4d3a99c351dd, 6, (uint8_t*)(keyBlock + 6 * 6)); + num_to_bytes(0x1a982c7e459a, 6, (uint8_t*)(keyBlock + 7 * 6)); + num_to_bytes(0xd3f7d3f7d3f7, 6, (uint8_t*)(keyBlock + 8 * 6)); + num_to_bytes(0x714c5c886e97, 6, (uint8_t*)(keyBlock + 9 * 6)); + num_to_bytes(0x587ee5f9350f, 6, (uint8_t*)(keyBlock + 10 * 6)); + num_to_bytes(0xa0478cc39091, 6, (uint8_t*)(keyBlock + 11 * 6)); + num_to_bytes(0x533cb6c723f6, 6, (uint8_t*)(keyBlock + 12 * 6)); + num_to_bytes(0x8fd0a4f256e9, 6, (uint8_t*)(keyBlock + 13 * 6)); PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); for (i = 0; i < SectorsCnt; i++) { @@ -1312,7 +1320,6 @@ int CmdHF14AMfDbg(const char *Cmd) return 0; } - int CmdHF14AMfEGet(const char *Cmd) { uint8_t blockNo = 0; @@ -1609,7 +1616,6 @@ int CmdHF14AMfCSetUID(const char *Cmd) return 0; } - int CmdHF14AMfCSetBlk(const char *Cmd) { uint8_t uid[8]; @@ -1735,7 +1741,7 @@ int CmdHF14AMfCLoad(const char *Cmd) } fclose(f); - if (blockNum != 16 * 4){ + if (blockNum != 16 * 4 && blockNum != 32 * 4 + 8 * 16){ PrintAndLog("File content error. There must be 64 blocks"); return 4; } @@ -1744,7 +1750,6 @@ int CmdHF14AMfCLoad(const char *Cmd) } } - int CmdHF14AMfCGetBlk(const char *Cmd) { uint8_t memBlock[16]; uint8_t blockNo = 0; From f38a152863a5eb289acb169c5a38b4b77e87956e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 11 Sep 2014 23:23:46 +0200 Subject: [PATCH 02/78] First check in. --- armsrc/LCD.c | 2 +- armsrc/Makefile | 15 +- armsrc/aes.c | 1168 ++++++++++++++++++++++++++++++++++ armsrc/aes.h | 30 + armsrc/appmain.c | 88 +-- armsrc/apps.h | 73 ++- armsrc/des.c | 383 +++++++++++ armsrc/des.h | 107 ++++ armsrc/desfire_crypto.c | 642 +++++++++++++++++++ armsrc/desfire_crypto.h | 15 + armsrc/desfire_key.c | 158 +++++ armsrc/desfire_key.h | 10 + armsrc/epa.c | 2 +- armsrc/fpgaloader.c | 3 +- armsrc/hitag2.c | 4 +- armsrc/iclass.c | 339 +++++++++- armsrc/iso14443.c | 4 +- armsrc/iso14443a.c | 34 +- armsrc/iso14443a.h | 3 +- armsrc/iso15693.c | 10 +- armsrc/legicrf.c | 6 +- armsrc/lfops.c | 82 ++- armsrc/mifarecmd.c | 94 ++- armsrc/mifarecmd.h | 7 +- armsrc/mifaredesfire.c | 568 +++++++++++++++++ armsrc/mifaredesfire.h | 16 + armsrc/mifaresniff.h | 6 +- armsrc/mifareutil.c | 91 ++- armsrc/mifareutil.h | 3 + armsrc/start.c | 2 +- armsrc/string.c | 5 + armsrc/string.h | 4 + armsrc/util.c | 42 +- armsrc/util.h | 6 +- client/Makefile | 24 +- client/cmdhf.c | 6 + client/cmdhf14a.c | 194 +++--- client/cmdhf14b.c | 3 +- client/cmdhf15.c | 2 +- client/cmdhfdes.c | 69 ++ client/cmdhfdes.h | 27 + client/cmdhfepa.c | 2 +- client/cmdhficlass.c | 326 +++++++--- client/cmdhficlass.h | 2 +- client/cmdhflegic.c | 1 - client/cmdhfmf.c | 151 ++++- client/cmdhfmf.h | 7 +- client/cmdhfmfdes.c | 436 +++++++++++++ client/cmdhfmfdes.h | 20 + client/cmdhfmfu.c | 1159 +++++++++++++++++++++++++++++++++ client/cmdhfmfu.h | 16 + client/cmdhw.c | 1 - client/cmdlf.c | 1 - client/cmdlfem4x.c | 91 ++- client/cmdlfhid.c | 1 - client/cmdlfhitag.c | 5 +- client/cmdlfio.c | 1 - client/cmdlfpcf7931.c | 1 - client/cmdlft55xx.c | 103 ++- client/cmdlfti.c | 1 - client/cmdmain.c | 2 +- client/cmdmain.h | 2 +- client/data.c | 1 - client/flash.c | 3 +- client/flasher.c | 2 +- client/loclass/cipher.c | 255 ++++++++ client/loclass/cipher.h | 31 + client/loclass/cipherutils.c | 273 ++++++++ client/loclass/cipherutils.h | 59 ++ client/loclass/des.c | 1014 +++++++++++++++++++++++++++++ client/loclass/des.h | 256 ++++++++ client/loclass/elite_crack.c | 656 +++++++++++++++++++ client/loclass/elite_crack.h | 108 ++++ client/loclass/fileutils.c | 65 ++ client/loclass/fileutils.h | 24 + client/loclass/ikeys.c | 878 +++++++++++++++++++++++++ client/loclass/ikeys.h | 32 + client/loclass/main.c | 96 +++ client/mifarehost.h | 1 - client/proxmark3.c | 38 -- client/proxmark3.h | 2 +- client/ui.c | 192 ++++++ client/ui.h | 4 + client/util.c | 34 + client/util.h | 3 + common/Makefile.common | 4 +- common/cmd.c | 2 +- common/cmd.h | 4 +- {include => common}/crc.h | 0 common/crc32.c | 35 + common/crc32.h | 15 + common/desfire.h | 177 ++++++ common/iso14443crc.c | 2 +- common/iso14443crc.h | 2 +- common/iso15693tools.c | 31 +- common/iso15693tools.h | 1 + common/legic_prng.c | 2 +- common/usb_cdc.c | 2 +- common/usb_cdc.h | 2 +- include/crc.h.old | 48 ++ include/mifare.h | 2 +- include/proxmark3.h | 3 +- include/usb_cmd.h | 17 + 103 files changed, 10544 insertions(+), 508 deletions(-) create mode 100644 armsrc/aes.c create mode 100644 armsrc/aes.h create mode 100644 armsrc/des.c create mode 100644 armsrc/des.h create mode 100644 armsrc/desfire_crypto.c create mode 100644 armsrc/desfire_crypto.h create mode 100644 armsrc/desfire_key.c create mode 100644 armsrc/desfire_key.h create mode 100644 armsrc/mifaredesfire.c create mode 100644 armsrc/mifaredesfire.h create mode 100644 client/cmdhfdes.c create mode 100644 client/cmdhfdes.h create mode 100644 client/cmdhfmfdes.c create mode 100644 client/cmdhfmfdes.h create mode 100644 client/cmdhfmfu.c create mode 100644 client/cmdhfmfu.h create mode 100644 client/loclass/cipher.c create mode 100644 client/loclass/cipher.h create mode 100644 client/loclass/cipherutils.c create mode 100644 client/loclass/cipherutils.h create mode 100644 client/loclass/des.c create mode 100644 client/loclass/des.h create mode 100644 client/loclass/elite_crack.c create mode 100644 client/loclass/elite_crack.h create mode 100644 client/loclass/fileutils.c create mode 100644 client/loclass/fileutils.h create mode 100644 client/loclass/ikeys.c create mode 100644 client/loclass/ikeys.h create mode 100644 client/loclass/main.c rename {include => common}/crc.h (100%) create mode 100644 common/crc32.c create mode 100644 common/crc32.h create mode 100644 common/desfire.h create mode 100644 include/crc.h.old diff --git a/armsrc/LCD.c b/armsrc/LCD.c index 65d64ac9..87be5e3a 100644 --- a/armsrc/LCD.c +++ b/armsrc/LCD.c @@ -6,7 +6,7 @@ // LCD code //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "LCD.h" #include "fonts.h" diff --git a/armsrc/Makefile b/armsrc/Makefile index e10c1001..ea19491a 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -10,7 +10,7 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line #in the next section to remove that particular feature from compilation -APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG +APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -fno-strict-aliasing #-DWITH_LCD #SRC_LCD = fonts.c LCD.c @@ -18,13 +18,15 @@ SRC_LF = lfops.c hitag2.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 +SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c +SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c THUMBSRC = start.c \ $(SRC_LCD) \ $(SRC_ISO15693) \ $(SRC_LF) \ - appmain.c printf.c \ + appmain.c \ + printf.c \ util.c \ string.c \ usb_cdc.c \ @@ -33,14 +35,15 @@ THUMBSRC = start.c \ # These are to be compiled in ARM mode ARMSRC = fpgaloader.c \ legicrf.c \ - iso14443crc.c \ - crc16.c \ $(SRC_ISO14443a) \ $(SRC_ISO14443b) \ $(SRC_CRAPTO1) \ + $(SRC_CRC) \ legic_prng.c \ iclass.c \ - crc.c + mifaredesfire.c \ + desfire_crypto.c \ + desfire_key.c # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS += -I. diff --git a/armsrc/aes.c b/armsrc/aes.c new file mode 100644 index 00000000..3df006bb --- /dev/null +++ b/armsrc/aes.c @@ -0,0 +1,1168 @@ +#include "stdio.h" +#include "aes.h" + +static const unsigned int Te0[256] = { + 0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL, + 0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL, + 0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL, + 0xe7fefe19UL, 0xb5d7d762UL, 0x4dababe6UL, 0xec76769aUL, + 0x8fcaca45UL, 0x1f82829dUL, 0x89c9c940UL, 0xfa7d7d87UL, + 0xeffafa15UL, 0xb25959ebUL, 0x8e4747c9UL, 0xfbf0f00bUL, + 0x41adadecUL, 0xb3d4d467UL, 0x5fa2a2fdUL, 0x45afafeaUL, + 0x239c9cbfUL, 0x53a4a4f7UL, 0xe4727296UL, 0x9bc0c05bUL, + 0x75b7b7c2UL, 0xe1fdfd1cUL, 0x3d9393aeUL, 0x4c26266aUL, + 0x6c36365aUL, 0x7e3f3f41UL, 0xf5f7f702UL, 0x83cccc4fUL, + 0x6834345cUL, 0x51a5a5f4UL, 0xd1e5e534UL, 0xf9f1f108UL, + 0xe2717193UL, 0xabd8d873UL, 0x62313153UL, 0x2a15153fUL, + 0x0804040cUL, 0x95c7c752UL, 0x46232365UL, 0x9dc3c35eUL, + 0x30181828UL, 0x379696a1UL, 0x0a05050fUL, 0x2f9a9ab5UL, + 0x0e070709UL, 0x24121236UL, 0x1b80809bUL, 0xdfe2e23dUL, + 0xcdebeb26UL, 0x4e272769UL, 0x7fb2b2cdUL, 0xea75759fUL, + 0x1209091bUL, 0x1d83839eUL, 0x582c2c74UL, 0x341a1a2eUL, + 0x361b1b2dUL, 0xdc6e6eb2UL, 0xb45a5aeeUL, 0x5ba0a0fbUL, + 0xa45252f6UL, 0x763b3b4dUL, 0xb7d6d661UL, 0x7db3b3ceUL, + 0x5229297bUL, 0xdde3e33eUL, 0x5e2f2f71UL, 0x13848497UL, + 0xa65353f5UL, 0xb9d1d168UL, 0x00000000UL, 0xc1eded2cUL, + 0x40202060UL, 0xe3fcfc1fUL, 0x79b1b1c8UL, 0xb65b5bedUL, + 0xd46a6abeUL, 0x8dcbcb46UL, 0x67bebed9UL, 0x7239394bUL, + 0x944a4adeUL, 0x984c4cd4UL, 0xb05858e8UL, 0x85cfcf4aUL, + 0xbbd0d06bUL, 0xc5efef2aUL, 0x4faaaae5UL, 0xedfbfb16UL, + 0x864343c5UL, 0x9a4d4dd7UL, 0x66333355UL, 0x11858594UL, + 0x8a4545cfUL, 0xe9f9f910UL, 0x04020206UL, 0xfe7f7f81UL, + 0xa05050f0UL, 0x783c3c44UL, 0x259f9fbaUL, 0x4ba8a8e3UL, + 0xa25151f3UL, 0x5da3a3feUL, 0x804040c0UL, 0x058f8f8aUL, + 0x3f9292adUL, 0x219d9dbcUL, 0x70383848UL, 0xf1f5f504UL, + 0x63bcbcdfUL, 0x77b6b6c1UL, 0xafdada75UL, 0x42212163UL, + 0x20101030UL, 0xe5ffff1aUL, 0xfdf3f30eUL, 0xbfd2d26dUL, + 0x81cdcd4cUL, 0x180c0c14UL, 0x26131335UL, 0xc3ecec2fUL, + 0xbe5f5fe1UL, 0x359797a2UL, 0x884444ccUL, 0x2e171739UL, + 0x93c4c457UL, 0x55a7a7f2UL, 0xfc7e7e82UL, 0x7a3d3d47UL, + 0xc86464acUL, 0xba5d5de7UL, 0x3219192bUL, 0xe6737395UL, + 0xc06060a0UL, 0x19818198UL, 0x9e4f4fd1UL, 0xa3dcdc7fUL, + 0x44222266UL, 0x542a2a7eUL, 0x3b9090abUL, 0x0b888883UL, + 0x8c4646caUL, 0xc7eeee29UL, 0x6bb8b8d3UL, 0x2814143cUL, + 0xa7dede79UL, 0xbc5e5ee2UL, 0x160b0b1dUL, 0xaddbdb76UL, + 0xdbe0e03bUL, 0x64323256UL, 0x743a3a4eUL, 0x140a0a1eUL, + 0x924949dbUL, 0x0c06060aUL, 0x4824246cUL, 0xb85c5ce4UL, + 0x9fc2c25dUL, 0xbdd3d36eUL, 0x43acacefUL, 0xc46262a6UL, + 0x399191a8UL, 0x319595a4UL, 0xd3e4e437UL, 0xf279798bUL, + 0xd5e7e732UL, 0x8bc8c843UL, 0x6e373759UL, 0xda6d6db7UL, + 0x018d8d8cUL, 0xb1d5d564UL, 0x9c4e4ed2UL, 0x49a9a9e0UL, + 0xd86c6cb4UL, 0xac5656faUL, 0xf3f4f407UL, 0xcfeaea25UL, + 0xca6565afUL, 0xf47a7a8eUL, 0x47aeaee9UL, 0x10080818UL, + 0x6fbabad5UL, 0xf0787888UL, 0x4a25256fUL, 0x5c2e2e72UL, + 0x381c1c24UL, 0x57a6a6f1UL, 0x73b4b4c7UL, 0x97c6c651UL, + 0xcbe8e823UL, 0xa1dddd7cUL, 0xe874749cUL, 0x3e1f1f21UL, + 0x964b4bddUL, 0x61bdbddcUL, 0x0d8b8b86UL, 0x0f8a8a85UL, + 0xe0707090UL, 0x7c3e3e42UL, 0x71b5b5c4UL, 0xcc6666aaUL, + 0x904848d8UL, 0x06030305UL, 0xf7f6f601UL, 0x1c0e0e12UL, + 0xc26161a3UL, 0x6a35355fUL, 0xae5757f9UL, 0x69b9b9d0UL, + 0x17868691UL, 0x99c1c158UL, 0x3a1d1d27UL, 0x279e9eb9UL, + 0xd9e1e138UL, 0xebf8f813UL, 0x2b9898b3UL, 0x22111133UL, + 0xd26969bbUL, 0xa9d9d970UL, 0x078e8e89UL, 0x339494a7UL, + 0x2d9b9bb6UL, 0x3c1e1e22UL, 0x15878792UL, 0xc9e9e920UL, + 0x87cece49UL, 0xaa5555ffUL, 0x50282878UL, 0xa5dfdf7aUL, + 0x038c8c8fUL, 0x59a1a1f8UL, 0x09898980UL, 0x1a0d0d17UL, + 0x65bfbfdaUL, 0xd7e6e631UL, 0x844242c6UL, 0xd06868b8UL, + 0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL, + 0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL, +}; +static const unsigned int Te1[256] = { + 0xa5c66363UL, 0x84f87c7cUL, 0x99ee7777UL, 0x8df67b7bUL, + 0x0dfff2f2UL, 0xbdd66b6bUL, 0xb1de6f6fUL, 0x5491c5c5UL, + 0x50603030UL, 0x03020101UL, 0xa9ce6767UL, 0x7d562b2bUL, + 0x19e7fefeUL, 0x62b5d7d7UL, 0xe64dababUL, 0x9aec7676UL, + 0x458fcacaUL, 0x9d1f8282UL, 0x4089c9c9UL, 0x87fa7d7dUL, + 0x15effafaUL, 0xebb25959UL, 0xc98e4747UL, 0x0bfbf0f0UL, + 0xec41adadUL, 0x67b3d4d4UL, 0xfd5fa2a2UL, 0xea45afafUL, + 0xbf239c9cUL, 0xf753a4a4UL, 0x96e47272UL, 0x5b9bc0c0UL, + 0xc275b7b7UL, 0x1ce1fdfdUL, 0xae3d9393UL, 0x6a4c2626UL, + 0x5a6c3636UL, 0x417e3f3fUL, 0x02f5f7f7UL, 0x4f83ccccUL, + 0x5c683434UL, 0xf451a5a5UL, 0x34d1e5e5UL, 0x08f9f1f1UL, + 0x93e27171UL, 0x73abd8d8UL, 0x53623131UL, 0x3f2a1515UL, + 0x0c080404UL, 0x5295c7c7UL, 0x65462323UL, 0x5e9dc3c3UL, + 0x28301818UL, 0xa1379696UL, 0x0f0a0505UL, 0xb52f9a9aUL, + 0x090e0707UL, 0x36241212UL, 0x9b1b8080UL, 0x3ddfe2e2UL, + 0x26cdebebUL, 0x694e2727UL, 0xcd7fb2b2UL, 0x9fea7575UL, + 0x1b120909UL, 0x9e1d8383UL, 0x74582c2cUL, 0x2e341a1aUL, + 0x2d361b1bUL, 0xb2dc6e6eUL, 0xeeb45a5aUL, 0xfb5ba0a0UL, + 0xf6a45252UL, 0x4d763b3bUL, 0x61b7d6d6UL, 0xce7db3b3UL, + 0x7b522929UL, 0x3edde3e3UL, 0x715e2f2fUL, 0x97138484UL, + 0xf5a65353UL, 0x68b9d1d1UL, 0x00000000UL, 0x2cc1ededUL, + 0x60402020UL, 0x1fe3fcfcUL, 0xc879b1b1UL, 0xedb65b5bUL, + 0xbed46a6aUL, 0x468dcbcbUL, 0xd967bebeUL, 0x4b723939UL, + 0xde944a4aUL, 0xd4984c4cUL, 0xe8b05858UL, 0x4a85cfcfUL, + 0x6bbbd0d0UL, 0x2ac5efefUL, 0xe54faaaaUL, 0x16edfbfbUL, + 0xc5864343UL, 0xd79a4d4dUL, 0x55663333UL, 0x94118585UL, + 0xcf8a4545UL, 0x10e9f9f9UL, 0x06040202UL, 0x81fe7f7fUL, + 0xf0a05050UL, 0x44783c3cUL, 0xba259f9fUL, 0xe34ba8a8UL, + 0xf3a25151UL, 0xfe5da3a3UL, 0xc0804040UL, 0x8a058f8fUL, + 0xad3f9292UL, 0xbc219d9dUL, 0x48703838UL, 0x04f1f5f5UL, + 0xdf63bcbcUL, 0xc177b6b6UL, 0x75afdadaUL, 0x63422121UL, + 0x30201010UL, 0x1ae5ffffUL, 0x0efdf3f3UL, 0x6dbfd2d2UL, + 0x4c81cdcdUL, 0x14180c0cUL, 0x35261313UL, 0x2fc3ececUL, + 0xe1be5f5fUL, 0xa2359797UL, 0xcc884444UL, 0x392e1717UL, + 0x5793c4c4UL, 0xf255a7a7UL, 0x82fc7e7eUL, 0x477a3d3dUL, + 0xacc86464UL, 0xe7ba5d5dUL, 0x2b321919UL, 0x95e67373UL, + 0xa0c06060UL, 0x98198181UL, 0xd19e4f4fUL, 0x7fa3dcdcUL, + 0x66442222UL, 0x7e542a2aUL, 0xab3b9090UL, 0x830b8888UL, + 0xca8c4646UL, 0x29c7eeeeUL, 0xd36bb8b8UL, 0x3c281414UL, + 0x79a7dedeUL, 0xe2bc5e5eUL, 0x1d160b0bUL, 0x76addbdbUL, + 0x3bdbe0e0UL, 0x56643232UL, 0x4e743a3aUL, 0x1e140a0aUL, + 0xdb924949UL, 0x0a0c0606UL, 0x6c482424UL, 0xe4b85c5cUL, + 0x5d9fc2c2UL, 0x6ebdd3d3UL, 0xef43acacUL, 0xa6c46262UL, + 0xa8399191UL, 0xa4319595UL, 0x37d3e4e4UL, 0x8bf27979UL, + 0x32d5e7e7UL, 0x438bc8c8UL, 0x596e3737UL, 0xb7da6d6dUL, + 0x8c018d8dUL, 0x64b1d5d5UL, 0xd29c4e4eUL, 0xe049a9a9UL, + 0xb4d86c6cUL, 0xfaac5656UL, 0x07f3f4f4UL, 0x25cfeaeaUL, + 0xafca6565UL, 0x8ef47a7aUL, 0xe947aeaeUL, 0x18100808UL, + 0xd56fbabaUL, 0x88f07878UL, 0x6f4a2525UL, 0x725c2e2eUL, + 0x24381c1cUL, 0xf157a6a6UL, 0xc773b4b4UL, 0x5197c6c6UL, + 0x23cbe8e8UL, 0x7ca1ddddUL, 0x9ce87474UL, 0x213e1f1fUL, + 0xdd964b4bUL, 0xdc61bdbdUL, 0x860d8b8bUL, 0x850f8a8aUL, + 0x90e07070UL, 0x427c3e3eUL, 0xc471b5b5UL, 0xaacc6666UL, + 0xd8904848UL, 0x05060303UL, 0x01f7f6f6UL, 0x121c0e0eUL, + 0xa3c26161UL, 0x5f6a3535UL, 0xf9ae5757UL, 0xd069b9b9UL, + 0x91178686UL, 0x5899c1c1UL, 0x273a1d1dUL, 0xb9279e9eUL, + 0x38d9e1e1UL, 0x13ebf8f8UL, 0xb32b9898UL, 0x33221111UL, + 0xbbd26969UL, 0x70a9d9d9UL, 0x89078e8eUL, 0xa7339494UL, + 0xb62d9b9bUL, 0x223c1e1eUL, 0x92158787UL, 0x20c9e9e9UL, + 0x4987ceceUL, 0xffaa5555UL, 0x78502828UL, 0x7aa5dfdfUL, + 0x8f038c8cUL, 0xf859a1a1UL, 0x80098989UL, 0x171a0d0dUL, + 0xda65bfbfUL, 0x31d7e6e6UL, 0xc6844242UL, 0xb8d06868UL, + 0xc3824141UL, 0xb0299999UL, 0x775a2d2dUL, 0x111e0f0fUL, + 0xcb7bb0b0UL, 0xfca85454UL, 0xd66dbbbbUL, 0x3a2c1616UL, +}; +static const unsigned int Te2[256] = { + 0x63a5c663UL, 0x7c84f87cUL, 0x7799ee77UL, 0x7b8df67bUL, + 0xf20dfff2UL, 0x6bbdd66bUL, 0x6fb1de6fUL, 0xc55491c5UL, + 0x30506030UL, 0x01030201UL, 0x67a9ce67UL, 0x2b7d562bUL, + 0xfe19e7feUL, 0xd762b5d7UL, 0xabe64dabUL, 0x769aec76UL, + 0xca458fcaUL, 0x829d1f82UL, 0xc94089c9UL, 0x7d87fa7dUL, + 0xfa15effaUL, 0x59ebb259UL, 0x47c98e47UL, 0xf00bfbf0UL, + 0xadec41adUL, 0xd467b3d4UL, 0xa2fd5fa2UL, 0xafea45afUL, + 0x9cbf239cUL, 0xa4f753a4UL, 0x7296e472UL, 0xc05b9bc0UL, + 0xb7c275b7UL, 0xfd1ce1fdUL, 0x93ae3d93UL, 0x266a4c26UL, + 0x365a6c36UL, 0x3f417e3fUL, 0xf702f5f7UL, 0xcc4f83ccUL, + 0x345c6834UL, 0xa5f451a5UL, 0xe534d1e5UL, 0xf108f9f1UL, + 0x7193e271UL, 0xd873abd8UL, 0x31536231UL, 0x153f2a15UL, + 0x040c0804UL, 0xc75295c7UL, 0x23654623UL, 0xc35e9dc3UL, + 0x18283018UL, 0x96a13796UL, 0x050f0a05UL, 0x9ab52f9aUL, + 0x07090e07UL, 0x12362412UL, 0x809b1b80UL, 0xe23ddfe2UL, + 0xeb26cdebUL, 0x27694e27UL, 0xb2cd7fb2UL, 0x759fea75UL, + 0x091b1209UL, 0x839e1d83UL, 0x2c74582cUL, 0x1a2e341aUL, + 0x1b2d361bUL, 0x6eb2dc6eUL, 0x5aeeb45aUL, 0xa0fb5ba0UL, + 0x52f6a452UL, 0x3b4d763bUL, 0xd661b7d6UL, 0xb3ce7db3UL, + 0x297b5229UL, 0xe33edde3UL, 0x2f715e2fUL, 0x84971384UL, + 0x53f5a653UL, 0xd168b9d1UL, 0x00000000UL, 0xed2cc1edUL, + 0x20604020UL, 0xfc1fe3fcUL, 0xb1c879b1UL, 0x5bedb65bUL, + 0x6abed46aUL, 0xcb468dcbUL, 0xbed967beUL, 0x394b7239UL, + 0x4ade944aUL, 0x4cd4984cUL, 0x58e8b058UL, 0xcf4a85cfUL, + 0xd06bbbd0UL, 0xef2ac5efUL, 0xaae54faaUL, 0xfb16edfbUL, + 0x43c58643UL, 0x4dd79a4dUL, 0x33556633UL, 0x85941185UL, + 0x45cf8a45UL, 0xf910e9f9UL, 0x02060402UL, 0x7f81fe7fUL, + 0x50f0a050UL, 0x3c44783cUL, 0x9fba259fUL, 0xa8e34ba8UL, + 0x51f3a251UL, 0xa3fe5da3UL, 0x40c08040UL, 0x8f8a058fUL, + 0x92ad3f92UL, 0x9dbc219dUL, 0x38487038UL, 0xf504f1f5UL, + 0xbcdf63bcUL, 0xb6c177b6UL, 0xda75afdaUL, 0x21634221UL, + 0x10302010UL, 0xff1ae5ffUL, 0xf30efdf3UL, 0xd26dbfd2UL, + 0xcd4c81cdUL, 0x0c14180cUL, 0x13352613UL, 0xec2fc3ecUL, + 0x5fe1be5fUL, 0x97a23597UL, 0x44cc8844UL, 0x17392e17UL, + 0xc45793c4UL, 0xa7f255a7UL, 0x7e82fc7eUL, 0x3d477a3dUL, + 0x64acc864UL, 0x5de7ba5dUL, 0x192b3219UL, 0x7395e673UL, + 0x60a0c060UL, 0x81981981UL, 0x4fd19e4fUL, 0xdc7fa3dcUL, + 0x22664422UL, 0x2a7e542aUL, 0x90ab3b90UL, 0x88830b88UL, + 0x46ca8c46UL, 0xee29c7eeUL, 0xb8d36bb8UL, 0x143c2814UL, + 0xde79a7deUL, 0x5ee2bc5eUL, 0x0b1d160bUL, 0xdb76addbUL, + 0xe03bdbe0UL, 0x32566432UL, 0x3a4e743aUL, 0x0a1e140aUL, + 0x49db9249UL, 0x060a0c06UL, 0x246c4824UL, 0x5ce4b85cUL, + 0xc25d9fc2UL, 0xd36ebdd3UL, 0xacef43acUL, 0x62a6c462UL, + 0x91a83991UL, 0x95a43195UL, 0xe437d3e4UL, 0x798bf279UL, + 0xe732d5e7UL, 0xc8438bc8UL, 0x37596e37UL, 0x6db7da6dUL, + 0x8d8c018dUL, 0xd564b1d5UL, 0x4ed29c4eUL, 0xa9e049a9UL, + 0x6cb4d86cUL, 0x56faac56UL, 0xf407f3f4UL, 0xea25cfeaUL, + 0x65afca65UL, 0x7a8ef47aUL, 0xaee947aeUL, 0x08181008UL, + 0xbad56fbaUL, 0x7888f078UL, 0x256f4a25UL, 0x2e725c2eUL, + 0x1c24381cUL, 0xa6f157a6UL, 0xb4c773b4UL, 0xc65197c6UL, + 0xe823cbe8UL, 0xdd7ca1ddUL, 0x749ce874UL, 0x1f213e1fUL, + 0x4bdd964bUL, 0xbddc61bdUL, 0x8b860d8bUL, 0x8a850f8aUL, + 0x7090e070UL, 0x3e427c3eUL, 0xb5c471b5UL, 0x66aacc66UL, + 0x48d89048UL, 0x03050603UL, 0xf601f7f6UL, 0x0e121c0eUL, + 0x61a3c261UL, 0x355f6a35UL, 0x57f9ae57UL, 0xb9d069b9UL, + 0x86911786UL, 0xc15899c1UL, 0x1d273a1dUL, 0x9eb9279eUL, + 0xe138d9e1UL, 0xf813ebf8UL, 0x98b32b98UL, 0x11332211UL, + 0x69bbd269UL, 0xd970a9d9UL, 0x8e89078eUL, 0x94a73394UL, + 0x9bb62d9bUL, 0x1e223c1eUL, 0x87921587UL, 0xe920c9e9UL, + 0xce4987ceUL, 0x55ffaa55UL, 0x28785028UL, 0xdf7aa5dfUL, + 0x8c8f038cUL, 0xa1f859a1UL, 0x89800989UL, 0x0d171a0dUL, + 0xbfda65bfUL, 0xe631d7e6UL, 0x42c68442UL, 0x68b8d068UL, + 0x41c38241UL, 0x99b02999UL, 0x2d775a2dUL, 0x0f111e0fUL, + 0xb0cb7bb0UL, 0x54fca854UL, 0xbbd66dbbUL, 0x163a2c16UL, +}; +static const unsigned int Te3[256] = { + 0x6363a5c6UL, 0x7c7c84f8UL, 0x777799eeUL, 0x7b7b8df6UL, + 0xf2f20dffUL, 0x6b6bbdd6UL, 0x6f6fb1deUL, 0xc5c55491UL, + 0x30305060UL, 0x01010302UL, 0x6767a9ceUL, 0x2b2b7d56UL, + 0xfefe19e7UL, 0xd7d762b5UL, 0xababe64dUL, 0x76769aecUL, + 0xcaca458fUL, 0x82829d1fUL, 0xc9c94089UL, 0x7d7d87faUL, + 0xfafa15efUL, 0x5959ebb2UL, 0x4747c98eUL, 0xf0f00bfbUL, + 0xadadec41UL, 0xd4d467b3UL, 0xa2a2fd5fUL, 0xafafea45UL, + 0x9c9cbf23UL, 0xa4a4f753UL, 0x727296e4UL, 0xc0c05b9bUL, + 0xb7b7c275UL, 0xfdfd1ce1UL, 0x9393ae3dUL, 0x26266a4cUL, + 0x36365a6cUL, 0x3f3f417eUL, 0xf7f702f5UL, 0xcccc4f83UL, + 0x34345c68UL, 0xa5a5f451UL, 0xe5e534d1UL, 0xf1f108f9UL, + 0x717193e2UL, 0xd8d873abUL, 0x31315362UL, 0x15153f2aUL, + 0x04040c08UL, 0xc7c75295UL, 0x23236546UL, 0xc3c35e9dUL, + 0x18182830UL, 0x9696a137UL, 0x05050f0aUL, 0x9a9ab52fUL, + 0x0707090eUL, 0x12123624UL, 0x80809b1bUL, 0xe2e23ddfUL, + 0xebeb26cdUL, 0x2727694eUL, 0xb2b2cd7fUL, 0x75759feaUL, + 0x09091b12UL, 0x83839e1dUL, 0x2c2c7458UL, 0x1a1a2e34UL, + 0x1b1b2d36UL, 0x6e6eb2dcUL, 0x5a5aeeb4UL, 0xa0a0fb5bUL, + 0x5252f6a4UL, 0x3b3b4d76UL, 0xd6d661b7UL, 0xb3b3ce7dUL, + 0x29297b52UL, 0xe3e33eddUL, 0x2f2f715eUL, 0x84849713UL, + 0x5353f5a6UL, 0xd1d168b9UL, 0x00000000UL, 0xeded2cc1UL, + 0x20206040UL, 0xfcfc1fe3UL, 0xb1b1c879UL, 0x5b5bedb6UL, + 0x6a6abed4UL, 0xcbcb468dUL, 0xbebed967UL, 0x39394b72UL, + 0x4a4ade94UL, 0x4c4cd498UL, 0x5858e8b0UL, 0xcfcf4a85UL, + 0xd0d06bbbUL, 0xefef2ac5UL, 0xaaaae54fUL, 0xfbfb16edUL, + 0x4343c586UL, 0x4d4dd79aUL, 0x33335566UL, 0x85859411UL, + 0x4545cf8aUL, 0xf9f910e9UL, 0x02020604UL, 0x7f7f81feUL, + 0x5050f0a0UL, 0x3c3c4478UL, 0x9f9fba25UL, 0xa8a8e34bUL, + 0x5151f3a2UL, 0xa3a3fe5dUL, 0x4040c080UL, 0x8f8f8a05UL, + 0x9292ad3fUL, 0x9d9dbc21UL, 0x38384870UL, 0xf5f504f1UL, + 0xbcbcdf63UL, 0xb6b6c177UL, 0xdada75afUL, 0x21216342UL, + 0x10103020UL, 0xffff1ae5UL, 0xf3f30efdUL, 0xd2d26dbfUL, + 0xcdcd4c81UL, 0x0c0c1418UL, 0x13133526UL, 0xecec2fc3UL, + 0x5f5fe1beUL, 0x9797a235UL, 0x4444cc88UL, 0x1717392eUL, + 0xc4c45793UL, 0xa7a7f255UL, 0x7e7e82fcUL, 0x3d3d477aUL, + 0x6464acc8UL, 0x5d5de7baUL, 0x19192b32UL, 0x737395e6UL, + 0x6060a0c0UL, 0x81819819UL, 0x4f4fd19eUL, 0xdcdc7fa3UL, + 0x22226644UL, 0x2a2a7e54UL, 0x9090ab3bUL, 0x8888830bUL, + 0x4646ca8cUL, 0xeeee29c7UL, 0xb8b8d36bUL, 0x14143c28UL, + 0xdede79a7UL, 0x5e5ee2bcUL, 0x0b0b1d16UL, 0xdbdb76adUL, + 0xe0e03bdbUL, 0x32325664UL, 0x3a3a4e74UL, 0x0a0a1e14UL, + 0x4949db92UL, 0x06060a0cUL, 0x24246c48UL, 0x5c5ce4b8UL, + 0xc2c25d9fUL, 0xd3d36ebdUL, 0xacacef43UL, 0x6262a6c4UL, + 0x9191a839UL, 0x9595a431UL, 0xe4e437d3UL, 0x79798bf2UL, + 0xe7e732d5UL, 0xc8c8438bUL, 0x3737596eUL, 0x6d6db7daUL, + 0x8d8d8c01UL, 0xd5d564b1UL, 0x4e4ed29cUL, 0xa9a9e049UL, + 0x6c6cb4d8UL, 0x5656faacUL, 0xf4f407f3UL, 0xeaea25cfUL, + 0x6565afcaUL, 0x7a7a8ef4UL, 0xaeaee947UL, 0x08081810UL, + 0xbabad56fUL, 0x787888f0UL, 0x25256f4aUL, 0x2e2e725cUL, + 0x1c1c2438UL, 0xa6a6f157UL, 0xb4b4c773UL, 0xc6c65197UL, + 0xe8e823cbUL, 0xdddd7ca1UL, 0x74749ce8UL, 0x1f1f213eUL, + 0x4b4bdd96UL, 0xbdbddc61UL, 0x8b8b860dUL, 0x8a8a850fUL, + 0x707090e0UL, 0x3e3e427cUL, 0xb5b5c471UL, 0x6666aaccUL, + 0x4848d890UL, 0x03030506UL, 0xf6f601f7UL, 0x0e0e121cUL, + 0x6161a3c2UL, 0x35355f6aUL, 0x5757f9aeUL, 0xb9b9d069UL, + 0x86869117UL, 0xc1c15899UL, 0x1d1d273aUL, 0x9e9eb927UL, + 0xe1e138d9UL, 0xf8f813ebUL, 0x9898b32bUL, 0x11113322UL, + 0x6969bbd2UL, 0xd9d970a9UL, 0x8e8e8907UL, 0x9494a733UL, + 0x9b9bb62dUL, 0x1e1e223cUL, 0x87879215UL, 0xe9e920c9UL, + 0xcece4987UL, 0x5555ffaaUL, 0x28287850UL, 0xdfdf7aa5UL, + 0x8c8c8f03UL, 0xa1a1f859UL, 0x89898009UL, 0x0d0d171aUL, + 0xbfbfda65UL, 0xe6e631d7UL, 0x4242c684UL, 0x6868b8d0UL, + 0x4141c382UL, 0x9999b029UL, 0x2d2d775aUL, 0x0f0f111eUL, + 0xb0b0cb7bUL, 0x5454fca8UL, 0xbbbbd66dUL, 0x16163a2cUL, +}; +static const unsigned int Te4[256] = { + 0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL, + 0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL, + 0x30303030UL, 0x01010101UL, 0x67676767UL, 0x2b2b2b2bUL, + 0xfefefefeUL, 0xd7d7d7d7UL, 0xababababUL, 0x76767676UL, + 0xcacacacaUL, 0x82828282UL, 0xc9c9c9c9UL, 0x7d7d7d7dUL, + 0xfafafafaUL, 0x59595959UL, 0x47474747UL, 0xf0f0f0f0UL, + 0xadadadadUL, 0xd4d4d4d4UL, 0xa2a2a2a2UL, 0xafafafafUL, + 0x9c9c9c9cUL, 0xa4a4a4a4UL, 0x72727272UL, 0xc0c0c0c0UL, + 0xb7b7b7b7UL, 0xfdfdfdfdUL, 0x93939393UL, 0x26262626UL, + 0x36363636UL, 0x3f3f3f3fUL, 0xf7f7f7f7UL, 0xccccccccUL, + 0x34343434UL, 0xa5a5a5a5UL, 0xe5e5e5e5UL, 0xf1f1f1f1UL, + 0x71717171UL, 0xd8d8d8d8UL, 0x31313131UL, 0x15151515UL, + 0x04040404UL, 0xc7c7c7c7UL, 0x23232323UL, 0xc3c3c3c3UL, + 0x18181818UL, 0x96969696UL, 0x05050505UL, 0x9a9a9a9aUL, + 0x07070707UL, 0x12121212UL, 0x80808080UL, 0xe2e2e2e2UL, + 0xebebebebUL, 0x27272727UL, 0xb2b2b2b2UL, 0x75757575UL, + 0x09090909UL, 0x83838383UL, 0x2c2c2c2cUL, 0x1a1a1a1aUL, + 0x1b1b1b1bUL, 0x6e6e6e6eUL, 0x5a5a5a5aUL, 0xa0a0a0a0UL, + 0x52525252UL, 0x3b3b3b3bUL, 0xd6d6d6d6UL, 0xb3b3b3b3UL, + 0x29292929UL, 0xe3e3e3e3UL, 0x2f2f2f2fUL, 0x84848484UL, + 0x53535353UL, 0xd1d1d1d1UL, 0x00000000UL, 0xededededUL, + 0x20202020UL, 0xfcfcfcfcUL, 0xb1b1b1b1UL, 0x5b5b5b5bUL, + 0x6a6a6a6aUL, 0xcbcbcbcbUL, 0xbebebebeUL, 0x39393939UL, + 0x4a4a4a4aUL, 0x4c4c4c4cUL, 0x58585858UL, 0xcfcfcfcfUL, + 0xd0d0d0d0UL, 0xefefefefUL, 0xaaaaaaaaUL, 0xfbfbfbfbUL, + 0x43434343UL, 0x4d4d4d4dUL, 0x33333333UL, 0x85858585UL, + 0x45454545UL, 0xf9f9f9f9UL, 0x02020202UL, 0x7f7f7f7fUL, + 0x50505050UL, 0x3c3c3c3cUL, 0x9f9f9f9fUL, 0xa8a8a8a8UL, + 0x51515151UL, 0xa3a3a3a3UL, 0x40404040UL, 0x8f8f8f8fUL, + 0x92929292UL, 0x9d9d9d9dUL, 0x38383838UL, 0xf5f5f5f5UL, + 0xbcbcbcbcUL, 0xb6b6b6b6UL, 0xdadadadaUL, 0x21212121UL, + 0x10101010UL, 0xffffffffUL, 0xf3f3f3f3UL, 0xd2d2d2d2UL, + 0xcdcdcdcdUL, 0x0c0c0c0cUL, 0x13131313UL, 0xececececUL, + 0x5f5f5f5fUL, 0x97979797UL, 0x44444444UL, 0x17171717UL, + 0xc4c4c4c4UL, 0xa7a7a7a7UL, 0x7e7e7e7eUL, 0x3d3d3d3dUL, + 0x64646464UL, 0x5d5d5d5dUL, 0x19191919UL, 0x73737373UL, + 0x60606060UL, 0x81818181UL, 0x4f4f4f4fUL, 0xdcdcdcdcUL, + 0x22222222UL, 0x2a2a2a2aUL, 0x90909090UL, 0x88888888UL, + 0x46464646UL, 0xeeeeeeeeUL, 0xb8b8b8b8UL, 0x14141414UL, + 0xdedededeUL, 0x5e5e5e5eUL, 0x0b0b0b0bUL, 0xdbdbdbdbUL, + 0xe0e0e0e0UL, 0x32323232UL, 0x3a3a3a3aUL, 0x0a0a0a0aUL, + 0x49494949UL, 0x06060606UL, 0x24242424UL, 0x5c5c5c5cUL, + 0xc2c2c2c2UL, 0xd3d3d3d3UL, 0xacacacacUL, 0x62626262UL, + 0x91919191UL, 0x95959595UL, 0xe4e4e4e4UL, 0x79797979UL, + 0xe7e7e7e7UL, 0xc8c8c8c8UL, 0x37373737UL, 0x6d6d6d6dUL, + 0x8d8d8d8dUL, 0xd5d5d5d5UL, 0x4e4e4e4eUL, 0xa9a9a9a9UL, + 0x6c6c6c6cUL, 0x56565656UL, 0xf4f4f4f4UL, 0xeaeaeaeaUL, + 0x65656565UL, 0x7a7a7a7aUL, 0xaeaeaeaeUL, 0x08080808UL, + 0xbabababaUL, 0x78787878UL, 0x25252525UL, 0x2e2e2e2eUL, + 0x1c1c1c1cUL, 0xa6a6a6a6UL, 0xb4b4b4b4UL, 0xc6c6c6c6UL, + 0xe8e8e8e8UL, 0xddddddddUL, 0x74747474UL, 0x1f1f1f1fUL, + 0x4b4b4b4bUL, 0xbdbdbdbdUL, 0x8b8b8b8bUL, 0x8a8a8a8aUL, + 0x70707070UL, 0x3e3e3e3eUL, 0xb5b5b5b5UL, 0x66666666UL, + 0x48484848UL, 0x03030303UL, 0xf6f6f6f6UL, 0x0e0e0e0eUL, + 0x61616161UL, 0x35353535UL, 0x57575757UL, 0xb9b9b9b9UL, + 0x86868686UL, 0xc1c1c1c1UL, 0x1d1d1d1dUL, 0x9e9e9e9eUL, + 0xe1e1e1e1UL, 0xf8f8f8f8UL, 0x98989898UL, 0x11111111UL, + 0x69696969UL, 0xd9d9d9d9UL, 0x8e8e8e8eUL, 0x94949494UL, + 0x9b9b9b9bUL, 0x1e1e1e1eUL, 0x87878787UL, 0xe9e9e9e9UL, + 0xcecececeUL, 0x55555555UL, 0x28282828UL, 0xdfdfdfdfUL, + 0x8c8c8c8cUL, 0xa1a1a1a1UL, 0x89898989UL, 0x0d0d0d0dUL, + 0xbfbfbfbfUL, 0xe6e6e6e6UL, 0x42424242UL, 0x68686868UL, + 0x41414141UL, 0x99999999UL, 0x2d2d2d2dUL, 0x0f0f0f0fUL, + 0xb0b0b0b0UL, 0x54545454UL, 0xbbbbbbbbUL, 0x16161616UL, +}; +static const unsigned int Td0[256] = { + 0x51f4a750UL, 0x7e416553UL, 0x1a17a4c3UL, 0x3a275e96UL, + 0x3bab6bcbUL, 0x1f9d45f1UL, 0xacfa58abUL, 0x4be30393UL, + 0x2030fa55UL, 0xad766df6UL, 0x88cc7691UL, 0xf5024c25UL, + 0x4fe5d7fcUL, 0xc52acbd7UL, 0x26354480UL, 0xb562a38fUL, + 0xdeb15a49UL, 0x25ba1b67UL, 0x45ea0e98UL, 0x5dfec0e1UL, + 0xc32f7502UL, 0x814cf012UL, 0x8d4697a3UL, 0x6bd3f9c6UL, + 0x038f5fe7UL, 0x15929c95UL, 0xbf6d7aebUL, 0x955259daUL, + 0xd4be832dUL, 0x587421d3UL, 0x49e06929UL, 0x8ec9c844UL, + 0x75c2896aUL, 0xf48e7978UL, 0x99583e6bUL, 0x27b971ddUL, + 0xbee14fb6UL, 0xf088ad17UL, 0xc920ac66UL, 0x7dce3ab4UL, + 0x63df4a18UL, 0xe51a3182UL, 0x97513360UL, 0x62537f45UL, + 0xb16477e0UL, 0xbb6bae84UL, 0xfe81a01cUL, 0xf9082b94UL, + 0x70486858UL, 0x8f45fd19UL, 0x94de6c87UL, 0x527bf8b7UL, + 0xab73d323UL, 0x724b02e2UL, 0xe31f8f57UL, 0x6655ab2aUL, + 0xb2eb2807UL, 0x2fb5c203UL, 0x86c57b9aUL, 0xd33708a5UL, + 0x302887f2UL, 0x23bfa5b2UL, 0x02036abaUL, 0xed16825cUL, + 0x8acf1c2bUL, 0xa779b492UL, 0xf307f2f0UL, 0x4e69e2a1UL, + 0x65daf4cdUL, 0x0605bed5UL, 0xd134621fUL, 0xc4a6fe8aUL, + 0x342e539dUL, 0xa2f355a0UL, 0x058ae132UL, 0xa4f6eb75UL, + 0x0b83ec39UL, 0x4060efaaUL, 0x5e719f06UL, 0xbd6e1051UL, + 0x3e218af9UL, 0x96dd063dUL, 0xdd3e05aeUL, 0x4de6bd46UL, + 0x91548db5UL, 0x71c45d05UL, 0x0406d46fUL, 0x605015ffUL, + 0x1998fb24UL, 0xd6bde997UL, 0x894043ccUL, 0x67d99e77UL, + 0xb0e842bdUL, 0x07898b88UL, 0xe7195b38UL, 0x79c8eedbUL, + 0xa17c0a47UL, 0x7c420fe9UL, 0xf8841ec9UL, 0x00000000UL, + 0x09808683UL, 0x322bed48UL, 0x1e1170acUL, 0x6c5a724eUL, + 0xfd0efffbUL, 0x0f853856UL, 0x3daed51eUL, 0x362d3927UL, + 0x0a0fd964UL, 0x685ca621UL, 0x9b5b54d1UL, 0x24362e3aUL, + 0x0c0a67b1UL, 0x9357e70fUL, 0xb4ee96d2UL, 0x1b9b919eUL, + 0x80c0c54fUL, 0x61dc20a2UL, 0x5a774b69UL, 0x1c121a16UL, + 0xe293ba0aUL, 0xc0a02ae5UL, 0x3c22e043UL, 0x121b171dUL, + 0x0e090d0bUL, 0xf28bc7adUL, 0x2db6a8b9UL, 0x141ea9c8UL, + 0x57f11985UL, 0xaf75074cUL, 0xee99ddbbUL, 0xa37f60fdUL, + 0xf701269fUL, 0x5c72f5bcUL, 0x44663bc5UL, 0x5bfb7e34UL, + 0x8b432976UL, 0xcb23c6dcUL, 0xb6edfc68UL, 0xb8e4f163UL, + 0xd731dccaUL, 0x42638510UL, 0x13972240UL, 0x84c61120UL, + 0x854a247dUL, 0xd2bb3df8UL, 0xaef93211UL, 0xc729a16dUL, + 0x1d9e2f4bUL, 0xdcb230f3UL, 0x0d8652ecUL, 0x77c1e3d0UL, + 0x2bb3166cUL, 0xa970b999UL, 0x119448faUL, 0x47e96422UL, + 0xa8fc8cc4UL, 0xa0f03f1aUL, 0x567d2cd8UL, 0x223390efUL, + 0x87494ec7UL, 0xd938d1c1UL, 0x8ccaa2feUL, 0x98d40b36UL, + 0xa6f581cfUL, 0xa57ade28UL, 0xdab78e26UL, 0x3fadbfa4UL, + 0x2c3a9de4UL, 0x5078920dUL, 0x6a5fcc9bUL, 0x547e4662UL, + 0xf68d13c2UL, 0x90d8b8e8UL, 0x2e39f75eUL, 0x82c3aff5UL, + 0x9f5d80beUL, 0x69d0937cUL, 0x6fd52da9UL, 0xcf2512b3UL, + 0xc8ac993bUL, 0x10187da7UL, 0xe89c636eUL, 0xdb3bbb7bUL, + 0xcd267809UL, 0x6e5918f4UL, 0xec9ab701UL, 0x834f9aa8UL, + 0xe6956e65UL, 0xaaffe67eUL, 0x21bccf08UL, 0xef15e8e6UL, + 0xbae79bd9UL, 0x4a6f36ceUL, 0xea9f09d4UL, 0x29b07cd6UL, + 0x31a4b2afUL, 0x2a3f2331UL, 0xc6a59430UL, 0x35a266c0UL, + 0x744ebc37UL, 0xfc82caa6UL, 0xe090d0b0UL, 0x33a7d815UL, + 0xf104984aUL, 0x41ecdaf7UL, 0x7fcd500eUL, 0x1791f62fUL, + 0x764dd68dUL, 0x43efb04dUL, 0xccaa4d54UL, 0xe49604dfUL, + 0x9ed1b5e3UL, 0x4c6a881bUL, 0xc12c1fb8UL, 0x4665517fUL, + 0x9d5eea04UL, 0x018c355dUL, 0xfa877473UL, 0xfb0b412eUL, + 0xb3671d5aUL, 0x92dbd252UL, 0xe9105633UL, 0x6dd64713UL, + 0x9ad7618cUL, 0x37a10c7aUL, 0x59f8148eUL, 0xeb133c89UL, + 0xcea927eeUL, 0xb761c935UL, 0xe11ce5edUL, 0x7a47b13cUL, + 0x9cd2df59UL, 0x55f2733fUL, 0x1814ce79UL, 0x73c737bfUL, + 0x53f7cdeaUL, 0x5ffdaa5bUL, 0xdf3d6f14UL, 0x7844db86UL, + 0xcaaff381UL, 0xb968c43eUL, 0x3824342cUL, 0xc2a3405fUL, + 0x161dc372UL, 0xbce2250cUL, 0x283c498bUL, 0xff0d9541UL, + 0x39a80171UL, 0x080cb3deUL, 0xd8b4e49cUL, 0x6456c190UL, + 0x7bcb8461UL, 0xd532b670UL, 0x486c5c74UL, 0xd0b85742UL, +}; +static const unsigned int Td1[256] = { + 0x5051f4a7UL, 0x537e4165UL, 0xc31a17a4UL, 0x963a275eUL, + 0xcb3bab6bUL, 0xf11f9d45UL, 0xabacfa58UL, 0x934be303UL, + 0x552030faUL, 0xf6ad766dUL, 0x9188cc76UL, 0x25f5024cUL, + 0xfc4fe5d7UL, 0xd7c52acbUL, 0x80263544UL, 0x8fb562a3UL, + 0x49deb15aUL, 0x6725ba1bUL, 0x9845ea0eUL, 0xe15dfec0UL, + 0x02c32f75UL, 0x12814cf0UL, 0xa38d4697UL, 0xc66bd3f9UL, + 0xe7038f5fUL, 0x9515929cUL, 0xebbf6d7aUL, 0xda955259UL, + 0x2dd4be83UL, 0xd3587421UL, 0x2949e069UL, 0x448ec9c8UL, + 0x6a75c289UL, 0x78f48e79UL, 0x6b99583eUL, 0xdd27b971UL, + 0xb6bee14fUL, 0x17f088adUL, 0x66c920acUL, 0xb47dce3aUL, + 0x1863df4aUL, 0x82e51a31UL, 0x60975133UL, 0x4562537fUL, + 0xe0b16477UL, 0x84bb6baeUL, 0x1cfe81a0UL, 0x94f9082bUL, + 0x58704868UL, 0x198f45fdUL, 0x8794de6cUL, 0xb7527bf8UL, + 0x23ab73d3UL, 0xe2724b02UL, 0x57e31f8fUL, 0x2a6655abUL, + 0x07b2eb28UL, 0x032fb5c2UL, 0x9a86c57bUL, 0xa5d33708UL, + 0xf2302887UL, 0xb223bfa5UL, 0xba02036aUL, 0x5ced1682UL, + 0x2b8acf1cUL, 0x92a779b4UL, 0xf0f307f2UL, 0xa14e69e2UL, + 0xcd65daf4UL, 0xd50605beUL, 0x1fd13462UL, 0x8ac4a6feUL, + 0x9d342e53UL, 0xa0a2f355UL, 0x32058ae1UL, 0x75a4f6ebUL, + 0x390b83ecUL, 0xaa4060efUL, 0x065e719fUL, 0x51bd6e10UL, + 0xf93e218aUL, 0x3d96dd06UL, 0xaedd3e05UL, 0x464de6bdUL, + 0xb591548dUL, 0x0571c45dUL, 0x6f0406d4UL, 0xff605015UL, + 0x241998fbUL, 0x97d6bde9UL, 0xcc894043UL, 0x7767d99eUL, + 0xbdb0e842UL, 0x8807898bUL, 0x38e7195bUL, 0xdb79c8eeUL, + 0x47a17c0aUL, 0xe97c420fUL, 0xc9f8841eUL, 0x00000000UL, + 0x83098086UL, 0x48322bedUL, 0xac1e1170UL, 0x4e6c5a72UL, + 0xfbfd0effUL, 0x560f8538UL, 0x1e3daed5UL, 0x27362d39UL, + 0x640a0fd9UL, 0x21685ca6UL, 0xd19b5b54UL, 0x3a24362eUL, + 0xb10c0a67UL, 0x0f9357e7UL, 0xd2b4ee96UL, 0x9e1b9b91UL, + 0x4f80c0c5UL, 0xa261dc20UL, 0x695a774bUL, 0x161c121aUL, + 0x0ae293baUL, 0xe5c0a02aUL, 0x433c22e0UL, 0x1d121b17UL, + 0x0b0e090dUL, 0xadf28bc7UL, 0xb92db6a8UL, 0xc8141ea9UL, + 0x8557f119UL, 0x4caf7507UL, 0xbbee99ddUL, 0xfda37f60UL, + 0x9ff70126UL, 0xbc5c72f5UL, 0xc544663bUL, 0x345bfb7eUL, + 0x768b4329UL, 0xdccb23c6UL, 0x68b6edfcUL, 0x63b8e4f1UL, + 0xcad731dcUL, 0x10426385UL, 0x40139722UL, 0x2084c611UL, + 0x7d854a24UL, 0xf8d2bb3dUL, 0x11aef932UL, 0x6dc729a1UL, + 0x4b1d9e2fUL, 0xf3dcb230UL, 0xec0d8652UL, 0xd077c1e3UL, + 0x6c2bb316UL, 0x99a970b9UL, 0xfa119448UL, 0x2247e964UL, + 0xc4a8fc8cUL, 0x1aa0f03fUL, 0xd8567d2cUL, 0xef223390UL, + 0xc787494eUL, 0xc1d938d1UL, 0xfe8ccaa2UL, 0x3698d40bUL, + 0xcfa6f581UL, 0x28a57adeUL, 0x26dab78eUL, 0xa43fadbfUL, + 0xe42c3a9dUL, 0x0d507892UL, 0x9b6a5fccUL, 0x62547e46UL, + 0xc2f68d13UL, 0xe890d8b8UL, 0x5e2e39f7UL, 0xf582c3afUL, + 0xbe9f5d80UL, 0x7c69d093UL, 0xa96fd52dUL, 0xb3cf2512UL, + 0x3bc8ac99UL, 0xa710187dUL, 0x6ee89c63UL, 0x7bdb3bbbUL, + 0x09cd2678UL, 0xf46e5918UL, 0x01ec9ab7UL, 0xa8834f9aUL, + 0x65e6956eUL, 0x7eaaffe6UL, 0x0821bccfUL, 0xe6ef15e8UL, + 0xd9bae79bUL, 0xce4a6f36UL, 0xd4ea9f09UL, 0xd629b07cUL, + 0xaf31a4b2UL, 0x312a3f23UL, 0x30c6a594UL, 0xc035a266UL, + 0x37744ebcUL, 0xa6fc82caUL, 0xb0e090d0UL, 0x1533a7d8UL, + 0x4af10498UL, 0xf741ecdaUL, 0x0e7fcd50UL, 0x2f1791f6UL, + 0x8d764dd6UL, 0x4d43efb0UL, 0x54ccaa4dUL, 0xdfe49604UL, + 0xe39ed1b5UL, 0x1b4c6a88UL, 0xb8c12c1fUL, 0x7f466551UL, + 0x049d5eeaUL, 0x5d018c35UL, 0x73fa8774UL, 0x2efb0b41UL, + 0x5ab3671dUL, 0x5292dbd2UL, 0x33e91056UL, 0x136dd647UL, + 0x8c9ad761UL, 0x7a37a10cUL, 0x8e59f814UL, 0x89eb133cUL, + 0xeecea927UL, 0x35b761c9UL, 0xede11ce5UL, 0x3c7a47b1UL, + 0x599cd2dfUL, 0x3f55f273UL, 0x791814ceUL, 0xbf73c737UL, + 0xea53f7cdUL, 0x5b5ffdaaUL, 0x14df3d6fUL, 0x867844dbUL, + 0x81caaff3UL, 0x3eb968c4UL, 0x2c382434UL, 0x5fc2a340UL, + 0x72161dc3UL, 0x0cbce225UL, 0x8b283c49UL, 0x41ff0d95UL, + 0x7139a801UL, 0xde080cb3UL, 0x9cd8b4e4UL, 0x906456c1UL, + 0x617bcb84UL, 0x70d532b6UL, 0x74486c5cUL, 0x42d0b857UL, +}; +static const unsigned int Td2[256] = { + 0xa75051f4UL, 0x65537e41UL, 0xa4c31a17UL, 0x5e963a27UL, + 0x6bcb3babUL, 0x45f11f9dUL, 0x58abacfaUL, 0x03934be3UL, + 0xfa552030UL, 0x6df6ad76UL, 0x769188ccUL, 0x4c25f502UL, + 0xd7fc4fe5UL, 0xcbd7c52aUL, 0x44802635UL, 0xa38fb562UL, + 0x5a49deb1UL, 0x1b6725baUL, 0x0e9845eaUL, 0xc0e15dfeUL, + 0x7502c32fUL, 0xf012814cUL, 0x97a38d46UL, 0xf9c66bd3UL, + 0x5fe7038fUL, 0x9c951592UL, 0x7aebbf6dUL, 0x59da9552UL, + 0x832dd4beUL, 0x21d35874UL, 0x692949e0UL, 0xc8448ec9UL, + 0x896a75c2UL, 0x7978f48eUL, 0x3e6b9958UL, 0x71dd27b9UL, + 0x4fb6bee1UL, 0xad17f088UL, 0xac66c920UL, 0x3ab47dceUL, + 0x4a1863dfUL, 0x3182e51aUL, 0x33609751UL, 0x7f456253UL, + 0x77e0b164UL, 0xae84bb6bUL, 0xa01cfe81UL, 0x2b94f908UL, + 0x68587048UL, 0xfd198f45UL, 0x6c8794deUL, 0xf8b7527bUL, + 0xd323ab73UL, 0x02e2724bUL, 0x8f57e31fUL, 0xab2a6655UL, + 0x2807b2ebUL, 0xc2032fb5UL, 0x7b9a86c5UL, 0x08a5d337UL, + 0x87f23028UL, 0xa5b223bfUL, 0x6aba0203UL, 0x825ced16UL, + 0x1c2b8acfUL, 0xb492a779UL, 0xf2f0f307UL, 0xe2a14e69UL, + 0xf4cd65daUL, 0xbed50605UL, 0x621fd134UL, 0xfe8ac4a6UL, + 0x539d342eUL, 0x55a0a2f3UL, 0xe132058aUL, 0xeb75a4f6UL, + 0xec390b83UL, 0xefaa4060UL, 0x9f065e71UL, 0x1051bd6eUL, + 0x8af93e21UL, 0x063d96ddUL, 0x05aedd3eUL, 0xbd464de6UL, + 0x8db59154UL, 0x5d0571c4UL, 0xd46f0406UL, 0x15ff6050UL, + 0xfb241998UL, 0xe997d6bdUL, 0x43cc8940UL, 0x9e7767d9UL, + 0x42bdb0e8UL, 0x8b880789UL, 0x5b38e719UL, 0xeedb79c8UL, + 0x0a47a17cUL, 0x0fe97c42UL, 0x1ec9f884UL, 0x00000000UL, + 0x86830980UL, 0xed48322bUL, 0x70ac1e11UL, 0x724e6c5aUL, + 0xfffbfd0eUL, 0x38560f85UL, 0xd51e3daeUL, 0x3927362dUL, + 0xd9640a0fUL, 0xa621685cUL, 0x54d19b5bUL, 0x2e3a2436UL, + 0x67b10c0aUL, 0xe70f9357UL, 0x96d2b4eeUL, 0x919e1b9bUL, + 0xc54f80c0UL, 0x20a261dcUL, 0x4b695a77UL, 0x1a161c12UL, + 0xba0ae293UL, 0x2ae5c0a0UL, 0xe0433c22UL, 0x171d121bUL, + 0x0d0b0e09UL, 0xc7adf28bUL, 0xa8b92db6UL, 0xa9c8141eUL, + 0x198557f1UL, 0x074caf75UL, 0xddbbee99UL, 0x60fda37fUL, + 0x269ff701UL, 0xf5bc5c72UL, 0x3bc54466UL, 0x7e345bfbUL, + 0x29768b43UL, 0xc6dccb23UL, 0xfc68b6edUL, 0xf163b8e4UL, + 0xdccad731UL, 0x85104263UL, 0x22401397UL, 0x112084c6UL, + 0x247d854aUL, 0x3df8d2bbUL, 0x3211aef9UL, 0xa16dc729UL, + 0x2f4b1d9eUL, 0x30f3dcb2UL, 0x52ec0d86UL, 0xe3d077c1UL, + 0x166c2bb3UL, 0xb999a970UL, 0x48fa1194UL, 0x642247e9UL, + 0x8cc4a8fcUL, 0x3f1aa0f0UL, 0x2cd8567dUL, 0x90ef2233UL, + 0x4ec78749UL, 0xd1c1d938UL, 0xa2fe8ccaUL, 0x0b3698d4UL, + 0x81cfa6f5UL, 0xde28a57aUL, 0x8e26dab7UL, 0xbfa43fadUL, + 0x9de42c3aUL, 0x920d5078UL, 0xcc9b6a5fUL, 0x4662547eUL, + 0x13c2f68dUL, 0xb8e890d8UL, 0xf75e2e39UL, 0xaff582c3UL, + 0x80be9f5dUL, 0x937c69d0UL, 0x2da96fd5UL, 0x12b3cf25UL, + 0x993bc8acUL, 0x7da71018UL, 0x636ee89cUL, 0xbb7bdb3bUL, + 0x7809cd26UL, 0x18f46e59UL, 0xb701ec9aUL, 0x9aa8834fUL, + 0x6e65e695UL, 0xe67eaaffUL, 0xcf0821bcUL, 0xe8e6ef15UL, + 0x9bd9bae7UL, 0x36ce4a6fUL, 0x09d4ea9fUL, 0x7cd629b0UL, + 0xb2af31a4UL, 0x23312a3fUL, 0x9430c6a5UL, 0x66c035a2UL, + 0xbc37744eUL, 0xcaa6fc82UL, 0xd0b0e090UL, 0xd81533a7UL, + 0x984af104UL, 0xdaf741ecUL, 0x500e7fcdUL, 0xf62f1791UL, + 0xd68d764dUL, 0xb04d43efUL, 0x4d54ccaaUL, 0x04dfe496UL, + 0xb5e39ed1UL, 0x881b4c6aUL, 0x1fb8c12cUL, 0x517f4665UL, + 0xea049d5eUL, 0x355d018cUL, 0x7473fa87UL, 0x412efb0bUL, + 0x1d5ab367UL, 0xd25292dbUL, 0x5633e910UL, 0x47136dd6UL, + 0x618c9ad7UL, 0x0c7a37a1UL, 0x148e59f8UL, 0x3c89eb13UL, + 0x27eecea9UL, 0xc935b761UL, 0xe5ede11cUL, 0xb13c7a47UL, + 0xdf599cd2UL, 0x733f55f2UL, 0xce791814UL, 0x37bf73c7UL, + 0xcdea53f7UL, 0xaa5b5ffdUL, 0x6f14df3dUL, 0xdb867844UL, + 0xf381caafUL, 0xc43eb968UL, 0x342c3824UL, 0x405fc2a3UL, + 0xc372161dUL, 0x250cbce2UL, 0x498b283cUL, 0x9541ff0dUL, + 0x017139a8UL, 0xb3de080cUL, 0xe49cd8b4UL, 0xc1906456UL, + 0x84617bcbUL, 0xb670d532UL, 0x5c74486cUL, 0x5742d0b8UL, +}; +static const unsigned int Td3[256] = { + 0xf4a75051UL, 0x4165537eUL, 0x17a4c31aUL, 0x275e963aUL, + 0xab6bcb3bUL, 0x9d45f11fUL, 0xfa58abacUL, 0xe303934bUL, + 0x30fa5520UL, 0x766df6adUL, 0xcc769188UL, 0x024c25f5UL, + 0xe5d7fc4fUL, 0x2acbd7c5UL, 0x35448026UL, 0x62a38fb5UL, + 0xb15a49deUL, 0xba1b6725UL, 0xea0e9845UL, 0xfec0e15dUL, + 0x2f7502c3UL, 0x4cf01281UL, 0x4697a38dUL, 0xd3f9c66bUL, + 0x8f5fe703UL, 0x929c9515UL, 0x6d7aebbfUL, 0x5259da95UL, + 0xbe832dd4UL, 0x7421d358UL, 0xe0692949UL, 0xc9c8448eUL, + 0xc2896a75UL, 0x8e7978f4UL, 0x583e6b99UL, 0xb971dd27UL, + 0xe14fb6beUL, 0x88ad17f0UL, 0x20ac66c9UL, 0xce3ab47dUL, + 0xdf4a1863UL, 0x1a3182e5UL, 0x51336097UL, 0x537f4562UL, + 0x6477e0b1UL, 0x6bae84bbUL, 0x81a01cfeUL, 0x082b94f9UL, + 0x48685870UL, 0x45fd198fUL, 0xde6c8794UL, 0x7bf8b752UL, + 0x73d323abUL, 0x4b02e272UL, 0x1f8f57e3UL, 0x55ab2a66UL, + 0xeb2807b2UL, 0xb5c2032fUL, 0xc57b9a86UL, 0x3708a5d3UL, + 0x2887f230UL, 0xbfa5b223UL, 0x036aba02UL, 0x16825cedUL, + 0xcf1c2b8aUL, 0x79b492a7UL, 0x07f2f0f3UL, 0x69e2a14eUL, + 0xdaf4cd65UL, 0x05bed506UL, 0x34621fd1UL, 0xa6fe8ac4UL, + 0x2e539d34UL, 0xf355a0a2UL, 0x8ae13205UL, 0xf6eb75a4UL, + 0x83ec390bUL, 0x60efaa40UL, 0x719f065eUL, 0x6e1051bdUL, + 0x218af93eUL, 0xdd063d96UL, 0x3e05aeddUL, 0xe6bd464dUL, + 0x548db591UL, 0xc45d0571UL, 0x06d46f04UL, 0x5015ff60UL, + 0x98fb2419UL, 0xbde997d6UL, 0x4043cc89UL, 0xd99e7767UL, + 0xe842bdb0UL, 0x898b8807UL, 0x195b38e7UL, 0xc8eedb79UL, + 0x7c0a47a1UL, 0x420fe97cUL, 0x841ec9f8UL, 0x00000000UL, + 0x80868309UL, 0x2bed4832UL, 0x1170ac1eUL, 0x5a724e6cUL, + 0x0efffbfdUL, 0x8538560fUL, 0xaed51e3dUL, 0x2d392736UL, + 0x0fd9640aUL, 0x5ca62168UL, 0x5b54d19bUL, 0x362e3a24UL, + 0x0a67b10cUL, 0x57e70f93UL, 0xee96d2b4UL, 0x9b919e1bUL, + 0xc0c54f80UL, 0xdc20a261UL, 0x774b695aUL, 0x121a161cUL, + 0x93ba0ae2UL, 0xa02ae5c0UL, 0x22e0433cUL, 0x1b171d12UL, + 0x090d0b0eUL, 0x8bc7adf2UL, 0xb6a8b92dUL, 0x1ea9c814UL, + 0xf1198557UL, 0x75074cafUL, 0x99ddbbeeUL, 0x7f60fda3UL, + 0x01269ff7UL, 0x72f5bc5cUL, 0x663bc544UL, 0xfb7e345bUL, + 0x4329768bUL, 0x23c6dccbUL, 0xedfc68b6UL, 0xe4f163b8UL, + 0x31dccad7UL, 0x63851042UL, 0x97224013UL, 0xc6112084UL, + 0x4a247d85UL, 0xbb3df8d2UL, 0xf93211aeUL, 0x29a16dc7UL, + 0x9e2f4b1dUL, 0xb230f3dcUL, 0x8652ec0dUL, 0xc1e3d077UL, + 0xb3166c2bUL, 0x70b999a9UL, 0x9448fa11UL, 0xe9642247UL, + 0xfc8cc4a8UL, 0xf03f1aa0UL, 0x7d2cd856UL, 0x3390ef22UL, + 0x494ec787UL, 0x38d1c1d9UL, 0xcaa2fe8cUL, 0xd40b3698UL, + 0xf581cfa6UL, 0x7ade28a5UL, 0xb78e26daUL, 0xadbfa43fUL, + 0x3a9de42cUL, 0x78920d50UL, 0x5fcc9b6aUL, 0x7e466254UL, + 0x8d13c2f6UL, 0xd8b8e890UL, 0x39f75e2eUL, 0xc3aff582UL, + 0x5d80be9fUL, 0xd0937c69UL, 0xd52da96fUL, 0x2512b3cfUL, + 0xac993bc8UL, 0x187da710UL, 0x9c636ee8UL, 0x3bbb7bdbUL, + 0x267809cdUL, 0x5918f46eUL, 0x9ab701ecUL, 0x4f9aa883UL, + 0x956e65e6UL, 0xffe67eaaUL, 0xbccf0821UL, 0x15e8e6efUL, + 0xe79bd9baUL, 0x6f36ce4aUL, 0x9f09d4eaUL, 0xb07cd629UL, + 0xa4b2af31UL, 0x3f23312aUL, 0xa59430c6UL, 0xa266c035UL, + 0x4ebc3774UL, 0x82caa6fcUL, 0x90d0b0e0UL, 0xa7d81533UL, + 0x04984af1UL, 0xecdaf741UL, 0xcd500e7fUL, 0x91f62f17UL, + 0x4dd68d76UL, 0xefb04d43UL, 0xaa4d54ccUL, 0x9604dfe4UL, + 0xd1b5e39eUL, 0x6a881b4cUL, 0x2c1fb8c1UL, 0x65517f46UL, + 0x5eea049dUL, 0x8c355d01UL, 0x877473faUL, 0x0b412efbUL, + 0x671d5ab3UL, 0xdbd25292UL, 0x105633e9UL, 0xd647136dUL, + 0xd7618c9aUL, 0xa10c7a37UL, 0xf8148e59UL, 0x133c89ebUL, + 0xa927eeceUL, 0x61c935b7UL, 0x1ce5ede1UL, 0x47b13c7aUL, + 0xd2df599cUL, 0xf2733f55UL, 0x14ce7918UL, 0xc737bf73UL, + 0xf7cdea53UL, 0xfdaa5b5fUL, 0x3d6f14dfUL, 0x44db8678UL, + 0xaff381caUL, 0x68c43eb9UL, 0x24342c38UL, 0xa3405fc2UL, + 0x1dc37216UL, 0xe2250cbcUL, 0x3c498b28UL, 0x0d9541ffUL, + 0xa8017139UL, 0x0cb3de08UL, 0xb4e49cd8UL, 0x56c19064UL, + 0xcb84617bUL, 0x32b670d5UL, 0x6c5c7448UL, 0xb85742d0UL, +}; +static const unsigned int Td4[256] = { + 0x52525252UL, 0x09090909UL, 0x6a6a6a6aUL, 0xd5d5d5d5UL, + 0x30303030UL, 0x36363636UL, 0xa5a5a5a5UL, 0x38383838UL, + 0xbfbfbfbfUL, 0x40404040UL, 0xa3a3a3a3UL, 0x9e9e9e9eUL, + 0x81818181UL, 0xf3f3f3f3UL, 0xd7d7d7d7UL, 0xfbfbfbfbUL, + 0x7c7c7c7cUL, 0xe3e3e3e3UL, 0x39393939UL, 0x82828282UL, + 0x9b9b9b9bUL, 0x2f2f2f2fUL, 0xffffffffUL, 0x87878787UL, + 0x34343434UL, 0x8e8e8e8eUL, 0x43434343UL, 0x44444444UL, + 0xc4c4c4c4UL, 0xdedededeUL, 0xe9e9e9e9UL, 0xcbcbcbcbUL, + 0x54545454UL, 0x7b7b7b7bUL, 0x94949494UL, 0x32323232UL, + 0xa6a6a6a6UL, 0xc2c2c2c2UL, 0x23232323UL, 0x3d3d3d3dUL, + 0xeeeeeeeeUL, 0x4c4c4c4cUL, 0x95959595UL, 0x0b0b0b0bUL, + 0x42424242UL, 0xfafafafaUL, 0xc3c3c3c3UL, 0x4e4e4e4eUL, + 0x08080808UL, 0x2e2e2e2eUL, 0xa1a1a1a1UL, 0x66666666UL, + 0x28282828UL, 0xd9d9d9d9UL, 0x24242424UL, 0xb2b2b2b2UL, + 0x76767676UL, 0x5b5b5b5bUL, 0xa2a2a2a2UL, 0x49494949UL, + 0x6d6d6d6dUL, 0x8b8b8b8bUL, 0xd1d1d1d1UL, 0x25252525UL, + 0x72727272UL, 0xf8f8f8f8UL, 0xf6f6f6f6UL, 0x64646464UL, + 0x86868686UL, 0x68686868UL, 0x98989898UL, 0x16161616UL, + 0xd4d4d4d4UL, 0xa4a4a4a4UL, 0x5c5c5c5cUL, 0xccccccccUL, + 0x5d5d5d5dUL, 0x65656565UL, 0xb6b6b6b6UL, 0x92929292UL, + 0x6c6c6c6cUL, 0x70707070UL, 0x48484848UL, 0x50505050UL, + 0xfdfdfdfdUL, 0xededededUL, 0xb9b9b9b9UL, 0xdadadadaUL, + 0x5e5e5e5eUL, 0x15151515UL, 0x46464646UL, 0x57575757UL, + 0xa7a7a7a7UL, 0x8d8d8d8dUL, 0x9d9d9d9dUL, 0x84848484UL, + 0x90909090UL, 0xd8d8d8d8UL, 0xababababUL, 0x00000000UL, + 0x8c8c8c8cUL, 0xbcbcbcbcUL, 0xd3d3d3d3UL, 0x0a0a0a0aUL, + 0xf7f7f7f7UL, 0xe4e4e4e4UL, 0x58585858UL, 0x05050505UL, + 0xb8b8b8b8UL, 0xb3b3b3b3UL, 0x45454545UL, 0x06060606UL, + 0xd0d0d0d0UL, 0x2c2c2c2cUL, 0x1e1e1e1eUL, 0x8f8f8f8fUL, + 0xcacacacaUL, 0x3f3f3f3fUL, 0x0f0f0f0fUL, 0x02020202UL, + 0xc1c1c1c1UL, 0xafafafafUL, 0xbdbdbdbdUL, 0x03030303UL, + 0x01010101UL, 0x13131313UL, 0x8a8a8a8aUL, 0x6b6b6b6bUL, + 0x3a3a3a3aUL, 0x91919191UL, 0x11111111UL, 0x41414141UL, + 0x4f4f4f4fUL, 0x67676767UL, 0xdcdcdcdcUL, 0xeaeaeaeaUL, + 0x97979797UL, 0xf2f2f2f2UL, 0xcfcfcfcfUL, 0xcecececeUL, + 0xf0f0f0f0UL, 0xb4b4b4b4UL, 0xe6e6e6e6UL, 0x73737373UL, + 0x96969696UL, 0xacacacacUL, 0x74747474UL, 0x22222222UL, + 0xe7e7e7e7UL, 0xadadadadUL, 0x35353535UL, 0x85858585UL, + 0xe2e2e2e2UL, 0xf9f9f9f9UL, 0x37373737UL, 0xe8e8e8e8UL, + 0x1c1c1c1cUL, 0x75757575UL, 0xdfdfdfdfUL, 0x6e6e6e6eUL, + 0x47474747UL, 0xf1f1f1f1UL, 0x1a1a1a1aUL, 0x71717171UL, + 0x1d1d1d1dUL, 0x29292929UL, 0xc5c5c5c5UL, 0x89898989UL, + 0x6f6f6f6fUL, 0xb7b7b7b7UL, 0x62626262UL, 0x0e0e0e0eUL, + 0xaaaaaaaaUL, 0x18181818UL, 0xbebebebeUL, 0x1b1b1b1bUL, + 0xfcfcfcfcUL, 0x56565656UL, 0x3e3e3e3eUL, 0x4b4b4b4bUL, + 0xc6c6c6c6UL, 0xd2d2d2d2UL, 0x79797979UL, 0x20202020UL, + 0x9a9a9a9aUL, 0xdbdbdbdbUL, 0xc0c0c0c0UL, 0xfefefefeUL, + 0x78787878UL, 0xcdcdcdcdUL, 0x5a5a5a5aUL, 0xf4f4f4f4UL, + 0x1f1f1f1fUL, 0xddddddddUL, 0xa8a8a8a8UL, 0x33333333UL, + 0x88888888UL, 0x07070707UL, 0xc7c7c7c7UL, 0x31313131UL, + 0xb1b1b1b1UL, 0x12121212UL, 0x10101010UL, 0x59595959UL, + 0x27272727UL, 0x80808080UL, 0xececececUL, 0x5f5f5f5fUL, + 0x60606060UL, 0x51515151UL, 0x7f7f7f7fUL, 0xa9a9a9a9UL, + 0x19191919UL, 0xb5b5b5b5UL, 0x4a4a4a4aUL, 0x0d0d0d0dUL, + 0x2d2d2d2dUL, 0xe5e5e5e5UL, 0x7a7a7a7aUL, 0x9f9f9f9fUL, + 0x93939393UL, 0xc9c9c9c9UL, 0x9c9c9c9cUL, 0xefefefefUL, + 0xa0a0a0a0UL, 0xe0e0e0e0UL, 0x3b3b3b3bUL, 0x4d4d4d4dUL, + 0xaeaeaeaeUL, 0x2a2a2a2aUL, 0xf5f5f5f5UL, 0xb0b0b0b0UL, + 0xc8c8c8c8UL, 0xebebebebUL, 0xbbbbbbbbUL, 0x3c3c3c3cUL, + 0x83838383UL, 0x53535353UL, 0x99999999UL, 0x61616161UL, + 0x17171717UL, 0x2b2b2b2bUL, 0x04040404UL, 0x7e7e7e7eUL, + 0xbabababaUL, 0x77777777UL, 0xd6d6d6d6UL, 0x26262626UL, + 0xe1e1e1e1UL, 0x69696969UL, 0x14141414UL, 0x63636363UL, + 0x55555555UL, 0x21212121UL, 0x0c0c0c0cUL, 0x7d7d7d7dUL, +}; +static const unsigned int rcon[] = { + 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, + 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, + 0x1B000000UL, 0x36000000UL, +}; + +#define GETU32(pt) (((unsigned int)(pt)[0] << 24) ^ \ + ((unsigned int)(pt)[1] << 16) ^ \ + ((unsigned int)(pt)[2] << 8) ^ \ + ((unsigned int)(pt)[3])) + +#define PUTU32(ct, st) { (ct)[0] = (unsigned char)((st) >> 24); \ + (ct)[1] = (unsigned char)((st) >> 16); \ + (ct)[2] = (unsigned char)((st) >> 8); \ + (ct)[3] = (unsigned char)(st); } + +/* +* Expand the cipher key into the encryption key schedule and return the +* number of rounds for the given cipher key size. +*/ +int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBytes) +{ + int i = 0; + unsigned int temp; + + rk[0] = GETU32(cipherKey ); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + if (keyBytes == 16) { // 128 bits + for (;;) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 10; + } + rk += 4; + } + } + rk[4] = GETU32(cipherKey + 16); + rk[5] = GETU32(cipherKey + 20); + if (keyBytes == 24) { // 192 bits + for (;;) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 12; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(cipherKey + 24); + rk[7] = GETU32(cipherKey + 28); + if (keyBytes == 32) { // 256 bits + for (;;) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 14; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +/* +* Expand the cipher key into encryption and decryption key schedule and +* return the number of rounds for the given cipher key size. +*/ +int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char cipherKey[], int keyBytes) +{ + int Nr, i; + + // expand the cipher key + Nr = aes_setkey_enc(rk, cipherKey, keyBytes); + // invert the order of the first round keys + rrk += Nr * 4; + rrk[0] = rk[0]; + rrk[1] = rk[1]; + rrk[2] = rk[2]; + rrk[3] = rk[3]; + + /* + * apply the inverse MixColumn transform to all round keys but the first + * and the last + */ + for (i = 1; i < Nr; i++) { + rrk -= 4; + rk += 4; + rrk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rrk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rrk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rrk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + // invert the order of the last round keys + rrk -= 4; + rk += 4; + rrk[0] = rk[0]; + rrk[1] = rk[1]; + rrk[2] = rk[2]; + rrk[3] = rk[3]; + + return Nr; +} + +/* +* Encrypt the plain text into cipher +*/ +void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) +{ + unsigned int s0, s1, s2, s3, t0, t1, t2, t3, *iv; + const unsigned int *rk; + int r; + + rk = pCtx->Ek; + iv = pCtx->Iv; + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(pt ) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; + if (pCtx->Mode) { + s0 = s0 ^ iv[0]; + s1 = s1 ^ iv[1]; + s2 = s2 ^ iv[2]; + s3 = s3 ^ iv[3]; + } + /* + * Nr - 1 full rounds: + */ + r = pCtx->Nr >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(ct , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(ct + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(ct + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(ct + 12, s3); + + if (pCtx->Mode) { + iv[0] = s0; + iv[1] = s1; + iv[2] = s2; + iv[3] = s3; + } +} + +/* +* Decrypt the cipher into plain text +*/ +void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) +{ + unsigned int s0, s1, s2, s3, t0, t1, t2, t3, v0, v1, v2, v3, *iv; + const unsigned int *rk; + int r; + + rk = pCtx->Dk; + iv = pCtx->Iv; + /* + * map byte array block to cipher state + * and add initial round key: + */ + v0 = GETU32(ct ); s0 = v0 ^ rk[0]; + v1 = GETU32(ct + 4); s1 = v1 ^ rk[1]; + v2 = GETU32(ct + 8); s2 = v2 ^ rk[2]; + v3 = GETU32(ct + 12); s3 = v3 ^ rk[3]; + /* + * Nr - 1 full rounds: + */ + r = pCtx->Nr >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + + if (pCtx->Mode) { + s0 = s0 ^ iv[0]; iv[0] = v0; + s1 = s1 ^ iv[1]; iv[1] = v1; + s2 = s2 ^ iv[2]; iv[2] = v2; + s3 = s3 ^ iv[3]; iv[3] = v3; + } + + PUTU32(pt , s0); + PUTU32(pt + 4, s1); + PUTU32(pt + 8, s2); + PUTU32(pt + 12, s3); +} + +////////////////////////////////////////////////////////////////////////////// +// API functions // +////////////////////////////////////////////////////////////////////////////// + +/* +* initialize AES context +*/ +int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode) +{ + if (pKey == 0 || pCtx == 0 || (KeyLen != KEY128 && KeyLen != KEY192 && KeyLen != KEY256)) + return -1; + + // generate key schedule + pCtx->Nr = AesGenKeySched(pCtx->Ek, pCtx->Dk, pKey, KeyLen); + + // initialize IV + if (pIV != 0) { + pCtx->Iv[0] = GETU32(pIV ); + pCtx->Iv[1] = GETU32(pIV + 4 ); + pCtx->Iv[2] = GETU32(pIV + 8 ); + pCtx->Iv[3] = GETU32(pIV + 12); + } + + // mode + pCtx->Mode = Mode; + + return 0; +} + +/* +* Encrypt plain text +*/ +int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen) +{ + int i; + + if (pData == 0 || pCipher == 0 || pCtx == 0 || (DataLen & 0xf) != 0) + return -1; + + for (i = 0; i < DataLen; i += BLOCKSZ) { + // encrypt block by block + AesEncBlk(pCtx, pData, pCipher); + pCipher += BLOCKSZ; + pData += BLOCKSZ; + } + return DataLen; +} + +/* +* Decrypt cipher +*/ +int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen) +{ + int i; + + if (pData == 0 || pCipher == 0 || pCtx == 0 || (CipherLen & 0xf) != 0) + return -1; + + for (i = 0; i < CipherLen; i += BLOCKSZ) { + // decrypt block by block + AesDecBlk(pCtx, pCipher, pData); + pCipher += BLOCKSZ; + pData += BLOCKSZ; + } + return CipherLen; +} + +////////////////////////////////////////////////////////////////////////////// +// Sample main program // +////////////////////////////////////////////////////////////////////////////// + +#ifndef EMBEDDED +int main() +{ + AesCtx ctx; + unsigned char iv[] = "INI VECTINI VECT"; + unsigned char key[] = "This is a sample AESKey"; + unsigned char databuf[] = "Data : AES Test"; // must be in multiple of 16 + + // initialize context and encrypt data at one end + + if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) + printf("init error\n"); + + if (AesEncrypt(&ctx, databuf, databuf, sizeof databuf) < 0) + printf("error in encryption\n"); + + // initialize context and decrypt cipher at other end + + if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) + printf("init error\n"); + + if (AesDecrypt(&ctx, databuf, databuf, sizeof databuf) < 0) + printf("error in decryption\n"); + + printf("%s\n", databuf); + + return 0; +} +#endif \ No newline at end of file diff --git a/armsrc/aes.h b/armsrc/aes.h new file mode 100644 index 00000000..85944873 --- /dev/null +++ b/armsrc/aes.h @@ -0,0 +1,30 @@ +/* +* AES Cryptographic Algorithm Header File. Include this header file in +* your source which uses these given APIs. (This source is kept under +* public domain) +*/ + +// AES context structure +typedef struct { + unsigned int Ek[60]; + unsigned int Dk[60]; + unsigned int Iv[4]; + unsigned char Nr; + unsigned char Mode; +} AesCtx; + +// key length in bytes +#define KEY128 16 +#define KEY192 24 +#define KEY256 32 +// block size in bytes +#define BLOCKSZ 16 +// mode +#define EBC 0 +#define CBC 1 + +// AES API function prototype + +int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode); +int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen); +int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen); \ No newline at end of file diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 2061f6b3..6f8b0150 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -10,10 +10,10 @@ // executes. //----------------------------------------------------------------------------- -#include "usb_cdc.h" -#include "cmd.h" +#include "../common/usb_cdc.h" +#include "../common/cmd.h" -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "printf.h" @@ -22,7 +22,7 @@ #include #include "legicrf.h" -#include +#include "../include/hitag2.h" #ifdef WITH_LCD #include "LCD.h" @@ -81,40 +81,12 @@ void DbpString(char *str) { byte_t len = strlen(str); cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len); -// /* this holds up stuff unless we're connected to usb */ -// if (!UsbConnected()) -// return; -// -// UsbCommand c; -// c.cmd = CMD_DEBUG_PRINT_STRING; -// c.arg[0] = strlen(str); -// if(c.arg[0] > sizeof(c.d.asBytes)) { -// c.arg[0] = sizeof(c.d.asBytes); -// } -// memcpy(c.d.asBytes, str, c.arg[0]); -// -// UsbSendPacket((uint8_t *)&c, sizeof(c)); -// // TODO fix USB so stupid things like this aren't req'd -// SpinDelay(50); } #if 0 void DbpIntegers(int x1, int x2, int x3) { cmd_send(CMD_DEBUG_PRINT_INTEGERS,x1,x2,x3,0,0); -// /* this holds up stuff unless we're connected to usb */ -// if (!UsbConnected()) -// return; -// -// UsbCommand c; -// c.cmd = CMD_DEBUG_PRINT_INTEGERS; -// c.arg[0] = x1; -// c.arg[1] = x2; -// c.arg[2] = x3; -// -// UsbSendPacket((uint8_t *)&c, sizeof(c)); -// // XXX -// SpinDelay(50); } #endif @@ -199,8 +171,6 @@ void MeasureAntennaTuning(void) int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0 int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV -// UsbCommand c; - LED_B_ON(); DbpString("Measuring antenna characteristics, please wait..."); memset(dest,0,sizeof(FREE_BUFFER_SIZE)); @@ -692,7 +662,6 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_PCF7931_READ: // Read PCF7931 tag ReadPCF7931(); cmd_send(CMD_ACK,0,0,0,0,0); -// UsbSendPacket((uint8_t*)&ack, sizeof(ack)); break; case CMD_EM4X_READ_WORD: EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]); @@ -800,8 +769,17 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFAREU_READBL: MifareUReadBlock(c->arg[0],c->d.asBytes); break; + case CMD_MIFAREUC_AUTH1: + MifareUC_Auth1(c->arg[0],c->d.asBytes); + break; + case CMD_MIFAREUC_AUTH2: + MifareUC_Auth2(c->arg[0],c->d.asBytes); + break; case CMD_MIFAREU_READCARD: - MifareUReadCard(c->arg[0],c->d.asBytes); + MifareUReadCard(c->arg[0],c->arg[1],c->d.asBytes); + break; + case CMD_MIFAREUC_READCARD: + MifareUReadCard(c->arg[0],c->arg[1],c->d.asBytes); break; case CMD_MIFARE_READSC: MifareReadSector(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); @@ -854,6 +832,24 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFARE_SNIFFER: 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; #endif #ifdef WITH_ICLASS @@ -867,6 +863,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_READER_ICLASS: ReaderIClass(c->arg[0]); break; + case CMD_READER_ICLASS_REPLAY: + ReaderIClass_Replay(c->arg[0], c->d.asBytes); + break; #endif case CMD_SIMULATE_TAG_HF_LISTEN: @@ -896,18 +895,6 @@ void UsbPacketReceived(uint8_t *packet, int len) break; case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: -// UsbCommand n; -// if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) { -// n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K; -// } else { -// n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE; -// } -// n.arg[0] = c->arg[0]; - // memcpy(n.d.asBytes, BigBuf+c->arg[0], 48); // 12*sizeof(uint32_t) - // LED_B_ON(); - // usb_write((uint8_t *)&n, sizeof(n)); - // UsbSendPacket((uint8_t *)&n, sizeof(n)); - // LED_B_OFF(); LED_B_ON(); for(size_t i=0; iarg[1]; i += USB_CMD_DATA_SIZE) { @@ -923,7 +910,6 @@ void UsbPacketReceived(uint8_t *packet, int len) uint8_t *b = (uint8_t *)BigBuf; memcpy(b+c->arg[0], c->d.asBytes, 48); //Dbprintf("copied 48 bytes to %i",b+c->arg[0]); -// UsbSendPacket((uint8_t*)&ack, sizeof(ack)); cmd_send(CMD_ACK,0,0,0,0,0); break; } @@ -981,7 +967,6 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_DEVICE_INFO: { uint32_t dev_info = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS; if(common_area.flags.bootrom_present) dev_info |= DEVICE_INFO_FLAG_BOOTROM_PRESENT; -// UsbSendPacket((uint8_t*)&c, sizeof(c)); cmd_send(CMD_DEVICE_INFO,dev_info,0,0,0,0); break; } @@ -1010,7 +995,6 @@ void __attribute__((noreturn)) AppMain(void) // Init USB device` usb_enable(); -// UsbStart(); // The FPGA gets its clock from us from PCK0 output, so set that up. AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0; @@ -1046,8 +1030,6 @@ void __attribute__((noreturn)) AppMain(void) UsbPacketReceived(rx,rx_len); } } -// UsbPoll(FALSE); - WDT_HIT(); #ifdef WITH_LF diff --git a/armsrc/apps.h b/armsrc/apps.h index 1ef0e472..7c389e7c 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -14,9 +14,27 @@ #include #include -#include "common.h" -#include "hitag2.h" -#include "mifare.h" +#include + +#include +#include +#include + + +#include "../include/common.h" +#include "../include/hitag2.h" +#include "../include/mifare.h" + +//#include +//#include + +//#include "des.h" +//#include "aes.h" +#include "../common/desfire.h" +#include "../common/crc32.h" +//#include "desfire_crypto.h" +//#include "desfire_key.h" + // The large multi-purpose buffer, typically used to hold A/D samples, // maybe processed in some way. @@ -172,7 +190,9 @@ void ReaderMifare(bool first_try); int32_t dist_nt(uint32_t nt1, uint32_t nt2); void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); void MifareUReadBlock(uint8_t arg0,uint8_t *datain); -void MifareUReadCard(uint8_t arg0,uint8_t *datain); +void MifareUC_Auth1(uint8_t arg0, uint8_t *datain); +void MifareUC_Auth2(uint32_t arg0, uint8_t *datain); +void MifareUReadCard(uint8_t arg0,int Pages,uint8_t *datain); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0,uint8_t *datain); @@ -188,6 +208,47 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +// mifaredesfire.h +void MifareDesfireGetInformation(); +void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); +void MifareDES_Auth2(uint32_t arg0, uint8_t *datain); +int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); +void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); +int SendDesfireCommand(enum DESFIRE_CMD desfire_cmd, uint8_t *dataout, uint8_t fromscratch); +uint8_t* CreateAPDU( uint8_t *datain, size_t len); +void OnSuccess(); +void OnError(); + +// desfire_key.h +desfirekey_t Desfire_des_key_new (const uint8_t value[8]); +desfirekey_t Desfire_3des_key_new (const uint8_t value[16]); +desfirekey_t Desfire_des_key_new_with_version (const uint8_t value[8]); +desfirekey_t Desfire_3des_key_new_with_version (const uint8_t value[16]); +desfirekey_t Desfire_3k3des_key_new (const uint8_t value[24]); +desfirekey_t Desfire_3k3des_key_new_with_version (const uint8_t value[24]); +desfirekey_t Desfire_aes_key_new (const uint8_t value[16]); +desfirekey_t Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version); +uint8_t Desfire_key_get_version (desfirekey_t key); +void Desfire_key_set_version (desfirekey_t key, uint8_t version); +desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey); + +// 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 void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); @@ -201,7 +262,9 @@ void SetDebugIso15693(uint32_t flag); void RAMFUNC SnoopIClass(void); void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void ReaderIClass(uint8_t arg0); -//int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived); +void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC); +void IClass_iso14443A_GetPublic(uint8_t arg0); + // hitag2.h void SnoopHitag(uint32_t type); void SimulateHitagTag(bool tag_mem_supplied, byte_t* data); diff --git a/armsrc/des.c b/armsrc/des.c new file mode 100644 index 00000000..0a27503e --- /dev/null +++ b/armsrc/des.c @@ -0,0 +1,383 @@ +/* des.c */ +/* + This file is part of the ARM-Crypto-Lib. + Copyright (C) 2006-2010 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** + * \file des.c + * \author Daniel Otte + * \email daniel.otte@rub.de + * \date 2007-06-16 + * \brief DES and EDE-DES implementation + * \license GPLv3 or later + * + */ +#include +#include + +const uint8_t sbox[256] = { + /* S-box 1 */ + 0xE4, 0xD1, 0x2F, 0xB8, 0x3A, 0x6C, 0x59, 0x07, + 0x0F, 0x74, 0xE2, 0xD1, 0xA6, 0xCB, 0x95, 0x38, + 0x41, 0xE8, 0xD6, 0x2B, 0xFC, 0x97, 0x3A, 0x50, + 0xFC, 0x82, 0x49, 0x17, 0x5B, 0x3E, 0xA0, 0x6D, + /* S-box 2 */ + 0xF1, 0x8E, 0x6B, 0x34, 0x97, 0x2D, 0xC0, 0x5A, + 0x3D, 0x47, 0xF2, 0x8E, 0xC0, 0x1A, 0x69, 0xB5, + 0x0E, 0x7B, 0xA4, 0xD1, 0x58, 0xC6, 0x93, 0x2F, + 0xD8, 0xA1, 0x3F, 0x42, 0xB6, 0x7C, 0x05, 0xE9, + /* S-box 3 */ + 0xA0, 0x9E, 0x63, 0xF5, 0x1D, 0xC7, 0xB4, 0x28, + 0xD7, 0x09, 0x34, 0x6A, 0x28, 0x5E, 0xCB, 0xF1, + 0xD6, 0x49, 0x8F, 0x30, 0xB1, 0x2C, 0x5A, 0xE7, + 0x1A, 0xD0, 0x69, 0x87, 0x4F, 0xE3, 0xB5, 0x2C, + /* S-box 4 */ + 0x7D, 0xE3, 0x06, 0x9A, 0x12, 0x85, 0xBC, 0x4F, + 0xD8, 0xB5, 0x6F, 0x03, 0x47, 0x2C, 0x1A, 0xE9, + 0xA6, 0x90, 0xCB, 0x7D, 0xF1, 0x3E, 0x52, 0x84, + 0x3F, 0x06, 0xA1, 0xD8, 0x94, 0x5B, 0xC7, 0x2E, + /* S-box 5 */ + 0x2C, 0x41, 0x7A, 0xB6, 0x85, 0x3F, 0xD0, 0xE9, + 0xEB, 0x2C, 0x47, 0xD1, 0x50, 0xFA, 0x39, 0x86, + 0x42, 0x1B, 0xAD, 0x78, 0xF9, 0xC5, 0x63, 0x0E, + 0xB8, 0xC7, 0x1E, 0x2D, 0x6F, 0x09, 0xA4, 0x53, + /* S-box 6 */ + 0xC1, 0xAF, 0x92, 0x68, 0x0D, 0x34, 0xE7, 0x5B, + 0xAF, 0x42, 0x7C, 0x95, 0x61, 0xDE, 0x0B, 0x38, + 0x9E, 0xF5, 0x28, 0xC3, 0x70, 0x4A, 0x1D, 0xB6, + 0x43, 0x2C, 0x95, 0xFA, 0xBE, 0x17, 0x60, 0x8D, + /* S-box 7 */ + 0x4B, 0x2E, 0xF0, 0x8D, 0x3C, 0x97, 0x5A, 0x61, + 0xD0, 0xB7, 0x49, 0x1A, 0xE3, 0x5C, 0x2F, 0x86, + 0x14, 0xBD, 0xC3, 0x7E, 0xAF, 0x68, 0x05, 0x92, + 0x6B, 0xD8, 0x14, 0xA7, 0x95, 0x0F, 0xE2, 0x3C, + /* S-box 8 */ + 0xD2, 0x84, 0x6F, 0xB1, 0xA9, 0x3E, 0x50, 0xC7, + 0x1F, 0xD8, 0xA3, 0x74, 0xC5, 0x6B, 0x0E, 0x92, + 0x7B, 0x41, 0x9C, 0xE2, 0x06, 0xAD, 0xF3, 0x58, + 0x21, 0xE7, 0x4A, 0x8D, 0xFC, 0x90, 0x35, 0x6B +}; + +const uint8_t e_permtab[] ={ + 4, 6, /* 4 bytes in 6 bytes out*/ + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1 +}; + +const uint8_t p_permtab[] ={ + 4, 4, /* 32 bit -> 32 bit */ + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 +}; + +const uint8_t ip_permtab[] ={ + 8, 8, /* 64 bit -> 64 bit */ + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +const uint8_t inv_ip_permtab[] ={ + 8, 8, /* 64 bit -> 64 bit */ + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; + +const uint8_t pc1_permtab[] ={ + 8, 7, /* 64 bit -> 56 bit*/ + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 +}; + +const uint8_t pc2_permtab[] ={ + 7, 6, /* 56 bit -> 48 bit */ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 +}; + +const uint8_t splitin6bitword_permtab[] = { + 8, 8, /* 64 bit -> 64 bit */ + 64, 64, 1, 6, 2, 3, 4, 5, + 64, 64, 7, 12, 8, 9, 10, 11, + 64, 64, 13, 18, 14, 15, 16, 17, + 64, 64, 19, 24, 20, 21, 22, 23, + 64, 64, 25, 30, 26, 27, 28, 29, + 64, 64, 31, 36, 32, 33, 34, 35, + 64, 64, 37, 42, 38, 39, 40, 41, + 64, 64, 43, 48, 44, 45, 46, 47 +}; + +const uint8_t shiftkey_permtab[] = { + 7, 7, /* 56 bit -> 56 bit */ + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 1, + 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 29 +}; + +const uint8_t shiftkeyinv_permtab[] = { + 7, 7, + 28, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, + 56, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55 +}; + +/* +1 0 +1 0 +2 1 +2 1 +2 1 +2 1 +2 1 +2 1 +---- +1 0 +2 1 +2 1 +2 1 +2 1 +2 1 +2 1 +1 0 +*/ +#define ROTTABLE 0x7EFC +#define ROTTABLE_INV 0x3F7E +/******************************************************************************/ + +void permute(const uint8_t *ptable, const uint8_t *in, uint8_t *out){ + uint8_t ob; /* in-bytes and out-bytes */ + uint8_t byte, bit; /* counter for bit and byte */ + ob = ptable[1]; + ptable = &(ptable[2]); + for(byte=0; byte>(x%8)) ){ + t|=0x01; + } + } + out[byte]=t; + } +} + +/******************************************************************************/ + +void changeendian32(uint32_t * a){ + *a = (*a & 0x000000FF) << 24 | + (*a & 0x0000FF00) << 8 | + (*a & 0x00FF0000) >> 8 | + (*a & 0xFF000000) >> 24; +} + +/******************************************************************************/ +static inline +void shiftkey(uint8_t *key){ + uint8_t k[7]; + memcpy(k, key, 7); + permute((uint8_t*)shiftkey_permtab, k, key); +} + +/******************************************************************************/ +static inline +void shiftkey_inv(uint8_t *key){ + uint8_t k[7]; + memcpy(k, key, 7); + permute((uint8_t*)shiftkeyinv_permtab, k, key); + +} + +/******************************************************************************/ +static inline +uint64_t splitin6bitwords(uint64_t a){ + uint64_t ret=0; + a &= 0x0000ffffffffffffLL; + permute((uint8_t*)splitin6bitword_permtab, (uint8_t*)&a, (uint8_t*)&ret); + return ret; +} + +/******************************************************************************/ + +static inline +uint8_t substitute(uint8_t a, uint8_t * sbp){ + uint8_t x; + x = sbp[a>>1]; + x = (a&1)?x&0x0F:x>>4; + return x; + +} + +/******************************************************************************/ + +uint32_t des_f(uint32_t r, uint8_t* kr){ + uint8_t i; + uint32_t t=0,ret; + uint64_t data; + uint8_t *sbp; /* sboxpointer */ + permute((uint8_t*)e_permtab, (uint8_t*)&r, (uint8_t*)&data); + for(i=0; i<7; ++i) + ((uint8_t*)&data)[i] ^= kr[i]; + + /* Sbox substitution */ + data = splitin6bitwords(data); + sbp=(uint8_t*)sbox; + for(i=0; i<8; ++i){ + uint8_t x; + x = substitute(((uint8_t*)&data)[i], sbp); + t<<=4; + t |= x; + sbp += 32; + } + changeendian32(&t); + + permute((uint8_t*)p_permtab,(uint8_t*)&t, (uint8_t*)&ret); + + return ret; +} + +/******************************************************************************/ + +void des_enc(void* out, const void* in, const void* key){ +#define R *((uint32_t*)&(data[4])) +#define L *((uint32_t*)&(data[0])) + + uint8_t data[8],kr[6],k[7]; + uint8_t i; + + permute((uint8_t*)ip_permtab, (uint8_t*)in, data); + permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k); + for(i=0; i<8; ++i){ + shiftkey(k); + if(ROTTABLE&((1<<((i<<1)+0))) ) + shiftkey(k); + permute((uint8_t*)pc2_permtab, k, kr); + L ^= des_f(R, kr); + + shiftkey(k); + if(ROTTABLE&((1<<((i<<1)+1))) ) + shiftkey(k); + permute((uint8_t*)pc2_permtab, k, kr); + R ^= des_f(L, kr); + + } + /* L <-> R*/ + R ^= L; + L ^= R; + R ^= L; + + permute((uint8_t*)inv_ip_permtab, data, (uint8_t*)out); +} + +/******************************************************************************/ + +void des_dec(void* out, const void* in, const uint8_t* key){ +#define R *((uint32_t*)&(data[4])) +#define L *((uint32_t*)&(data[0])) + + uint8_t data[8],kr[6],k[7]; + int8_t i; + permute((uint8_t*)ip_permtab, (uint8_t*)in, data); + permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k); + for(i=7; i>=0; --i){ + + permute((uint8_t*)pc2_permtab, k, kr); + L ^= des_f(R, kr); + shiftkey_inv(k); + if(ROTTABLE&((1<<((i<<1)+1))) ){ + shiftkey_inv(k); + } + + permute((uint8_t*)pc2_permtab, k, kr); + R ^= des_f(L, kr); + shiftkey_inv(k); + if(ROTTABLE&((1<<((i<<1)+0))) ){ + shiftkey_inv(k); + } + + } + /* L <-> R*/ + R ^= L; + L ^= R; + R ^= L; + + permute((uint8_t*)inv_ip_permtab, data, (uint8_t*)out); +} + +/******************************************************************************/ + +void tdes_enc(void* out, void* in, const void* key){ + des_enc(out, in, (uint8_t*)key + 0); + des_dec(out, out, (uint8_t*)key + 8); + des_enc(out, out, (uint8_t*)key +16); +} + +/******************************************************************************/ + +void tdes_dec(void* out, void* in, const uint8_t* key){ + des_dec(out, in, (uint8_t*)key +16); + des_enc(out, out, (uint8_t*)key + 8); + des_dec(out, out, (uint8_t*)key + 0); +} + +/******************************************************************************/ + + diff --git a/armsrc/des.h b/armsrc/des.h new file mode 100644 index 00000000..652886fd --- /dev/null +++ b/armsrc/des.h @@ -0,0 +1,107 @@ +/* des.h */ +/* + This file is part of the ARM-Crypto-Lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** + * \file des.h + * \author Daniel Otte + * \date 2007-06-16 + * \brief des and tdes declarations + * \license GPLv3 or later + * + */ +#ifndef DES_H_ +#define DES_H_ + +/* the FIPS 46-3 (1999-10-25) name for triple DES is triple data encryption algorithm so TDEA. + * Also we only implement the three key mode */ + +/** \def tdea_enc + * \brief defining an alias for void tdes_enc(void* out, const void* in, const void* key) + */ + +/** \def tdea_dec + * \brief defining an alias for void tdes_dec(void* out, const void* in, const void* key) + */ + +#define tdea_enc tdes_enc +#define tdea_dec tdes_dec + +/** \fn void des_enc(void* out, const void* in, const void* key) + * \brief encrypt a block with DES + * + * This function encrypts a block of 64 bits (8 bytes) with the DES algorithm. + * Key expansion is done automatically. The key is 64 bits long, but note that + * only 56 bits are used (the LSB of each byte is dropped). The input and output + * blocks may overlap. + * + * \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to + * \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from + * \param key pointer to the key (64 bit = 8 byte) + */ +void des_enc(void* out, const void* in, const void* key); + +/** \fn void des_dec(void* out, const void* in, const void* key) + * \brief decrypt a block with DES + * + * This function decrypts a block of 64 bits (8 bytes) with the DES algorithm. + * Key expansion is done automatically. The key is 64 bits long, but note that + * only 56 bits are used (the LSB of each byte is dropped). The input and output + * blocks may overlap. + * + * \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to + * \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from + * \param key pointer to the key (64 bit = 8 byte) + */ +void des_dec(void* out, const void* in, const void* key); + +/** \fn void tdes_enc(void* out, const void* in, const void* key) + * \brief encrypt a block with Tripple-DES + * + * This function encrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE) + * algorithm. Key expansion is done automatically. The key is 192 bits long, but + * note that only 178 bits are used (the LSB of each byte is dropped). The input + * and output blocks may overlap. + * + * \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to + * \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from + * \param key pointer to the key (192 bit = 24 byte) + */ +void tdes_enc(void* out, const void* in, const void* key); + +/** \fn void tdes_dec(void* out, const void* in, const void* key) + * \brief decrypt a block with Tripple-DES + * + * This function decrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE) + * algorithm. Key expansion is done automatically. The key is 192 bits long, but + * note that only 178 bits are used (the LSB of each byte is dropped). The input + * and output blocks may overlap. + * + * \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to + * \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from + * \param key pointer to the key (192 bit = 24 byte) + */ + void tdes_dec(void* out, const void* in, const void* key); + +#endif /*DES_H_*/ + +// Copied from des.h in desfire imp. +typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */ +typedef unsigned long DES3_KS[48][2]; /* Triple-DES key schedule */ + + +extern int Asmversion; /* 1 if we're linked with an asm version, 0 if C */ diff --git a/armsrc/desfire_crypto.c b/armsrc/desfire_crypto.c new file mode 100644 index 00000000..b77ad8ef --- /dev/null +++ b/armsrc/desfire_crypto.c @@ -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 + * + * $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 + printf ("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 + printf ("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 + printf ("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 index 00000000..d580ccc8 --- /dev/null +++ b/armsrc/desfire_crypto.h @@ -0,0 +1,15 @@ +#ifndef __DESFIRE_CRYPTO_H +#define __DESFIRE_CRYPTO_H + +#include +#include +#include +#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 index 00000000..b829013e --- /dev/null +++ b/armsrc/desfire_key.c @@ -0,0 +1,158 @@ +/*- + * 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 + * + * $Id$ + */ + + #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)); + // } +} + +desfirekey_t Desfire_des_key_new (const uint8_t value[8]) { + uint8_t data[8]; + memcpy (data, value, 8); + for (int n=0; n < 8; n++) + data[n] &= 0xfe; + return Desfire_des_key_new_with_version (data); +} + +desfirekey_t Desfire_des_key_new_with_version (const uint8_t value[8]) { + desfirekey_t key = NULL; + key->type = T_DES; + memcpy (key->data, value, 8); + memcpy (key->data+8, value, 8); + update_key_schedules (key); + return key; +} + +desfirekey_t Desfire_3des_key_new (const uint8_t value[16]) { + 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; + return Desfire_3des_key_new_with_version (data); +} + +desfirekey_t Desfire_3des_key_new_with_version (const uint8_t value[16]) { + desfirekey_t key = NULL; + key->type = T_3DES; + memcpy (key->data, value, 16); + update_key_schedules (key); + return key; +} + +desfirekey_t Desfire_3k3des_key_new (const uint8_t value[24]) { + uint8_t data[24]; + memcpy (data, value, 24); + for (int n=0; n < 8; n++) + data[n] &= 0xfe; + return Desfire_3k3des_key_new_with_version (data); +} + +desfirekey_t Desfire_3k3des_key_new_with_version (const uint8_t value[24]) { + desfirekey_t key = NULL; + key->type = T_3K3DES; + memcpy (key->data, value, 24); + update_key_schedules (key); + return key; +} + +desfirekey_t Desfire_aes_key_new (const uint8_t value[16]) { + return Desfire_aes_key_new_with_version (value, 0); +} + +desfirekey_t Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version) { + desfirekey_t key = NULL; + memcpy (key->data, value, 16); + key->type = T_AES; + key->aes_version = version; + return key; +} + +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; + } + } +} + +desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey) { + + desfirekey_t key = NULL; + + uint8_t buffer[24]; + + switch (authkey->type) { + case T_DES: + memcpy (buffer, rnda, 4); + memcpy (buffer+4, rndb, 4); + key = Desfire_des_key_new_with_version (buffer); + 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); + key = Desfire_3des_key_new_with_version (buffer); + 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); + key = Desfire_3k3des_key_new (buffer); + 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); + key = Desfire_aes_key_new (buffer); + break; + } + return key; +} \ No newline at end of file diff --git a/armsrc/desfire_key.h b/armsrc/desfire_key.h new file mode 100644 index 00000000..ae1249b4 --- /dev/null +++ b/armsrc/desfire_key.h @@ -0,0 +1,10 @@ +#ifndef __DESFIRE_KEY_H +#define __DESFIRE_KEY_H + +#include +#include +#include + +#include "iso14443a.h" +#include "../common/desfire.h" +#endif \ No newline at end of file diff --git a/armsrc/epa.c b/armsrc/epa.c index b0ae5e0d..565019ce 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -13,7 +13,7 @@ #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 diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 077b378a..32e0500e 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -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" diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 9181a62e..7d6668eb 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -16,10 +16,10 @@ // (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" static bool bQuiet; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index d5cd366d..f71607d2 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -36,15 +36,18 @@ // //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" #include "common.h" +#include "cmd.h" // Needed for CRC in emulation mode; // same construction as in ISO 14443; // different initial value (CRC_ICLASS) -#include "iso14443crc.h" +#include "../common/iso14443crc.h" +#include "../common/iso15693tools.h" + static int timeout = 4096; @@ -1167,12 +1170,11 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader } else if(receivedCmd[0] == 0x05) { // Reader random and reader MAC!!! // Do not respond - // We do not know what to answer, so lets keep quit + // We do not know what to answer, so lets keep quiet resp = resp1; respLen = 0; //order = 5; respdata = NULL; respsize = 0; if (breakAfterMacReceived){ - // TODO, actually return this to the caller instead of just // 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, @@ -1465,38 +1467,138 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer) return Demod.len; } +void setupIclassReader() +{ + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Reset trace buffer + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); + + // Setup SSC + FpgaSetupSsc(); + // Start from off (no field generated) + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + SpinDelay(200); + LED_A_ON(); + +} + // Reader iClass Anticollission void ReaderIClass(uint8_t arg0) { uint8_t act_all[] = { 0x0a }; uint8_t identify[] = { 0x0c }; uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[]= { 0x88, 0x02 }; + + uint8_t card_data[24]={0}; + uint8_t last_csn[8]={0}; uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + int read_status= 0; + bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; - // Reset trace buffer - memset(trace, 0x44, RECV_CMD_OFFSET); - traceLen = 0; + setupIclassReader(); - // Setup SSC - FpgaSetupSsc(); - // Start from off (no field generated) - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + size_t datasize = 0; + while(!BUTTON_PRESS()) + { + WDT_HIT(); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // Send act_all + ReaderTransmitIClass(act_all, 1); + // Card present? + if(ReaderReceiveIClass(resp)) { - // Now give it time to spin up. - // Signal field is on with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - SpinDelay(200); + ReaderTransmitIClass(identify, 1); - LED_A_ON(); + if(ReaderReceiveIClass(resp) == 10) { + //Copy the Anti-collision CSN to our select-packet + memcpy(&select[1],resp,8); + //Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2], + // resp[3], resp[4], resp[5], + // resp[6], resp[7]); + //Select the card + ReaderTransmitIClass(select, sizeof(select)); - for(;;) { + if(ReaderReceiveIClass(resp) == 10) { + //Save CSN in response data + memcpy(card_data,resp,8); + datasize += 8; + //Flag that we got to at least stage 1, read CSN + read_status = 1; + + // Card selected + //Dbprintf("Readcheck on Sector 2"); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + //Save CC (e-purse) in response data + memcpy(card_data+8,resp,8); + datasize += 8; + //Got both + read_status = 2; + } + + LED_B_ON(); + //Send back to client, but don't bother if we already sent this + if(memcmp(last_csn, card_data, 8) != 0) + cmd_send(CMD_ACK,read_status,0,0,card_data,datasize); + + //Save that we already sent this.... + if(read_status == 2) + memcpy(last_csn, card_data, 8); + + LED_B_OFF(); + + if(abort_after_read) break; + } + } + } + + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); + break; + } + } + LED_A_OFF(); +} + +void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { + uint8_t act_all[] = { 0x0a }; + uint8_t identify[] = { 0x0c }; + uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[]= { 0x88, 0x02 }; + uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; + + uint16_t crc = 0; + uint8_t cardsize=0; + bool read_success=false; + uint8_t mem=0; + + static struct memory_t{ + int k16; + int book; + int k2; + int lockauth; + int keyaccess; + } memory; + + uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + + setupIclassReader(); + + + for(int i=0;i<1;i++) { if(traceLen > TRACE_SIZE) { DbpString("Trace full"); @@ -1521,7 +1623,72 @@ void ReaderIClass(uint8_t arg0) { resp[3], resp[4], resp[5], resp[6], resp[7]); } - // Card selected, whats next... ;-) + // Card selected + Dbprintf("Readcheck on Sector 2"); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + }else return; + Dbprintf("Authenticate"); + //for now replay captured auth (as cc not updated) + memcpy(check+5,MAC,4); + //Dbprintf(" AA: %02x %02x %02x %02x", + // check[5], check[6], check[7],check[8]); + ReaderTransmitIClass(check, sizeof(check)); + if(ReaderReceiveIClass(resp) == 4) { + Dbprintf(" AR: %02x %02x %02x %02x", + resp[0], resp[1], resp[2],resp[3]); + }else { + Dbprintf("Error: Authentication Fail!"); + return; + } + Dbprintf("Dump Contents"); + //first get configuration block + read_success=false; + read[1]=1; + uint8_t *blockno=&read[1]; + crc = iclass_crc16((char *)blockno,1); + read[2] = crc >> 8; + read[3] = crc & 0xff; + while(!read_success){ + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 10) { + read_success=true; + mem=resp[5]; + memory.k16= (mem & 0x80); + memory.book= (mem & 0x20); + memory.k2= (mem & 0x8); + memory.lockauth= (mem & 0x2); + memory.keyaccess= (mem & 0x1); + + } + } + if (memory.k16){ + cardsize=255; + }else cardsize=32; + //then loop around remaining blocks + for(uint8_t j=0; j> 8; + read[3] = crc & 0xff; + while(!read_success){ + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 10) { + read_success=true; + Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", + j, resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + } + } } } WDT_HIT(); @@ -1530,4 +1697,130 @@ void ReaderIClass(uint8_t arg0) { LED_A_OFF(); } +//2. Create Read method (cut-down from above) based off responses from 1. +// Since we have the MAC could continue to use replay function. +//3. Create Write method +/* +void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, uint8_t *MAC) { + uint8_t act_all[] = { 0x0a }; + uint8_t identify[] = { 0x0c }; + uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[]= { 0x88, 0x02 }; + uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; + uint8_t write[] = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + uint16_t crc = 0; + + uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + // Reset trace buffer + memset(trace, 0x44, RECV_CMD_OFFSET); + traceLen = 0; + + // Setup SSC + FpgaSetupSsc(); + // Start from off (no field generated) + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + SpinDelay(200); + + LED_A_ON(); + + for(int i=0;i<1;i++) { + + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); + break; + } + + if (BUTTON_PRESS()) break; + + // Send act_all + ReaderTransmitIClass(act_all, 1); + // Card present? + if(ReaderReceiveIClass(resp)) { + ReaderTransmitIClass(identify, 1); + if(ReaderReceiveIClass(resp) == 10) { + // Select card + memcpy(&select[1],resp,8); + ReaderTransmitIClass(select, sizeof(select)); + + if(ReaderReceiveIClass(resp) == 10) { + Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + // Card selected + Dbprintf("Readcheck on Sector 2"); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + }else return; + Dbprintf("Authenticate"); + //for now replay captured auth (as cc not updated) + memcpy(check+5,MAC,4); + Dbprintf(" AA: %02x %02x %02x %02x", + check[5], check[6], check[7],check[8]); + ReaderTransmitIClass(check, sizeof(check)); + if(ReaderReceiveIClass(resp) == 4) { + Dbprintf(" AR: %02x %02x %02x %02x", + resp[0], resp[1], resp[2],resp[3]); + }else { + Dbprintf("Error: Authentication Fail!"); + return; + } + Dbprintf("Write Block"); + + //read configuration for max block number + read_success=false; + read[1]=1; + uint8_t *blockno=&read[1]; + crc = iclass_crc16((char *)blockno,1); + read[2] = crc >> 8; + read[3] = crc & 0xff; + while(!read_success){ + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 10) { + read_success=true; + mem=resp[5]; + memory.k16= (mem & 0x80); + memory.book= (mem & 0x20); + memory.k2= (mem & 0x8); + memory.lockauth= (mem & 0x2); + memory.keyaccess= (mem & 0x1); + + } + } + if (memory.k16){ + cardsize=255; + }else cardsize=32; + //check card_size + + memcpy(write+1,blockNo,1); + memcpy(write+2,data,8); + memcpy(write+10,mac,4); + while(!send_success){ + ReaderTransmitIClass(write, sizeof(write)); + if(ReaderReceiveIClass(resp) == 10) { + write_success=true; + } + }// + } + WDT_HIT(); + } + + LED_A_OFF(); +}*/ diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c index 7a445bcb..bc7b9b16 100644 --- a/armsrc/iso14443.c +++ b/armsrc/iso14443.c @@ -10,12 +10,12 @@ // supported. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" //static void GetSamplesFor14443(int weTx, int n); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 9a80a177..0cd9053b 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -10,13 +10,12 @@ // Routines to support ISO 14443 type A. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "cmd.h" - -#include "iso14443crc.h" +#include "../common/cmd.h" +#include "../common/iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" @@ -1616,6 +1615,13 @@ int ReaderReceive(uint8_t* receivedAnswer) return ReaderReceiveOffset(receivedAnswer, 0); } +int ReaderReceiveDesfiresAuthTiming(uint8_t *receivedAnswer, uint32_t *elapsedTime) +{ + int len = ReaderReceiveOffset(receivedAnswer, 0); + *elapsedTime = (Demod.endTime*16 - DELAY_AIR2ARM_AS_READER) - (Demod.startTime*16 - DELAY_AIR2ARM_AS_READER); + return len; +} + int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr) { if (!GetIso14443aAnswerFromTag(receivedAnswer,0,160)) return FALSE; @@ -1787,7 +1793,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(1050); // 10ms default 10*105 = } int iso14_apdu(uint8_t * cmd, size_t cmd_len, void * data) { @@ -1825,8 +1831,8 @@ void ReaderIso14443a(UsbCommand *c) { iso14a_command_t param = c->arg[0]; uint8_t *cmd = c->d.asBytes; - size_t len = c->arg[1]; - size_t lenbits = c->arg[2]; + size_t len = c->arg[1] & 0xFFFF; + size_t lenbits = c->arg[1] >> 16; uint32_t arg0 = 0; byte_t buf[USB_CMD_DATA_SIZE]; @@ -1862,9 +1868,10 @@ void ReaderIso14443a(UsbCommand *c) if(param & ISO14A_APPEND_CRC) { AppendCrc14443a(cmd,len); len += 2; - if (lenbits) lenbits += 16; + lenbits += 16; } if(lenbits>0) { + ReaderTransmitBitsPar(cmd,lenbits,GetParity(cmd,lenbits/8), NULL); } else { ReaderTransmit(cmd,len, NULL); @@ -2206,12 +2213,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (MF_DBGLEVEL >= 1) { if (!_7BUID) { - Dbprintf("4B UID: %02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]); + Dbprintf("4B UID: %02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3]); } else { - Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], - rUIDBCC2[0], rUIDBCC2[1] ,rUIDBCC2[2], rUIDBCC2[3]); + Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3],rUIDBCC2[0],rUIDBCC2[1] ,rUIDBCC2[2] , rUIDBCC2[3]); } } @@ -2321,9 +2325,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // 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)); + if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x",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 diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 6d18515f..af650a9e 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -12,7 +12,7 @@ #ifndef __ISO14443A_H #define __ISO14443A_H -#include "common.h" +#include "../include/common.h" #include "mifaresniff.h" // mifare reader over DMA buffer (SnoopIso14443a())!!! @@ -84,6 +84,7 @@ extern void ReaderTransmitBitsPar(uint8_t *frame, int bits, uint32_t par, uint32 extern void ReaderTransmitPar(uint8_t *frame, int len, uint32_t par, uint32_t *timing); extern int ReaderReceive(uint8_t *receivedAnswer); extern int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr); +extern int ReaderReceiveDesfiresAuthTiming(uint8_t *receivedAnswer, uint32_t *elapsedTime); extern void iso14443a_setup(uint8_t fpga_minor_mode); extern int iso14_apdu(uint8_t *cmd, size_t cmd_len, void *data); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index ed7beb6f..39d9effb 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -58,12 +58,12 @@ // *) document all the functions -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "util.h" #include "apps.h" #include "string.h" -#include "iso15693tools.h" -#include "cmd.h" +#include "../common/iso15693tools.h" +#include "../common/cmd.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) @@ -1275,12 +1275,8 @@ void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8 recvlen=SendDataTag(data,datalen,1,speed,(recv?&recvbuf:NULL)); if (recv) { -// n.cmd=/* CMD_ISO_15693_COMMAND_DONE */ CMD_ACK; -// n.arg[0]=recvlen>48?48:recvlen; -// memcpy(n.d.asBytes, recvbuf, 48); LED_B_ON(); cmd_send(CMD_ACK,recvlen>48?48:recvlen,0,0,recvbuf,48); -// UsbSendPacket((uint8_t *)&n, sizeof(n)); LED_B_OFF(); if (DEBUG) { diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 3fbdf5cb..0e63ef5e 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -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; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 6b131c26..11fc8c50 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -8,12 +8,14 @@ // Also routines for raw mode reading/simulating of LF waveform //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" -#include "hitag2.h" -#include "crc16.h" +#include "../include/hitag2.h" +#include "../common/crc16.h" #include "string.h" +#include "crapto1.h" +#include "mifareutil.h" void LFSetupFPGAForADC(int divisor, bool lf_field) { @@ -1146,6 +1148,15 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define WRITE_0 144 // 192 #define WRITE_1 400 // 432 for T55x7; 448 for E5550 +// VALUES TAKEN FROM EM4x function: SendForward +// START_GAP = 440; //(55*8) +// WRITE_GAP = 128; //(16*8) +// WRITE_1 = 256 32*8; //32 cycles at 125Khz (8us each) 1 +// //These timings work for 4469/4269/4305 (with the 55*8 above) +// WRITE_0 = 23*8 , 9*8 SpinDelayUs(23*8); // (8us each) 0 + + + // Write one bit to card void T55xxWriteBit(int bit) { @@ -1207,13 +1218,15 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod // Read one card block in page 0 void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) { - uint8_t *dest = (uint8_t *)BigBuf; - int m=0, i=0; + uint8_t *dest = mifare_get_bigbufptr(); + uint16_t bufferlength = 16000; + uint32_t i = 0; + + // Clear destination buffer before sending the command 0x80 = average. + memset(dest, 0x80, bufferlength); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - m = sizeof(BigBuf); - // 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. @@ -1254,31 +1267,33 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - // we don't care about actual value, only if it's more or less than a - // threshold essentially we capture zero crossings for later analysis - // if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; - i++; - if (i >= m) break; + LED_D_OFF(); + ++i; + if (i > bufferlength) break; } } + + cmd_send(CMD_ACK,0,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); - DbpString("DONE!"); } // Read card traceability data (page 1) void T55xxReadTrace(void){ - uint8_t *dest = (uint8_t *)BigBuf; - int m=0, i=0; + uint8_t *dest = mifare_get_bigbufptr(); + uint16_t bufferlength = 16000; + int i=0; + + // Clear destination buffer before sending the command 0x80 = average + memset(dest, 0x80, bufferlength); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - m = sizeof(BigBuf); - // 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. @@ -1309,17 +1324,20 @@ void T55xxReadTrace(void){ for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - i++; - if (i >= m) break; + LED_D_OFF(); + ++i; + if (i >= bufferlength) break; } } + cmd_send(CMD_ACK,0,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); - DbpString("DONE!"); } /*-------------- Cloning routines -----------*/ @@ -1763,7 +1781,6 @@ int IsBlock1PCF7931(uint8_t *Block) { return 0; } - #define ALLOC 16 void ReadPCF7931() { @@ -2023,6 +2040,7 @@ void SendForward(uint8_t fwd_bit_count) { } } + void EM4xLogin(uint32_t Password) { uint8_t fwd_bit_count; @@ -2040,9 +2058,14 @@ void EM4xLogin(uint32_t Password) { void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { + uint8_t *dest = mifare_get_bigbufptr(); + uint16_t bufferlength = 16000; + uint32_t i = 0; + + // Clear destination buffer before sending the command 0x80 = average. + memset(dest, 0x80, bufferlength); + uint8_t fwd_bit_count; - uint8_t *dest = (uint8_t *)BigBuf; - int m=0, i=0; //If password mode do login if (PwdMode == 1) EM4xLogin(Pwd); @@ -2051,9 +2074,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 = sizeof(BigBuf); - // 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. @@ -2069,10 +2089,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(); } diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 6be5b383..ff853a57 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2,6 +2,9 @@ // Merlok - June 2011, 2012 // Gerhard de Koning Gans - May 2008 // Hagen Fritsch - June 2010 +// Midnitesnake - Dec 2013 +// Andy Davies - Apr 2014 +// Iceman - May 2014 // // 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 @@ -12,9 +15,12 @@ #include "mifarecmd.h" #include "apps.h" +#include "util.h" +#include "desfire.h" +#include "../common/crc.h" //----------------------------------------------------------------------------- -// Select, Authenticate, Read a MIFARE tag. +// Select, Authenticaate, Read an MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) @@ -78,7 +84,72 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); +} + +void MifareUC_Auth1(uint8_t arg0, uint8_t *datain){ + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card, something went wrong before auth"); + }; + + + + + if(mifare_ultra_auth1(cuid, dataoutbuf)){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part1: Fail."); + } + + isOK=1; + if (MF_DBGLEVEL >= 2) DbpString("AUTH 1 FINISHED"); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,cuid,0,dataoutbuf,11); + LED_B_OFF(); + + // Thats it... + LEDsoff(); +} +void MifareUC_Auth2(uint32_t arg0, uint8_t *datain){ + // params + uint32_t cuid = arg0; + uint8_t key[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + + memcpy(key, datain, 16); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + if(mifare_ultra_auth2(cuid, key, dataoutbuf)){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail..."); + } + isOK=1; + if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED"); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,11); + LED_B_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } void MifareUReadBlock(uint8_t arg0,uint8_t *datain) @@ -129,7 +200,6 @@ void MifareUReadBlock(uint8_t arg0,uint8_t *datain) LEDsoff(); } - //----------------------------------------------------------------------------- // Select, Authenticate, Read a MIFARE tag. // read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes) @@ -198,15 +268,15 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LEDsoff(); } - -void MifareUReadCard(uint8_t arg0, uint8_t *datain) +void MifareUReadCard(uint8_t arg0, int arg1, uint8_t *datain) { // params uint8_t sectorNo = arg0; - + int Pages=arg1; + int count_Pages=0; // variables byte_t isOK = 0; - byte_t dataoutbuf[16 * 4]; + byte_t dataoutbuf[44 * 4]; uint8_t uid[10]; uint32_t cuid; @@ -218,16 +288,18 @@ void MifareUReadCard(uint8_t arg0, uint8_t *datain) LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - + Dbprintf("Pages %d",Pages); while (true) { if(!iso14443a_select_card(uid, NULL, &cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; - for(int sec=0;sec<16;sec++){ + for(int sec=0;sec= 1) Dbprintf("Read block %d error",sec); break; + }else{ + count_Pages++; }; } if(mifare_ultra_halt(cuid)) { @@ -238,11 +310,13 @@ void MifareUReadCard(uint8_t arg0, uint8_t *datain) isOK = 1; break; } - + Dbprintf("Pages read %d",count_Pages); if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); + if (Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); + if (Pages==44 && count_Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); + if (Pages==44 && count_Pages>16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,176); LED_B_OFF(); // Thats it... diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 3c00a343..2c5a7e3f 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -13,16 +13,15 @@ #ifndef __MIFARECMD_H #define __MIFARECMD_H -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" -#include "common.h" - +#include "../include/common.h" #endif \ No newline at end of file diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c new file mode 100644 index 00000000..d3b04fb0 --- /dev/null +++ b/armsrc/mifaredesfire.c @@ -0,0 +1,568 @@ +#include "mifaredesfire.h" + +#define MAX_APPLICATION_COUNT 28 +#define MAX_FILE_COUNT 16 +#define MAX_FRAME_SIZE 60 +#define NOT_YET_AUTHENTICATED 255 +#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) + +//static uint8_t __msg[MAX_FRAME_SIZE] = { 0x0A, 0x00, 0x00, /* ..., */ 0x00 }; +/* PCB CID CMD PAYLOAD */ +//static uint8_t __res[MAX_FRAME_SIZE]; + +void MifareDesfireGetInformation(){ + + + uint8_t len = 0; + uint8_t resp[RECV_RES_SIZE]; + uint8_t dataout[RECV_CMD_SIZE]; + byte_t buf[RECV_RES_SIZE]; + + memset(resp,0,sizeof(resp)); + memset(dataout,0, sizeof(dataout)); + memset(buf,0,sizeof(buf)); + + /* + 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? + + */ + uint8_t cmd1[] = {0x0a,0x00,GET_VERSION, 0x00, 0x00 }; + uint8_t cmd2[] = {0x0a,0x00,GET_KEY_VERSION, 0x00, 0x00, 0x00 }; + + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // card select - information + iso14a_card_select_t *card = (iso14a_card_select_t*)buf; + byte_t isOK = iso14443a_select_card(NULL, card, NULL); + if (isOK != 1) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("Can't select card"); + } + OnError(); + return; + } + + + memcpy(dataout,card->uid,7); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + // GET INFORMATION + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + if ( resp[2] != ADDITIONAL_FRAME) { + print_result("ERROR <--: ", resp, len); + OnError(); + return; + } + + memcpy(dataout+7,resp+3,7); + + // ADDITION_FRAME 1 + ++cmd1[0]; + cmd1[2] = ADDITIONAL_FRAME; + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + + if ( resp[2] != ADDITIONAL_FRAME) { + print_result("ERROR <--: ", resp, len); + OnError(); + return; + } + memcpy(dataout+7+7,resp+3,7); + + // ADDITION_FRAME 2 + --cmd1[0]; + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + if ( resp[2] != OPERATION_OK) { + print_result("ERROR <--: ", resp, len); + OnError(); + return; + } + + memcpy(dataout+7+7+7,resp+3,14); + + // GET MASTER KEYSETTINGS + cmd1[2] = GET_KEY_SETTINGS; + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + if (len){ + memcpy(dataout+7+7+7+14,resp+3,2); + } + + + // GET MASTER KEY VERSION + AppendCrc14443a(cmd2, 4); + ReaderTransmit(cmd2, sizeof(cmd2), NULL); + len = ReaderReceive(resp); + if (len){ + memcpy(dataout+7+7+7+14+2,resp+3,1); + } + + // GET FREE MEMORY + cmd1[2] = GET_FREE_MEMORY; + AppendCrc14443a(cmd1, 3); + ReaderTransmit(cmd1, sizeof(cmd1), NULL); + len = ReaderReceive(resp); + if (len){ + memcpy(dataout+7+7+7+14+2+1,resp+3,3); + } + + cmd_send(CMD_ACK,1,0,0,dataout,sizeof(dataout)); + OnSuccess(); +} + +void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain){ + + uint8_t null_key_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t new_key_data[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; + int res; + + MifareDESFireKey default_key = mifare_desfire_des_key_new_with_version (null_key_data); + + res = mifare_desfire_select_application (tags[i], aid); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_select_application"); + error = EXIT_FAILURE; + break; + } + + return; + // pcb cid cmd key crc1 cr2 + //uint8_t cmd2[] = {0x02,0x00,GET_KEY_VERSION, 0x00, 0x00, 0x00 }; + + //uint8_t* bigbuffer = mifare_get_bigbufptr(); + byte_t isOK = 1; + uint8_t resp[256]; + uint8_t key[24]; + uint8_t IV[16]; + + // första byten håller keylength. + uint8_t keylen = datain[0]; + memcpy(key, datain+1, keylen); + + if (MF_DBGLEVEL >= 1) { + + Dbprintf("MODE: %d", mode); + Dbprintf("ALGO: %d", algo); + Dbprintf("KEYNO: %d", keyno); + Dbprintf("KEYLEN: %d", keylen); + + print_result("KEY", key, keylen); + } + + // card select - information + byte_t buf[USB_CMD_DATA_SIZE]; + iso14a_card_select_t *card = (iso14a_card_select_t*)buf; + + // test of DES on ARM side. + /* + if ( mode == 1){ + uint8_t IV[8]; + uint8_t plain[16]; + uint8_t encData[16]; + + uint8_t tmpData[8]; + uint8_t tmpPlain[8]; + + memset(IV, 0, 8); + memset(tmpData, 0 ,8); + memset(tmpPlain,0 ,8); + memcpy(key, datain, 8); + memcpy(plain, datain+30, 16); + + for(uint8_t i=0; i< sizeof(plain); i=i+8 ){ + + memcpy(tmpPlain, plain+i, 8); + des_enc( &tmpData, &tmpPlain, &key); + memcpy(encData+i, tmpData, 8); + } + } +*/ + + iso14a_clear_trace(); + + iso14a_set_tracing(TRUE); + + // power up the field + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // select the card + isOK = iso14443a_select_card(resp, card, NULL); + if (isOK != 1) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("CAN'T SELECT CARD, SOMETHING WENT WRONG BEFORE AUTH"); + } + OnError(); + return; + } + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + // 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 ( SendDesfireCommand(AUTHENTICATE, &keyno, resp) > 0 ){ + // // fick nonce från kortet + // } + break; + case 2: + //SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp); + break; + case 3:{ + AesCtx ctx; + if ( AesCtxIni(&ctx, IV, key, KEY128, CBC) < 0 ){ + if (MF_DBGLEVEL >= 1) { + Dbprintf("AES context failed to init"); + } + OnError(); + return; + } + uint8_t real_cmd[6]; + real_cmd[0] = 0x90; + real_cmd[1] = 0x02; + real_cmd[2] = AUTHENTICATE_AES; + real_cmd[3] = keyno; + + AppendCrc14443a(real_cmd, 2); + ReaderTransmit(real_cmd, sizeof(real_cmd), NULL); + + int len = ReaderReceive(resp); + if(!len) { + OnError(); + return; + } + + print_result("RX:", resp, len); + + enum DESFIRE_STATUS status = resp[1]; + if ( status != ADDITIONAL_FRAME) { + OnError(); + return; + } + + // tags enc nonce + uint8_t encRndB[16]; + uint8_t decRndB[16]; + uint8_t nonce[16]; + uint8_t both[32]; + uint8_t encBoth[32]; + + memset(nonce, 0, 16); + memcpy( encRndB, resp+2, 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 ); + + uint8_t real_cmd_A[36]; + real_cmd_A[0] = 0x03; + real_cmd_A[1] = ADDITIONAL_FRAME; + + memcpy(real_cmd_A+2, encBoth, sizeof(encBoth) ); + AppendCrc14443a(real_cmd_A, sizeof(real_cmd_A)); + ReaderTransmit(real_cmd_A, sizeof(real_cmd_A), NULL); + + len = ReaderReceive(resp); + + print_result("Auth1a ", resp, 36); + + status = resp[1]; + if ( status != OPERATION_OK) { + Dbprintf("Cmd Error: %02x Len: %d", status,len); + OnError(); + return; + } + + break; + } + + } + + OnSuccess(resp); +} + + +// desfire_cmd = enum DESFIRE_CMD in desfire.h +// cmd = pointer to +// dataout = point to array for response data. +int SendDesfireCommand(enum DESFIRE_CMD desfire_cmd,uint8_t *dataout, uint8_t fromscratch){ + + uint8_t resp[80]; + uint8_t len; + + if ( fromscratch){ + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + // power up the field + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + // select the card + iso14443a_select_card(NULL, NULL, NULL); + } + + // 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat ISO) + uint8_t real_cmd[4]; + real_cmd[0] = 0x02; + real_cmd[1] = desfire_cmd; + AppendCrc14443a(real_cmd, 2); + ReaderTransmit(real_cmd, sizeof(real_cmd), NULL); + len = ReaderReceive(resp); + if(!len) + return -1; //DATA LINK ERROR + + if ( fromscratch){ + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + } + + enum DESFIRE_STATUS status = resp[1]; + //1 bytes iso, 1 byte status, in the end: 2 bytes crc + if ( status == OPERATION_OK || status == ADDITIONAL_FRAME) { + memcpy(dataout, resp+2, 2); + return len; + } + else { + Dbprintf("unexpected desfire response: %X (to %X)", status, desfire_cmd); + return -status; + } +} + + // 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); + + + /* Version + + //uint8_t versionCmd1[] = {0x02, 0x60}; + //uint8_t versionCmd2[] = {0x03, 0xaf}; + //uint8_t versionCmd3[] = {0x02, 0xaf}; + + // AUTH 1 - CMD: 0x02, 0x0A, 0x00 = Auth + // 0x02 = status byte för simpla svar?!? + // 0x0a = krypto typ + // 0x00 = key nr + //uint8_t initAuthCmdDES[] = {0x02, 0x0a, 0x00}; // DES + //uint8_t initAuthCmd3DES[] = {0x02, 0x1a, 0x00}; // 3DES + //uint8_t initAuthCmdAES[] = {0x02, 0xaa, 0x00}; // AES + // auth 1 - answer command + // 0x03 = status byte för komplexa typer? + // 0xaf = additional frame + // LEN = 1+1+32+2 = 36 + //uint8_t answerAuthCmd[34] = {0x03, 0xaf}; + + // Lägg till CRC + //AppendCrc14443a(versionCmd1,sizeof(versionCmd1)); +*/ + + // Sending commands + /*ReaderTransmit(versionCmd1,sizeof(versionCmd1)+2, NULL); + len = ReaderReceive(buffer); + print_result("Get Version 3", buffer, 9); + */ + + // for( int i = 0; i < 8; i++){ + // // Auth 1 - Request authentication + // ReaderTransmit(initAuthCmdAES,sizeof(initAuthCmdAES)+2, NULL); + // //len = ReaderReceive(buffer); + + // // 0xAE = authentication error + // if (buffer[1] == 0xae) { + // Dbprintf("Cmd Error: %02x", buffer[1]); + // OnError(); + // return; + // } + + // // tags enc nonce + // memcpy(encRndB, buffer+2, 16); + + // // dekryptera svaret från tag. + // AesDecrypt(&ctx, encRndB, decRndB, 16); + + // rol8(decRndB,16); + // memcpy(RndARndB, RndA,16); + // memcpy(RndARndB+16, decRndB ,16 ); + + // AesEncrypt(&ctx, RndARndB, encRndARndB, 32 ); + + // memcpy(answerAuthCmd+2, encRndARndB, 32); + // AppendCrc14443a(answerAuthCmd,sizeof(answerAuthCmd)); + + // ReaderTransmit(answerAuthCmd,sizeof(answerAuthCmd)+2, NULL); + + // len = ReaderReceive(buffer); + + // print_result("Auth1a ", buffer, 8); + // Dbprintf("Rx len: %02x", len); + + // if (buffer[1] == 0xCA) { + // Dbprintf("Cmd Error: %02x Len: %d", buffer[1],len); + // cmd_send(CMD_ACK,0,0,0,0,0); + // key[1] = i; + // AesCtxIni(&ctx, iv, key, KEY128, CBC); + // } + // } + + //des_dec(decRndB, encRndB, key); + + //Do crypto magic + /* + DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); + memcpy(RndARndB,RndA,8); + memcpy(RndARndB+8,RndB,8); + PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); + DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); + PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); + */ + + +int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ + + uint8_t* buffer = mifare_get_bigbufptr(); + uint8_t dcmd[19]; + + dcmd[0] = 0xAF; + memcpy(dcmd+1,key,16); + AppendCrc14443a(dcmd, 17); + + + ReaderTransmit(dcmd, sizeof(dcmd), NULL); + int len = ReaderReceive(buffer); + if(!len) { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + len = ReaderReceive(buffer); + } + + if(len==1) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("NAK - Authentication failed."); + Dbprintf("Cmd Error: %02x", buffer[0]); + } + return 1; + } + + if (len == 11){ + if (MF_DBGLEVEL >= 1) { + Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + buffer[0],buffer[1],buffer[2],buffer[3],buffer[4], + buffer[5],buffer[6],buffer[7],buffer[8],buffer[9], + buffer[10]); + } + return 0; + } + return 1; +} + +void MifareDES_Auth2(uint32_t arg0, uint8_t *datain){ + + return; + uint32_t cuid = arg0; + uint8_t key[16]; + + byte_t isOK = 0; + byte_t dataoutbuf[16]; + + memset(key, 0, 16); + memcpy(key, datain, 16); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + if(mifare_des_auth2(cuid, key, dataoutbuf)){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail..."); + } + isOK=1; + if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED"); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,11); + LED_B_OFF(); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +// CreateAPDU +uint8_t* CreateAPDU( uint8_t *datain, size_t len){ + + len = MIN(len, USB_CMD_DATA_SIZE); + + uint8_t tmpcmd[len]; + uint8_t *cmd = tmpcmd; + memset(cmd, 0, len); + cmd[0] = 0x0a; + cmd[1] = 0x00; + + memcpy(cmd, datain,len); + AppendCrc14443a(cmd, len+2); + return cmd; +} + +void SelectCard(){ + + uint8_t resp[RECV_RES_SIZE]; + byte_t buf[RECV_RES_SIZE]; + + memset(resp,0,sizeof(resp)); + memset(buf,0,sizeof(buf)); + + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // card select - information + iso14a_card_select_t *card = (iso14a_card_select_t*)buf; + byte_t isOK = iso14443a_select_card(NULL, card, NULL); + if (isOK != 1) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("Can't select card"); + } + OnError(); + return; + } +} + +void OnSuccess(){ + // Deselect card by sending a s-block. the crc is precalced for speed + uint8_t cmd[] = {0xc2,0xe0,0xb4}; + ReaderTransmit(cmd, sizeof(cmd), NULL); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +void OnError(){ + cmd_send(CMD_ACK,0,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} diff --git a/armsrc/mifaredesfire.h b/armsrc/mifaredesfire.h new file mode 100644 index 00000000..5d490e2e --- /dev/null +++ b/armsrc/mifaredesfire.h @@ -0,0 +1,16 @@ +#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 "crapto1.h" +#include "mifareutil.h" +#include "../include/common.h" + + +#endif diff --git a/armsrc/mifaresniff.h b/armsrc/mifaresniff.h index 1065fa61..3ee64f35 100644 --- a/armsrc/mifaresniff.h +++ b/armsrc/mifaresniff.h @@ -11,16 +11,16 @@ #ifndef __MIFARESNIFF_H #define __MIFARESNIFF_H -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" -#include "common.h" +#include "../include/common.h" #define SNF_INIT 0 #define SNF_NO_FIELD 1 diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 0b93db8f..537720df 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -9,12 +9,12 @@ // Work with mifare cards. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" @@ -84,26 +84,36 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *timing) { - uint8_t dcmd[8];//, ecmd[4]; - //uint32_t par=0; - + uint8_t dcmd[8]; dcmd[0] = cmd; - dcmd[1] = data[0]; - dcmd[2] = data[1]; - dcmd[3] = data[2]; - dcmd[4] = data[3]; - dcmd[5] = data[4]; + memcpy(dcmd+1,data,5); AppendCrc14443a(dcmd, 6); - //Dbprintf("Data command: %02x", dcmd[0]); - //Dbprintf("Data R: %02x %02x %02x %02x %02x %02x %02x", dcmd[1],dcmd[2],dcmd[3],dcmd[4],dcmd[5],dcmd[6],dcmd[7]); - - //memcpy(ecmd, dcmd, sizeof(dcmd)); ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer); - if(!len) - { + if(!len) { if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); return 2; + } + return len; +} + +int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint32_t *timing) +{ + uint8_t dcmd[19]; + int len; + dcmd[0] = cmd; + memcpy(dcmd+1,data,16); + AppendCrc14443a(dcmd, 17); + + ReaderTransmit(dcmd, sizeof(dcmd), timing); + len = ReaderReceive(answer); + if(!len) { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + len = ReaderReceive(answer); + } + if(len==1) { + if (MF_DBGLEVEL >= 1) Dbprintf("NAK - Authentication failed."); + return 1; } return len; } @@ -280,6 +290,55 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo memcpy(blockData, receivedAnswer, 16); return 0; +} + +int mifare_ultra_auth1(uint32_t uid, uint8_t *blockData){ + // variables + int len; + + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + // command MIFARE_CLASSIC_READBLOCK + len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, receivedAnswer,NULL); + if (len == 1) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + if (len == 11) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], + receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], + receivedAnswer[10]); + memcpy(blockData, receivedAnswer, 11); + return 0; + } + //else something went wrong??? + return 1; +} + +int mifare_ultra_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ + // variables + int len; + + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + + // command MIFARE_CLASSIC_READBLOCK + len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, key, receivedAnswer,NULL); + if (len == 1) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + if (len == 11){ + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], + receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], + receivedAnswer[10]); + memcpy(blockData, receivedAnswer, 11); + return 0; + } + //something went wrong? + return 1; } int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 8708d3dd..f9d74384 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -56,6 +56,7 @@ extern int MF_DBGLEVEL; uint8_t* mifare_get_bigbufptr(void); int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing); int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint8_t *timing); +int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint32_t *timing); int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing); int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \ @@ -63,6 +64,8 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, \ uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing); int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); +int mifare_ultra_auth1(uint32_t cuid, uint8_t *blockData); +int mifare_ultra_auth2(uint32_t cuid, uint8_t *key, uint8_t *blockData); int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); diff --git a/armsrc/start.c b/armsrc/start.c index d7332bda..3f5dc676 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -9,7 +9,7 @@ // with the linker script. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "apps.h" extern char __data_start__, __data_src_start__, __data_end__, __bss_start__, __bss_end__; diff --git a/armsrc/string.c b/armsrc/string.c index cc71276c..945a4cf6 100644 --- a/armsrc/string.c +++ b/armsrc/string.c @@ -48,6 +48,11 @@ int memcmp(const void *av, const void *bv, int len) return 0; } +void memxor(uint8_t * dest, uint8_t * src, size_t len) { + for( ; len > 0; len--,dest++,src++) + *dest ^= *src; +} + int strlen(const char *str) { int l = 0; diff --git a/armsrc/string.h b/armsrc/string.h index 46ee218d..1067b91f 100644 --- a/armsrc/string.h +++ b/armsrc/string.h @@ -12,10 +12,14 @@ #ifndef __STRING_H #define __STRING_H +#include +#include + int strlen(const char *str); void *memcpy(void *dest, const void *src, int len); void *memset(void *dest, int c, int len); int memcmp(const void *av, const void *bv, int len); +void memxor(uint8_t * dest, uint8_t * src, size_t len); char *strncat(char *dest, const char *src, unsigned int n); char *strcat(char *dest, const char *src); void strreverse(char s[]); diff --git a/armsrc/util.c b/armsrc/util.c index 2d3aab9c..f20e4b42 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -8,11 +8,31 @@ // Utility functions used in many places, not specific to any piece of code. //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include "util.h" #include "string.h" #include "apps.h" + + +void print_result(char *name, uint8_t *buf, size_t len) { + uint8_t *p = buf; + + if ( len % 16 == 0 ) { + for(; p-buf < len; p += 16) + Dbprintf("[%s:%02x/%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + name, + p-buf, + len, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] + ); + } + else { + for(; p-buf < len; p += 8) + Dbprintf("[%s:%02x/%02x] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + } +} + size_t nbytes(size_t nbits) { return (nbits/8)+((nbits%8)>0); } @@ -45,6 +65,26 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } +// RotateLeft - Ultralight, Desfire +void rol(uint8_t *data, const size_t len){ + uint8_t first = data[0]; + for (size_t i = 0; i < len-1; i++) { + data[i] = data[i+1]; + } + data[len-1] = first; +} +void lsl (uint8_t *data, size_t len) { + for (size_t n = 0; n < len - 1; n++) { + data[n] = (data[n] << 1) | (data[n+1] >> 7); + } + data[len - 1] <<= 1; +} + +int32_t le24toh (uint8_t data[3]) +{ + return (data[2] << 16) | (data[1] << 8) | data[0]; +} + void LEDsoff() { LED_A_OFF(); diff --git a/armsrc/util.h b/armsrc/util.h index e8b9cdff..c6503395 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -13,7 +13,7 @@ #include #include -#include +#include "../include/common.h" #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) @@ -27,10 +27,14 @@ #define BUTTON_DOUBLE_CLICK -2 #define BUTTON_ERROR -99 +void print_result(char *name, uint8_t *buf, size_t len); size_t nbytes(size_t nbits); uint32_t SwapBits(uint32_t value, int nrbits); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); +void rol(uint8_t *data, const size_t len); +void lsl (uint8_t *data, size_t len); +int32_t le24toh (uint8_t data[3]); void SpinDelay(int ms); void SpinDelayUs(int us); diff --git a/client/Makefile b/client/Makefile index e4a3580b..026db798 100644 --- a/client/Makefile +++ b/client/Makefile @@ -13,23 +13,16 @@ CXX=g++ VPATH = ../common OBJDIR = obj -LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a +LDLIBS = -L/mingw/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lcrypto -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 $(ICE_FLAGS) LUAPLATFORM = generic ifneq (,$(findstring MINGW,$(platform))) -CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 +CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -I$(QTDIR)/include/QtWidgets +QTLDLIBS = -L$(QTDIR)/lib -lQt5Core -lQt5Gui -lQt5Widgets MOC = $(QTDIR)/bin/moc LUAPLATFORM = mingw -else ifeq ($(platform),Darwin) -#CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers -#QTLDLIBS = -framework QtGui -framework QtCore -CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -QTLDLIBS = -F/opt/local/Library/Frameworks -framework QtGui -framework QtCore -MOC = moc -LUAPLATFORM = macosx else CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4 QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) @@ -58,6 +51,12 @@ CORESRCS = uart.c \ CMDSRCS = nonce2key/crapto1.c\ nonce2key/crypto1.c\ nonce2key/nonce2key.c\ + loclass/cipher.c \ + loclass/cipherutils.c \ + loclass/des.c \ + loclass/ikeys.c \ + loclass/elite_crack.c\ + loclass/fileutils.c\ mifarehost.c\ crc16.c \ iso14443crc.c \ @@ -74,6 +73,9 @@ CMDSRCS = nonce2key/crapto1.c\ cmdhflegic.c \ cmdhficlass.c \ cmdhfmf.c \ + cmdhfmfu.c \ + cmdhfmfdes.c \ + cmdhfdes.c \ cmdhw.c \ cmdlf.c \ cmdlfhid.c \ diff --git a/client/cmdhf.c b/client/cmdhf.c index d955fc83..dda0a669 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -22,6 +22,9 @@ #include "cmdhflegic.h" #include "cmdhficlass.h" #include "cmdhfmf.h" +#include "cmdhfmfu.h" +#include "cmdhfmfdes.h" +#include "cmdhfdes.h" static int CmdHelp(const char *Cmd); @@ -42,6 +45,9 @@ static command_t CommandTable[] = {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, + {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, + {"mfdes", CmdHFMFDes, 1, "{ MIFARE Desfire RFIDs... }"}, + {"des", CmdHFDES, 0, "{ MIFARE DESfire}"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 39bdcf40..bd19cee4 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -14,15 +14,15 @@ #include #include #include "util.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "data.h" #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" #include "cmdhf14a.h" -#include "common.h" +#include "../include/common.h" #include "cmdmain.h" -#include "mifare.h" +#include "../include/mifare.h" static int CmdHelp(const char *Cmd); static void waitCmd(uint8_t iLen); @@ -183,27 +183,24 @@ void iso14a_set_timeout(uint32_t timeout) { int CmdHF14AReader(const char *Cmd) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; SendCommand(&c); UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); + iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes; - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS - - if(select_status == 0) { + if(resp.arg[0] == 0) { PrintAndLog("iso14443a card select failed"); return 0; } - PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); + PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]); + PrintAndLog(" UID : %s", sprint_hex(card->uid, card->uidlen)); + PrintAndLog(" SAK : %02x [%d]", card->sak, resp.arg[0]); - switch (card.sak) { + switch (card->sak) { case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break; case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break; case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break; @@ -219,107 +216,67 @@ int CmdHF14AReader(const char *Cmd) case 0x98: PrintAndLog("TYPE : Gemplus MPCOS"); break; default: ; } - - - // 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 - c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT; - c.arg[1] = 2; - c.arg[2] = 0; - memcpy(c.d.asBytes, rats, 2); - SendCommand(&c); - WaitForResponse(CMD_ACK,&resp); - - memcpy(&card.ats, resp.d.asBytes, resp.arg[0]); - card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes - } - - // disconnect - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - - - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + if(resp.arg[0] == 1) { bool ta1 = 0, tb1 = 0, tc1 = 0; int pos; - if (select_status == 2) { - PrintAndLog("SAK incorrectly claims that card doesn't support RATS"); + PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len)); + if (card->ats_len > 0) { + PrintAndLog(" - TL : length is %d bytes", card->ats[0]); } - PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len)); - PrintAndLog(" - TL : length is %d bytes", card.ats[0]); - if (card.ats[0] != card.ats_len - 2) { - PrintAndLog("ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); - } - - if (card.ats[0] > 1) { // there is a format byte (T0) - ta1 = (card.ats[1] & 0x10) == 0x10; - tb1 = (card.ats[1] & 0x20) == 0x20; - tc1 = (card.ats[1] & 0x40) == 0x40; - int16_t fsci = card.ats[1] & 0x0f; + if (card->ats_len > 1) { + ta1 = (card->ats[1] & 0x10) == 0x10; + tb1 = (card->ats[1] & 0x20) == 0x20; + tc1 = (card->ats[1] & 0x40) == 0x40; PrintAndLog(" - T0 : TA1 is%s present, TB1 is%s present, " - "TC1 is%s present, FSCI is %d (FSC = %ld)", + "TC1 is%s present, FSCI is %d", (ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"), - fsci, - fsci < 5 ? (fsci - 2) * 8 : - fsci < 8 ? (fsci - 3) * 32 : - fsci == 8 ? 256 : - -1 - ); + (card->ats[1] & 0x0f)); } pos = 2; - if (ta1) { + if (ta1 && card->ats_len > pos) { char dr[16], ds[16]; dr[0] = ds[0] = '\0'; - if (card.ats[pos] & 0x10) strcat(ds, "2, "); - if (card.ats[pos] & 0x20) strcat(ds, "4, "); - if (card.ats[pos] & 0x40) strcat(ds, "8, "); - if (card.ats[pos] & 0x01) strcat(dr, "2, "); - if (card.ats[pos] & 0x02) strcat(dr, "4, "); - if (card.ats[pos] & 0x04) strcat(dr, "8, "); + if (card->ats[pos] & 0x10) strcat(ds, "2, "); + if (card->ats[pos] & 0x20) strcat(ds, "4, "); + if (card->ats[pos] & 0x40) strcat(ds, "8, "); + if (card->ats[pos] & 0x01) strcat(dr, "2, "); + if (card->ats[pos] & 0x02) strcat(dr, "4, "); + if (card->ats[pos] & 0x04) strcat(dr, "8, "); if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; PrintAndLog(" - TA1 : different divisors are%s supported, " "DR: [%s], DS: [%s]", - (card.ats[pos] & 0x80 ? " NOT" : ""), dr, ds); + (card->ats[pos] & 0x80 ? " NOT" : ""), dr, ds); pos++; } - if (tb1) { - uint32_t sfgi = card.ats[pos] & 0x0F; - uint32_t fwi = card.ats[pos] >> 4; - PrintAndLog(" - TB1 : SFGI = %d (SFGT = %s%ld/fc), FWI = %d (FWT = %ld/fc)", - (sfgi), - sfgi ? "" : "(not needed) ", - sfgi ? (1 << 12) << sfgi : 0, - fwi, - (1 << 12) << fwi - ); + if (tb1 && card->ats_len > pos) { + PrintAndLog(" - TB1 : SFGI = %d, FWI = %d", + (card->ats[pos] & 0x08), + (card->ats[pos] & 0x80) >> 4); pos++; } - if (tc1) { + if (tc1 && card->ats_len > pos) { PrintAndLog(" - TC1 : NAD is%s supported, CID is%s supported", - (card.ats[pos] & 0x01) ? "" : " NOT", - (card.ats[pos] & 0x02) ? "" : " NOT"); + (card->ats[pos] & 0x01) ? "" : " NOT", + (card->ats[pos] & 0x02) ? "" : " NOT"); pos++; } - if (card.ats[0] > pos) { + if (card->ats_len > pos) { char *tip = ""; - if (card.ats[0] - pos >= 7) { - if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + if (card->ats_len - pos > 7) { + if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { tip = "-> MIFARE Plus X 2K or 4K"; - } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + } else if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { tip = "-> MIFARE Plus S 2K or 4K"; } } - PrintAndLog(" - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); - if (card.ats[pos] == 0xC1) { + PrintAndLog(" - HB : %s%s", sprint_hex(card->ats + pos, card->ats_len - pos - 2), tip); + if (card->ats[pos] == 0xC1) { PrintAndLog(" c1 -> Mifare or (multiple) virtual cards of various type"); PrintAndLog(" %02x -> Length is %d bytes", - card.ats[pos + 1], card.ats[pos + 1]); - switch (card.ats[pos + 2] & 0xf0) { + card->ats[pos + 1], card->ats[pos + 1]); + switch (card->ats[pos + 2] & 0xf0) { case 0x10: PrintAndLog(" 1x -> MIFARE DESFire"); break; @@ -327,7 +284,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" 2x -> MIFARE Plus"); break; } - switch (card.ats[pos + 2] & 0x0f) { + switch (card->ats[pos + 2] & 0x0f) { case 0x00: PrintAndLog(" x0 -> <1 kByte"); break; @@ -344,7 +301,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" x0 -> 8 kByte"); break; } - switch (card.ats[pos + 3] & 0xf0) { + switch (card->ats[pos + 3] & 0xf0) { case 0x00: PrintAndLog(" 0x -> Engineering sample"); break; @@ -352,7 +309,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" 2x -> Released"); break; } - switch (card.ats[pos + 3] & 0x0f) { + switch (card->ats[pos + 3] & 0x0f) { case 0x00: PrintAndLog(" x0 -> Generation 1"); break; @@ -363,7 +320,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" x2 -> Generation 3"); break; } - switch (card.ats[pos + 4] & 0x0f) { + switch (card->ats[pos + 4] & 0x0f) { case 0x00: PrintAndLog(" x0 -> Only VCSL supported"); break; @@ -377,10 +334,10 @@ int CmdHF14AReader(const char *Cmd) } } } else { - PrintAndLog("proprietary non iso14443-4 card found, RATS not supported"); + PrintAndLog("proprietary non iso14443a-4 card found, RATS not supported"); } - return select_status; + return resp.arg[0]; } // Collect ISO14443 Type A UIDs @@ -402,17 +359,20 @@ int CmdHF14ACUIDs(const char *Cmd) UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes; + uint8_t *uid = resp.d.asBytes; + iso14a_card_select_t *card = (iso14a_card_select_t *)(uid + 12); // check if command failed if (resp.arg[0] == 0) { PrintAndLog("Card select failed."); } else { - char uid_string[20]; - for (uint16_t i = 0; i < card->uidlen; i++) { - sprintf(&uid_string[2*i], "%02X", card->uid[i]); + // check if UID is 4 bytes + if ((card->atqa[1] & 0xC0) == 0) { + PrintAndLog("%02X%02X%02X%02X", + *uid, *(uid + 1), *(uid + 2), *(uid + 3)); + } else { + PrintAndLog("UID longer than 4 bytes"); } - PrintAndLog("%s", uid_string); } } PrintAndLog("End: %u", time(NULL)); @@ -466,10 +426,6 @@ int CmdHF14ASim(const char *Cmd) // At lease save the mandatory first part of the UID c.arg[0] = long_uid & 0xffffffff; - - // At lease save the mandatory first part of the UID - c.arg[0] = long_uid & 0xffffffff; - 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]); } @@ -537,19 +493,22 @@ int CmdHF14ACmdRaw(const char *cmd) { uint8_t active=0; uint8_t active_select=0; uint16_t numbits=0; + uint16_t timeout=0; + uint8_t bTimeout=0; char buf[5]=""; int i=0; - uint8_t data[100]; + uint8_t data[USB_CMD_DATA_SIZE]; unsigned int datalen=0, temp; if (strlen(cmd)<2) { - PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] <0A 0B 0C ... hex>"); + PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <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"); PrintAndLog(" -a active signal field ON without select"); PrintAndLog(" -s active signal field ON with select"); PrintAndLog(" -b number of bits to send. Useful for send partial byte"); + PrintAndLog(" -t timeout"); return 0; } @@ -582,6 +541,14 @@ int CmdHF14ACmdRaw(const char *cmd) { while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } i-=2; break; + case 't': + bTimeout=1; + sscanf(cmd+i+2,"%d",&temp); + timeout = temp & 0xFFFF; + i+=3; + while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } + i+=2; + break; default: PrintAndLog("Invalid option"); return 0; @@ -599,15 +566,19 @@ int CmdHF14ACmdRaw(const char *cmd) { if (strlen(buf)>=2) { sscanf(buf,"%x",&temp); data[datalen]=(uint8_t)(temp & 0xff); - datalen++; *buf=0; + if (++datalen>sizeof(data)){ + if (crc) + PrintAndLog("Buffer is full, we can't add CRC to your data"); + break; + } } continue; } PrintAndLog("Invalid char on input"); return 0; } - if(crc && datalen>0) + if(crc && datalen>0 && datalenMAX_TIMEOUT) { + c.arg[2] = MAX_TIMEOUT; + PrintAndLog("Set timeout to 624 ms. The max we can wait for response"); + } + } if(power) c.arg[0] |= ISO14A_NO_DISCONNECT; if(datalen>0) c.arg[0] |= ISO14A_RAW; - c.arg[1] = datalen; - c.arg[2] = numbits; + // Max buffer is USB_CMD_DATA_SIZE + c.arg[1] = (datalen & 0xFFFF) | (numbits << 16); memcpy(c.d.asBytes,data,datalen); SendCommand(&c); diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index c42d54c5..25a452e6 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -13,8 +13,7 @@ #include #include #include -#include "iso14443crc.h" -//#include "proxusb.h" +#include "../common/iso14443crc.h" #include "proxmark3.h" #include "data.h" #include "graph.h" diff --git a/client/cmdhf15.c b/client/cmdhf15.c index cc61d289..195560ed 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -33,7 +33,7 @@ #include "ui.h" #include "cmdparser.h" #include "cmdhf15.h" -#include "iso15693tools.h" +#include "../common/iso15693tools.h" #include "cmdmain.h" #define FrameSOF Iso15693FrameSOF diff --git a/client/cmdhfdes.c b/client/cmdhfdes.c new file mode 100644 index 00000000..1876e5c1 --- /dev/null +++ b/client/cmdhfdes.c @@ -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 "); + 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 index 00000000..e51797cb --- /dev/null +++ b/client/cmdhfdes.h @@ -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 +#include +#include +#include +#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 diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index 8a36d6ae..92e61c68 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -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" diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index b8e1e098..e32664f5 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch // Copyright (C) 2011 Gerhard de Koning Gans +// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende // // 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 @@ -15,14 +16,19 @@ #include #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type #include "data.h" -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" #include "cmdhficlass.h" -#include "common.h" +#include "../include/common.h" #include "util.h" #include "cmdmain.h" +#include "loclass/des.h" +#include "loclass/cipherutils.h" +#include "loclass/cipher.h" +#include "loclass/ikeys.h" +#include "loclass/elite_crack.h" +#include "loclass/fileutils.h" static int CmdHelp(const char *Cmd); @@ -290,11 +296,6 @@ int CmdHFiClassListOld(const char *Cmd) return 0; } -/*void iso14a_set_timeout(uint32_t timeout) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}}; - SendCommand(&c); -}*/ - int CmdHFiClassSnoop(const char *Cmd) { UsbCommand c = {CMD_SNOOP_ICLASS}; @@ -393,37 +394,255 @@ int CmdHFiClassSim(const char *Cmd) memcpy(c.d.asBytes, CSN, 8); SendCommand(&c); } + return 0; } int CmdHFiClassReader(const char *Cmd) { - uint8_t readerType = 0; - - if (strlen(Cmd)<1) { - PrintAndLog("Usage: hf iclass reader "); - PrintAndLog(" sample: hf iclass reader 0"); - return 0; - } - - readerType = param_get8(Cmd, 0); - PrintAndLog("--readertype:%02x", readerType); - - UsbCommand c = {CMD_READER_ICLASS, {readerType}}; - //memcpy(c.d.asBytes, CSN, 8); + UsbCommand c = {CMD_READER_ICLASS, {0}}; SendCommand(&c); + UsbCommand resp; + while(!ukbhit()){ + if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; - /*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); - if (resp != NULL) { - uint8_t isOK = resp->arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - }*/ + PrintAndLog("isOk:%02x", isOK); + + if(isOK > 0) + { + PrintAndLog("CSN: %s",sprint_hex(data,8)); + } + if(isOK >= 1) + { + PrintAndLog("CC: %s",sprint_hex(data+8,8)); + }else{ + PrintAndLog("No CC obtained"); + } + } else { + PrintAndLog("Command execute timeout"); + } + } return 0; } +int CmdHFiClassReader_Replay(const char *Cmd) +{ + uint8_t readerType = 0; + uint8_t MAC[4]={0x00, 0x00, 0x00, 0x00}; + + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf iclass replay "); + PrintAndLog(" sample: hf iclass replay 00112233"); + return 0; + } + + if (param_gethex(Cmd, 0, MAC, 8)) { + PrintAndLog("MAC must include 8 HEX symbols"); + return 1; + } + + UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}}; + memcpy(c.d.asBytes, MAC, 4); + SendCommand(&c); + + return 0; +} + +int CmdHFiClassReader_Dump(const char *Cmd) +{ + uint8_t readerType = 0; + uint8_t MAC[4]={0x00,0x00,0x00,0x00}; + uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t keytable[128] = {0}; + int elite = 0; + uint8_t *used_key; + int i; + if (strlen(Cmd)<1) + { + PrintAndLog("Usage: hf iclass dump [e]"); + PrintAndLog(" Key - A 16 byte master key"); + PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte"); + PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack"); + PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format"); + PrintAndLog(" sample: hf iclass dump 0011223344556677"); + + + return 0; + } + + if (param_gethex(Cmd, 0, KEY, 16)) { + PrintAndLog("KEY must include 16 HEX symbols"); + return 1; + } + + if (param_getchar(Cmd, 1) == 'e') + { + PrintAndLog("Elite switch on"); + elite = 1; + + //calc h2 + hash2(KEY, keytable); + printarr_human_readable("keytable", keytable, 128); + + } + + + UsbCommand c = {CMD_READER_ICLASS, {0}}; + c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE; + + SendCommand(&c); + + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; + + memcpy(CSN,data,8); + memcpy(CCNR,data+8,8); + + PrintAndLog("isOk:%02x", isOK); + + if(isOK > 0) + { + PrintAndLog("CSN: %s",sprint_hex(CSN,8)); + } + if(isOK > 1) + { + if(elite) + { + uint8_t key_sel[8] = {0}; + uint8_t key_sel_p[8] = { 0 }; + //Get the key index (hash1) + uint8_t key_index[8] = {0}; + + hash1(CSN, key_index); + printvar("hash1", key_index,8); + for(i = 0; i < 8 ; i++) + key_sel[i] = keytable[key_index[i]] & 0xFF; + printvar("k_sel", key_sel,8); + //Permute from iclass format to standard format + permutekey_rev(key_sel,key_sel_p); + used_key = key_sel_p; + }else{ + //Perhaps this should also be permuted to std format? + // Something like the code below? I have no std system + // to test this with /Martin + + //uint8_t key_sel_p[8] = { 0 }; + //permutekey_rev(KEY,key_sel_p); + //used_key = key_sel_p; + + used_key = KEY; + + } + printvar("Used key",used_key,8); + diversifyKey(CSN,used_key, div_key); + printvar("Div key", div_key, 8); + printvar("CC_NR:",CCNR,12); + doMAC(CCNR,12,div_key, MAC); + printvar("MAC", MAC, 4); + + UsbCommand d = {CMD_READER_ICLASS_REPLAY, {readerType}}; + memcpy(d.d.asBytes, MAC, 4); + SendCommand(&d); + + }else{ + PrintAndLog("Failed to obtain CC! Aborting"); + } + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} + +int CmdHFiClass_iso14443A_write(const char *Cmd) +{ + uint8_t readerType = 0; + uint8_t MAC[4]={0x00,0x00,0x00,0x00}; + uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + uint8_t blockNo=0; + uint8_t bldata[8]={0}; + + if (strlen(Cmd)<3) + { + PrintAndLog("Usage: hf iclass write "); + PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA"); + return 0; + } + + if (param_gethex(Cmd, 0, KEY, 16)) + { + PrintAndLog("KEY must include 16 HEX symbols"); + return 1; + } + + blockNo = param_get8(Cmd, 1); + if (blockNo>32) + { + PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!"); + return 1; + } + if (param_gethex(Cmd, 2, bldata, 8)) + { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + + UsbCommand c = {CMD_ICLASS_ISO14443A_WRITE, {0}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t * data = resp.d.asBytes; + + memcpy(CSN,data,8); + memcpy(CCNR,data+8,8); + PrintAndLog("DEBUG: %s",sprint_hex(CSN,8)); + PrintAndLog("DEBUG: %s",sprint_hex(CCNR,8)); + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + + diversifyKey(CSN,KEY, div_key); + + PrintAndLog("Div Key: %s",sprint_hex(div_key,8)); + doMAC(CCNR, 12,div_key, MAC); + + UsbCommand c2 = {CMD_ICLASS_ISO14443A_WRITE, {readerType,blockNo}}; + memcpy(c2.d.asBytes, bldata, 8); + memcpy(c2.d.asBytes+8, MAC, 4); + SendCommand(&c2); + + 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, 4)); + else + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + return 0; +} + + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -431,6 +650,9 @@ static command_t CommandTable[] = {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"}, {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"}, {"reader", CmdHFiClassReader, 0, "Read an iClass tag"}, + {"replay", CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"}, + {"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"}, + {"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"}, {NULL, NULL, 0, NULL} }; @@ -443,55 +665,5 @@ int CmdHFiClass(const char *Cmd) int CmdHelp(const char *Cmd) { CmdsHelp(CommandTable); - return 0; -} - -/** - * @brief checks if a file exists - * @param filename - * @return - */ -int fileExists(const char *filename) { - struct stat st; - int result = stat(filename, &st); - return result == 0; -} -/** - * @brief Utility function to save data to a file. This method takes a preferred name, but if that - * file already exists, it tries with another name until it finds something suitable. - * E.g. dumpdata-15.txt - * @param preferredName - * @param suffix the file suffix. Leave out the ".". - * @param data The binary data to write to the file - * @param datalen the length of the data - * @return 0 for ok, 1 for failz - */ -int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen) -{ - FILE *f = fopen(preferredName, "wb"); - int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5); - char * fileName = malloc(size); - - memset(fileName,0,size); - int num = 1; - sprintf(fileName,"%s.%s", preferredName, suffix); - while(fileExists(fileName)) - { - sprintf(fileName,"%s-%d.%s", preferredName, num, suffix); - num++; - } - /* We should have a valid filename now, e.g. dumpdata-3.bin */ - - /*Opening file for writing in binary mode*/ - FILE *fileHandle=fopen(fileName,"wb"); - if(!f) { - PrintAndLog("Failed to write to file '%s'", fileName); - return 0; - } - fwrite(data, 1, datalen, fileHandle); - fclose(fileHandle); - PrintAndLog("Saved data to '%s'", fileName); - - free(fileName); return 0; } diff --git a/client/cmdhficlass.h b/client/cmdhficlass.h index 98c79e4b..e4048eb1 100644 --- a/client/cmdhficlass.h +++ b/client/cmdhficlass.h @@ -18,6 +18,6 @@ int CmdHFiClassSnoop(const char *Cmd); int CmdHFiClassSim(const char *Cmd); int CmdHFiClassList(const char *Cmd); int CmdHFiClassReader(const char *Cmd); -int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen); +int CmdHFiClassReader_Replay(const char *Cmd); #endif diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 8366b09b..340fd2b0 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -10,7 +10,6 @@ #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "data.h" #include "ui.h" diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index eb3b4bf1..37c6fe94 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -7,7 +7,7 @@ //----------------------------------------------------------------------------- // High frequency MIFARE commands //----------------------------------------------------------------------------- - +#include "../include/mifare.h" #include "cmdhfmf.h" static int CmdHelp(const char *Cmd); @@ -140,6 +140,7 @@ int CmdHF14AMfWrBl(const char *Cmd) return 0; } +/* dublett finns i CMDHFMFU.C int CmdHF14AMfUWrBl(const char *Cmd) { uint8_t blockNo = 0; @@ -249,8 +250,7 @@ int CmdHF14AMfUWrBl(const char *Cmd) } return 0; } - - +*/ int CmdHF14AMfRdBl(const char *Cmd) { uint8_t blockNo = 0; @@ -299,6 +299,7 @@ int CmdHF14AMfRdBl(const char *Cmd) return 0; } +/* dublett finns i CMDHFMFU.C int CmdHF14AMfURdBl(const char *Cmd) { uint8_t blockNo = 0; @@ -330,8 +331,9 @@ int CmdHF14AMfURdBl(const char *Cmd) return 0; } +*/ - +/* dublett finns i CMDHFMFU.C int CmdHF14AMfURdCard(const char *Cmd) { int i; @@ -422,7 +424,7 @@ int CmdHF14AMfURdCard(const char *Cmd) } return 0; } - +*/ int CmdHF14AMfRdSc(const char *Cmd) { @@ -516,7 +518,16 @@ int CmdHF14AMfDump(const char *Cmd) UsbCommand resp; + int size = GetCardSize(); char cmdp = param_getchar(Cmd, 0); + + PrintAndLog("Got %d",size); + + return; + + if ( size > -1) + cmdp = (char)48+size; + switch (cmdp) { case '0' : numSectors = 5; break; case '1' : @@ -545,8 +556,7 @@ int CmdHF14AMfDump(const char *Cmd) return 1; } - // Read key file - + // Read keys A from file for (sectorNo=0; sectorNo where num is: +// -1 unidentified +// 0 - MINI (320bytes) +// 1 - 1K +// 2 - 2K +// 4 - 4K +int GetCardSize() +{ + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + + if(resp.arg[0] == 0) { + PrintAndLog("iso14443a card select failed"); + return -1; + } + + iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes; + + PrintAndLog("Trying to detect card size."); + + uint16_t atqa = 0; + uint8_t sak = 0; + atqa = (card->atqa[1] & 0xff) << 8; + atqa += card->atqa[0] & 0xff; + sak = card->sak; + + // https://code.google.com/p/libnfc/source/browse/libnfc/target-subr.c + + PrintAndLog("found ATAQ: %04X SAK: %02X", atqa, sak); + + + // NXP MIFARE Mini 0.3k + if ( (atqa && 0xff0f == 0x0004) && (sak == 0x09) ) return 0; + + // MIFARE Classic 1K + if ( (atqa && 0xff0f == 0x0004) && (sak == 0x08) ) return 1; + + // MIFARE Classik 4K + if ( (atqa && 0xff0f == 0x0002) && (sak == 0x18) ) return 4; + + // SmartMX with MIFARE 1K emulation + if ( (atqa && 0xf0ff == 0x0004) ) return 1; + + // SmartMX with MIFARE 4K emulation + if ( (atqa && 0xf0ff == 0x0002) ) return 4; + + // Infineon MIFARE CLASSIC 1K + if ( (atqa && 0xffff == 0x0004) && (sak == 0x88) ) return 1; + + // MFC 4K emulated by Nokia 6212 Classic + if ( (atqa && 0xffff == 0x0002) && (sak == 0x38) ) return 4; + + // MFC 4K emulated by Nokia 6131 NFC + if ( (atqa && 0xffff == 0x0008) && (sak == 0x38) ) return 4; + + // MIFARE Plus (4 Byte UID or 4 Byte RID) + // MIFARE Plus (7 Byte UID) + if ( + (atqa && 0xffff == 0x0002) || + (atqa && 0xffff == 0x0004) || + (atqa && 0xffff == 0x0042) || + (atqa && 0xffff == 0x0044) + ) + { + switch(sak){ + case 0x08: + case 0x10: + //case 0x20: + return 2; + break; + case 0x11: + case 0x18: + //case 0x20: + return 4; + break; + } + } + + return -1; +} + + + + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, - {"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"}, - {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, - {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, + //{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"}, + //{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, + //{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 62e856ad..45ba7cb1 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -16,12 +16,11 @@ #include #include #include "proxmark3.h" -#include "iso14443crc.h" +#include "../common/iso14443crc.h" #include "data.h" -//#include "proxusb.h" #include "ui.h" #include "cmdparser.h" -#include "common.h" +#include "../include/common.h" #include "util.h" #include "mifarehost.h" @@ -54,5 +53,5 @@ int CmdHF14AMfCGetBlk(const char* cmd); int CmdHF14AMfCGetSc(const char* cmd); int CmdHF14AMfCLoad(const char* cmd); int CmdHF14AMfCSave(const char* cmd); - +int GetCardSize(); #endif diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c new file mode 100644 index 00000000..93a972f4 --- /dev/null +++ b/client/cmdhfmfdes.c @@ -0,0 +1,436 @@ +//----------------------------------------------------------------------------- +// 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 +#include +#include +#include +#include +#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" + + +uint8_t key_zero_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +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_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }; + + +static int CmdHelp(const char *Cmd); +static void xor(unsigned char * dst, unsigned char * src, size_t len); +static int32_t le24toh (uint8_t data[3]); + + +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 "); + 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 "); + // 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, { 0x00 }}; + + 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; + } + + 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", GetVendorStr(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",GetVendorStr(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("-------------------------------------------------------------"); + + PrintAndLog(" Master Key settings"); + if ( resp.d.asBytes[35] & (1 << 3 ) ) + PrintAndLog(" 0x08 Configuration changeable;"); + else + PrintAndLog(" 0x08 Configuration NOT changeable;"); + + if ( resp.d.asBytes[35] & (1 << 2 ) ) + PrintAndLog(" 0x04 PICC Master Key not required for create / delete;"); + else + PrintAndLog(" 0x04 PICC Master Key required for create / delete;"); + + if ( resp.d.asBytes[35] & (1 << 1 ) ) + PrintAndLog(" 0x02 Free directory list access without PICC Master Key;"); + else + PrintAndLog(" 0x02 Directory list access with PICC Master Key;"); + + if ( resp.d.asBytes[35] & (1 << 0 ) ) + PrintAndLog(" 0x01 Allow changing the Master Key;"); + else + PrintAndLog(" 0x01 Master Key is not changeable anymore;"); + + PrintAndLog(""); + PrintAndLog(" Max number of keys : %d", resp.d.asBytes[36]); + PrintAndLog(" Master key Version : %d (0x%02x)", resp.d.asBytes[37], resp.d.asBytes[37]); + PrintAndLog("-------------------------------------------------------------"); + + uint8_t tmp[3]; + memcpy(tmp, resp.d.asBytes+38,3); + + PrintAndLog(" Free memory on card : %d bytes", le24toh( tmp )); + PrintAndLog("-------------------------------------------------------------"); + /* + Card Master key (CMK) 0x00 on AID = 00 00 00 (card level) + 0x1 + + Application Master Key (AMK) 0x00 on 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 + + KEY Versioning. + Se GetKeyVersion (samma nyckel kan ha olika versionen?) + + Session key: + 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte4-byte7) + RndB(byte4-byte7) + 8 : RndA(byte0-byte3) + RndB(byte0-byte3) + + AES 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte12-byte15) + RndB(byte12-byte15) + */ + + PrintAndLog(" RX :%s",sprint_hex(resp.d.asBytes, 40)); + return 1; +} + +char * GetVendorStr( uint8_t id){ + static char buf[30]; + char *retStr = buf; + + if ( id == 0x04 ) + sprintf(retStr, "0x%02X (NXP)",id); + else + sprintf(retStr,"0x%02X (Unknown)",id); + return buf; +} + +/* + 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 << 0 ) ) + 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", id); + return buf; +} + +int CmdHF14ADesEnumApplications(const char *Cmd){ + return 1; +} + +int CmdHF14ADesNonces(const char *Cmd){ + return 1; +} + +// +// MIAFRE DesFire Authentication +// +#define BUFSIZE 64 +int CmdHF14ADesAuth(const char *Cmd){ + + // NR DESC KEYLENGHT + // ------------------------ + // 1 = DES 8 + // 2 = 3DES 16 + // 3 = 3K 3DES 24 + // 4 = AES 16 + + // AUTHENTICTION MODES: + // 1 Normal + // 2 ISO + // 3 AES + + uint8_t keylength = 8; + //unsigned char testinput[] = { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00}; + unsigned char key[24]; // = { 0x75,0x28,0x78,0x39,0x74,0x93,0xCB,0x70}; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mfdes auth <1|2|3> <1|2|3|4> "); + PrintAndLog(" AUTH modes 1 = normal, 2 = iso, 3 = aes"); + PrintAndLog(" Crypto: 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES"); + PrintAndLog(" keynumber"); + PrintAndLog(" sample: hf mfdes auth 1 1 0 11223344"); + 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); + //memcpy(c.d.asBytes + 30, testinput, keylength); + + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,3000)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + + } else { + PrintAndLog("Command execute timeout"); + return 0; + } + + uint8_t * data= resp.d.asBytes; + + // PrintAndLog("-------------------------------------------------------------"); + PrintAndLog(" Key :%s",sprint_hex(key, keylength)); + // PrintAndLog(" Plain :%s",sprint_hex(testinput, keylength)); + PrintAndLog(" Encoded :%s",sprint_hex(data, keylength)); + PrintAndLog("-------------------------------------------------------------"); + //PrintAndLog(" Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56"); + + return 1; +} + + +static void xor(unsigned char * dst, unsigned char * src, size_t len) { + for( ; len > 0; len--,dst++,src++) + *dst ^= *src; +} + +static int32_t le24toh (uint8_t data[3]) { + return (data[2] << 16) | (data[1] << 8) | data[0]; +} + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help"}, + {"auth", CmdHF14ADesAuth, 0, "Tries a MIFARE DesFire Authentication"}, + {"rb", CmdHF14ADesRb, 0, "Read MIFARE DesFire block"}, + {"wb", CmdHF14ADesWb, 0, "write MIFARE DesFire block"}, + {"info", CmdHF14ADesInfo, 0, "Get MIFARE DesFire information"}, + {"enum", CmdHF14ADesEnumApplications,0, "Tries enumerate all applications"}, + {"nonce", CmdHF14ADesNonces, 0, " Collect n>0 nonces"}, + {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 index 00000000..5a4997e5 --- /dev/null +++ b/client/cmdhfmfdes.h @@ -0,0 +1,20 @@ +//----------------------------------------------------------------------------- +// 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); +int CmdHF14ADesNonces(const char *Cmd); +char * GetCardSizeStr( uint8_t fsize ); +char * GetVendorStr( uint8_t id); +char * GetProtocolStr(uint8_t id); diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c new file mode 100644 index 00000000..3b9f2e6d --- /dev/null +++ b/client/cmdhfmfu.c @@ -0,0 +1,1159 @@ +//----------------------------------------------------------------------------- +// Ultralight Code (c) 2013,2014 Midnitesnake & Andy Davies of Pentura +// +// 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 ULTRALIGHT (C) commands +//----------------------------------------------------------------------------- +#include +#include "cmdhfmf.h" + +uint8_t MAX_ULTRA_BLOCKS= 0x0f; +uint8_t MAX_ULTRAC_BLOCKS= 0x2c; +uint8_t key1_blnk_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +uint8_t key2_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; +uint8_t key3_3des_data[16] = { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 }; +uint8_t key4_nfc_data[16] = { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 }; +uint8_t key5_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }; + +static int CmdHelp(const char *Cmd); + +// +// Mifare Ultralight Write Single Block +// +int CmdHF14AMfUWrBl(const char *Cmd){ + uint8_t blockNo = 0; + bool chinese_card=0; + uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + UsbCommand resp; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mfu uwrbl [w]"); + PrintAndLog(" sample: hf mfu uwrbl 0 01020304"); + return 0; + } + blockNo = param_get8(Cmd, 0); + if (blockNo>MAX_ULTRA_BLOCKS){ + PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); + return 1; + } + if (param_gethex(Cmd, 1, bldata, 8)) { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + if (strchr(Cmd,'w') != 0) { + chinese_card=1; + } + switch(blockNo){ + case 0: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 1: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 2: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(c.d.asBytes, bldata, 4); + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 3: + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + default: + PrintAndLog("--block no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(e.d.asBytes,bldata, 4); + SendCommand(&e); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + } + return 0; +} + +// +// Mifare Ultralight Read Single Block +// +int CmdHF14AMfURdBl(const char *Cmd){ + + uint8_t blockNo = 0; + + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf mfu urdbl "); + PrintAndLog(" sample: hfu mfu urdbl 0"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + // if (blockNo>MAX_ULTRA_BLOCKS){ + // PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); + // return 1; + // } + PrintAndLog("--block no:%02x", (int)blockNo); + UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; + 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, 4)); + else + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + return 0; +} + +// +// Mifare Ultralight Read (Dump) Card Contents +// +int CmdHF14AMfURdCard(const char *Cmd){ + int i; + uint8_t BlockNo = 0; + int Pages=16; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool dump=false; + uint8_t datatemp[5]={0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + FILE *fout = NULL; + + if (strchr(Cmd,'x') != 0){ + dump=true; + if ((fout = fopen("dump_ultralight_data.bin","wb")) == NULL) { + PrintAndLog("Could not create file name dumpdata.bin"); + return 1; + } + PrintAndLog("Dumping Ultralight Card Data..."); + } + PrintAndLog("Attempting to Read Ultralight... "); + UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo, Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + PrintAndLog("isOk:%02x", isOK); + if (isOK) { + + // UID + memcpy( datatemp, data,3); + memcpy( datatemp+3, data+4, 4); + PrintAndLog(" UID :%s ", sprint_hex(datatemp, 7)); + // BBC + // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 + int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; + if ( data[3] == crc0 ) { + PrintAndLog(" BCC0 :%02x - Ok", data[3]); + } + else{ + PrintAndLog(" BCC0 :%02x - crc should be %02x", data[3], crc0); + } + + int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; + if ( data[8] == crc1 ){ + PrintAndLog(" BCC1 :%02x - Ok", data[8]); + } + else{ + PrintAndLog(" BCC1 :%02x - crc should be %02x", data[8], crc1 ); + } + + PrintAndLog(" Internal :%s ", sprint_hex(data + 9, 1)); + + memcpy(datatemp, data+10, 2); + PrintAndLog(" Lock :%s - %s", sprint_hex(datatemp, 2),printBits( 2, &datatemp) ); + + PrintAndLog(" OneTimePad :%s ", sprint_hex(data + 3*4, 4)); + PrintAndLog(""); + + for (i = 0; i < Pages; i++) { + switch(i){ + case 2: + //process lock bytes + lockbytes_t=data+(i*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + } + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 3: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 4: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 5: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 6: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 7: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 8: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 9: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 10: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 11: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 12: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 13: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 14: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 15: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + default: + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + } + } + } + } else { + PrintAndLog("Command1 execute timeout"); + } + if (dump) fclose(fout); + return 0; +} + +int CmdHF14AMfUDump(const char *Cmd){ + int i; + uint8_t BlockNo = 0; + int Pages=16; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool dump=false; + uint8_t datatemp[5]={0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + FILE *fout; + + dump=true; + if ((fout = fopen("dump_ultralight_data.bin","wb")) == NULL) { + PrintAndLog("Could not create file name dumpdata.bin"); + return 1; + } + PrintAndLog("Dumping Ultralight Card Data..."); + + PrintAndLog("Attempting to Read Ultralight... "); + UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + PrintAndLog("isOk:%02x", isOK); + if (isOK) + for (i = 0; i < Pages; i++) { + switch(i){ + case 2: + //process lock bytes + lockbytes_t=data+(i*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + } + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 3: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 4: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 5: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 6: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 7: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 8: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 9: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 10: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 11: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 12: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 13: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 14: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 15: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + default: + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + } + } + } else { + PrintAndLog("Command1 execute timeout"); + } + if (dump) fclose(fout); + return 0; +} + +// Needed to Authenticate to Ultralight C tags +void rol (uint8_t *data, const size_t len){ + uint8_t first = data[0]; + for (size_t i = 0; i < len-1; i++) { + data[i] = data[i+1]; + } + data[len-1] = first; +} + +//------------------------------------------------------------------------------- +// Ultralight C Methods +//------------------------------------------------------------------------------- + +// +// Ultralight C Authentication Demo {currently uses hard-coded key} +// +int CmdHF14AMfucAuth(const char *Cmd){ + + uint8_t blockNo = 0, keyNo=0; + uint8_t e_RndB[8]; + uint32_t cuid=0; + unsigned char RndARndB[16]; + uint8_t key[16]; + DES_cblock RndA, RndB; + DES_cblock iv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + DES_key_schedule ks1,ks2; + DES_cblock key1,key2; + + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf mfu auth k "); + PrintAndLog(" sample: hf mfu auth k 0"); + return 0; + } + + //Change key to user defined one + if (strchr(Cmd,'k') != 0){ + //choose a key + keyNo = param_get8(Cmd, 1); + switch(keyNo){ + case 0: + memcpy(key,key1_blnk_data,16); + break; + case 1: + memcpy(key,key2_defa_data,16); + break; + case 2: + memcpy(key,key4_nfc_data,16); + break; + case 3: + memcpy(key,key5_ones_data,16); + break; + default: + memcpy(key,key3_3des_data,16); + break; + } + }else{ + memcpy(key,key3_3des_data,16); + } + 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_MIFAREUC_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(RndB):%s", sprint_hex(data+1, 8)); + memcpy(e_RndB,data+1,8); + } + } else { + PrintAndLog("Command execute timeout"); + } + + //Do crypto magic + DES_random_key(&RndA); + DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); + PrintAndLog(" RndB:%s",sprint_hex(RndB, 8)); + PrintAndLog(" RndA:%s",sprint_hex(RndA, 8)); + rol(RndB,8); + memcpy(RndARndB,RndA,8); + memcpy(RndARndB+8,RndB,8); + PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); + DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); + PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); + + //Auth2 + UsbCommand d = {CMD_MIFAREUC_AUTH2, {cuid}}; + memcpy(d.d.asBytes,RndARndB, 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("enc(RndA'):%s", sprint_hex(data2+1, 8)); + } + + } else { + PrintAndLog("Command execute timeout"); + } + return 1; +} + +// +// Ultralight C Read Single Block +// +int CmdHF14AMfUCRdBl(const char *Cmd) +{ + + uint8_t blockNo = 0; + + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf mfu ucrdbl "); + PrintAndLog(" sample: hf mfu ucrdbl 0"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + if (blockNo>MAX_ULTRAC_BLOCKS){ + PrintAndLog("Error: Maximum number of readable blocks is 44 for Ultralight Cards!"); + return 1; + } + PrintAndLog("--block no:%02x", (int)blockNo); + + //Read Block + UsbCommand e = {CMD_MIFAREU_READBL, {blockNo}}; + SendCommand(&e); + UsbCommand resp_c; + if (WaitForResponseTimeout(CMD_ACK,&resp_c,1500)) { + uint8_t isOK = resp_c.arg[0] & 0xff; + uint8_t * data = resp_c.d.asBytes; + if (isOK) + PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4)); + else + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + return 0; +} + +// +// Ultralight C Read (or Dump) Card Contents +// +int CmdHF14AMfUCRdCard(const char *Cmd){ + int i; + uint8_t BlockNo = 0; + int Pages=44; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + uint8_t *lockbytes_t2=NULL; + uint8_t lockbytes2[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool bit2[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool dump=false; + uint8_t datatemp[5]={0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + FILE *fout = NULL; + + if (strchr(Cmd,'x') != 0){ + dump=true; + if ((fout = fopen("dump_ultralightc_data.bin","wb")) == NULL) { + PrintAndLog("Could not create file name dumpdata.bin"); + return 1; + } + PrintAndLog("Dumping Ultralight C Card Data..."); + } + PrintAndLog("Attempting to Read Ultralight C... "); + UsbCommand c = {CMD_MIFAREUC_READCARD, {BlockNo, Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + //Pages=sizeof(data)/sizeof(data[0]); + PrintAndLog("isOk:%02x", isOK); + if (isOK) + for (i = 0; i < Pages; i++) { + switch(i){ + case 2: + //process lock bytes + lockbytes_t=data+(i*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + } + //might as well read bottom lockbytes too + lockbytes_t2=data+(40*4); + lockbytes2[0]=lockbytes_t2[2]; + lockbytes2[1]=lockbytes_t2[3]; + for(int j=0; j<16; j++){ + bit2[j]=lockbytes2[j/8] & ( 1 <<(7-j%8)); + } + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 3: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 4: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 5: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 6: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 7: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 8: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 9: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 10: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 11: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 12: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 13: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 14: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 15: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 16: + case 17: + case 18: + case 19: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[6]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 20: + case 21: + case 22: + case 23: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[5]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 24: + case 25: + case 26: + case 27: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 28: + case 29: + case 30: + case 31: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 32: + case 33: + case 34: + case 35: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 36: + case 37: + case 38: + case 39: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 40: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 41: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 42: + //auth0 + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 43: + //auth1 + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + default: + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + } + } + + } else { + PrintAndLog("Command1 execute timeout"); + } + if (dump) fclose(fout); + return 0; +} + +// +// Ultralight C Dump Card Contents to file +// +int CmdHF14AMfUCDump(const char *Cmd){ + int i; + uint8_t BlockNo = 0; + int Pages=44; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + uint8_t *lockbytes_t2=NULL; + uint8_t lockbytes2[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool bit2[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + bool dump=false; + uint8_t datatemp[5]={0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + FILE *fout; + + dump=true; + if ((fout = fopen("dump_ultralightc_data.bin","wb")) == NULL) { + PrintAndLog("Could not create file name dumpdata.bin"); + return 1; + } + PrintAndLog("Dumping Ultralight C Card Data..."); + PrintAndLog("Attempting to Read Ultralight C... "); + UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; + SendCommand(&c); + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + PrintAndLog("isOk:%02x", isOK); + if (isOK) + for (i = 0; i < Pages; i++) { + switch(i){ + case 2: + //process lock bytes + lockbytes_t=data+(i*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + + } + //might as well read bottom lockbytes too + lockbytes_t2=data+(40*4); + lockbytes2[0]=lockbytes_t2[2]; + lockbytes2[1]=lockbytes_t2[3]; + for(int j=0; j<16; j++){ + bit2[j]=lockbytes2[j/8] & ( 1 <<(7-j%8)); + } + + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 3: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 4: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 5: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 6: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 7: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 8: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 9: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 10: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 11: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 12: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 13: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 14: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 15: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 16: + case 17: + case 18: + case 19: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[6]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 20: + case 21: + case 22: + case 23: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[5]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 24: + case 25: + case 26: + case 27: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[4]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 28: + case 29: + case 30: + case 31: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[2]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 32: + case 33: + case 34: + case 35: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[1]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 36: + case 37: + case 38: + case 39: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[0]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 40: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[12]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 41: + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[11]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 42: + //auth0 + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[10]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + case 43: + //auth1 + PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[9]); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + default: + PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); + memcpy(datatemp,data + i * 4,4); + if (dump) fwrite ( datatemp, 1, 4, fout ); + break; + } + } + + } else { + PrintAndLog("Command1 execute timeout"); + } + if (dump) fclose(fout); + return 0; +} + +// +// Mifare Ultralight C Write Single Block +// +int CmdHF14AMfUCWrBl(const char *Cmd){ + + uint8_t blockNo = 0; + bool chinese_card=0; + uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + UsbCommand resp; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mfu ucwrbl [w]"); + PrintAndLog(" sample: hf mfu uwrbl 0 01020304"); + return 0; + } + blockNo = param_get8(Cmd, 0); + if (blockNo>(MAX_ULTRAC_BLOCKS+4)){ + PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight Cards!"); + return 1; + } + if (param_gethex(Cmd, 1, bldata, 8)) { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + if (strchr(Cmd,'w') != 0) { + chinese_card=1; + } + switch(blockNo){ + case 0: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 1: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 2: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(c.d.asBytes, bldata, 4); + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 3: + PrintAndLog("--specialblock no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + default: + PrintAndLog("--block no:%02x", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(e.d.asBytes,bldata, 4); + SendCommand(&e); + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + } + return 0; +} + +//------------------------------------ +// Menu Stuff +//------------------------------------ +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1,"This help"}, + {"dbg", CmdHF14AMfDbg, 0,"Set default debug mode"}, + {"urdbl", CmdHF14AMfURdBl, 0,"Read MIFARE Ultralight block"}, + {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, + {"udump", CmdHF14AMfUDump, 0,"Dump MIFARE Ultralight tag to binary file"}, + {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, + {"ucrdbl", CmdHF14AMfUCRdBl, 0,"Read MIFARE Ultralight C block"}, + {"ucrdcard",CmdHF14AMfUCRdCard, 0,"Read MIFARE Ultralight C Card"}, + {"ucdump", CmdHF14AMfUCDump, 0,"Dump MIFARE Ultralight C tag to binary file"}, + {"ucwrbl", CmdHF14AMfUCWrBl, 0,"Write MIFARE Ultralight C block"}, + {"auth", CmdHF14AMfucAuth, 0,"Ultralight C Authentication"}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFMFUltra(const char *Cmd){ + // flush + WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd){ + CmdsHelp(CommandTable); + return 0; +} \ No newline at end of file diff --git a/client/cmdhfmfu.h b/client/cmdhfmfu.h new file mode 100644 index 00000000..20f25d1d --- /dev/null +++ b/client/cmdhfmfu.h @@ -0,0 +1,16 @@ +#include "cmdhfmf.h" + +//standard ultralight +int CmdHF14AMfUWrBl(const char *Cmd); +int CmdHF14AMfURdBl(const char *Cmd); +int CmdHF14AMfURdCard(const char *Cmd); +int CmdHF14AMfUDump(const char *Cmd); +//Crypto Cards +int CmdHF14AMfUCRdBl(const char *Cmd); +int CmdHF14AMfUCRdCard(const char *Cmd); +int CmdHF14AMfUCDump(const char *Cmd); +int CmdHF14AMfucAuth(const char *Cmd); +void rol (uint8_t *data, const size_t len); + +//general stuff +int CmdHFMFUltra(const char *Cmd); diff --git a/client/cmdhw.c b/client/cmdhw.c index 4f0f3e38..a526fe86 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -13,7 +13,6 @@ #include #include #include "ui.h" -//#include "proxusb.h" #include "proxmark3.h" #include "cmdparser.h" #include "cmdhw.h" diff --git a/client/cmdlf.c b/client/cmdlf.c index 22aa1e05..71d87f16 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -12,7 +12,6 @@ #include #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "data.h" #include "graph.h" diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index a7312d21..be31e1ea 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -11,14 +11,18 @@ #include #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "graph.h" +#include "cmdmain.h" #include "cmdparser.h" #include "cmddata.h" #include "cmdlf.h" #include "cmdlfem4x.h" +#include "util.h" +#include "data.h" + +char *global_em410xId; static int CmdHelp(const char *Cmd); @@ -139,6 +143,8 @@ retest: PrintAndLog("EM410x Tag ID: %s", id); PrintAndLog("Unique Tag ID: %s", id2); + global_em410xId = id; + /* Stop any loops */ return 1; } @@ -167,8 +173,9 @@ retest: } /* if we've already retested after flipping bits, return */ - if (retested++) + if (retested++){ return 0; + } /* if this didn't work, try flipping bits */ for (i = 0; i < bit2idx; i++) @@ -252,6 +259,7 @@ int CmdEM410xSim(const char *Cmd) int CmdEM410xWatch(const char *Cmd) { int read_h = (*Cmd == 'h'); + //char k; do { CmdLFRead(read_h ? "h" : ""); @@ -264,7 +272,22 @@ int CmdEM410xWatch(const char *Cmd) // Changed by martin, 4000 x 4 = 16000, // see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235 CmdSamples("16000"); + } while ( + !CmdEM410xRead("") + ); + return 0; +} + +int CmdEM410xWatchnSpoof(const char *Cmd) +{ + int read_h = (*Cmd == 'h'); + do + { + CmdLFRead(read_h ? "h" : ""); + CmdSamples("16000"); } while ( ! CmdEM410xRead("")); + PrintAndLog("# Replaying : %s",global_em410xId); + CmdEM410xSim(global_em410xId); return 0; } @@ -482,12 +505,12 @@ int CmdEM410xWrite(const char *Cmd) int CmdReadWord(const char *Cmd) { - int Word = 16; //default to invalid word + int Word = -1; //default to invalid word UsbCommand c; sscanf(Cmd, "%d", &Word); - if (Word > 15) { + if ( (Word > 15) | (Word < 0) ) { PrintAndLog("Word must be between 0 and 15"); return 1; } @@ -500,18 +523,37 @@ int CmdReadWord(const char *Cmd) c.arg[1] = Word; c.arg[2] = 0; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + size_t bytelength = 4096; + uint8_t data[bytelength]; + memset(data, 0x00, bytelength); + + GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < bytelength; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = bytelength; + RepaintGraphWindow(); + + manchester_decode(data, bytelength); + + free(data); + return 0; } int CmdReadWordPWD(const char *Cmd) { - int Word = 16; //default to invalid word + int Word = -1; //default to invalid word int Password = 0xFFFFFFFF; //default to blank password UsbCommand c; sscanf(Cmd, "%d %x", &Word, &Password); - if (Word > 15) { + if ( (Word > 15) | (Word < 0) ) { PrintAndLog("Word must be between 0 and 15"); return 1; } @@ -524,6 +566,24 @@ int CmdReadWordPWD(const char *Cmd) c.arg[1] = Word; c.arg[2] = Password; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + size_t bytelength = 4096; + uint8_t data[bytelength]; + memset(data, 0x00, bytelength); + + GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < bytelength; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = bytelength; + RepaintGraphWindow(); + + manchester_decode(data, bytelength); + + free(data); return 0; } @@ -581,15 +641,16 @@ int CmdWriteWordPWD(const char *Cmd) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, - {"em410xsim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, - {"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, - {"em410xwrite", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, - {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, - {"readword", CmdReadWord, 1, " -- Read EM4xxx word data"}, - {"readwordPWD", CmdReadWordPWD, 1, " -- Read EM4xxx word data in password mode"}, - {"writeword", CmdWriteWord, 1, " -- Write EM4xxx word data"}, - {"writewordPWD", CmdWriteWordPWD, 1, " -- Write EM4xxx word data in password mode"}, + {"410read", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, + {"410sim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, + {"410watch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, + {"410spoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, + {"410write", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, + {"4xread", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, + {"rd", CmdReadWord, 1, " -- Read EM4xxx word data"}, + {"rdpwd", CmdReadWordPWD, 1, " -- Read EM4xxx word data in password mode "}, + {"wr", CmdWriteWord, 1, " -- Write EM4xxx word data"}, + {"wrpwd", CmdWriteWordPWD, 1, " -- Write EM4xxx word data in password mode"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index dd413d2e..9dd11f18 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -10,7 +10,6 @@ #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "graph.h" diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index af61bd36..038ec887 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -12,13 +12,12 @@ #include #include #include "data.h" -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" -#include "common.h" +#include "../include/common.h" #include "util.h" -#include "hitag2.h" +#include "../include/hitag2.h" #include "sleep.h" #include "cmdmain.h" diff --git a/client/cmdlfio.c b/client/cmdlfio.c index a3d79b2b..d7d36bc1 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -3,7 +3,6 @@ #include #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "data.h" #include "graph.h" diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index 13917146..0d8fb93d 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -10,7 +10,6 @@ #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "graph.h" diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 9783370c..5a464ddb 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -10,55 +10,88 @@ #include #include #include -//#include "proxusb.h" #include "proxmark3.h" #include "ui.h" #include "graph.h" +#include "cmdmain.h" #include "cmdparser.h" #include "cmddata.h" #include "cmdlf.h" #include "cmdlft55xx.h" +#include "util.h" +#include "data.h" +#define LF_TRACE_BUFF_SIZE 16000 static int CmdHelp(const char *Cmd); int CmdReadBlk(const char *Cmd) { - int Block = 8; //default to invalid block + //default to invalid block + int Block = -1; UsbCommand c; sscanf(Cmd, "%d", &Block); - if (Block > 7) { + if ((Block > 7) | (Block < 0)) { PrintAndLog("Block must be between 0 and 7"); return 1; } - PrintAndLog("Reading block %d", Block); + PrintAndLog(" Reading page 0 block : %d", Block); + // this command fills up BigBuff + // c.cmd = CMD_T55XX_READ_BLOCK; - c.d.asBytes[0] = 0x0; //Normal mode + c.d.asBytes[0] = 0x00; c.arg[0] = 0; c.arg[1] = Block; c.arg[2] = 0; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + uint8_t data[LF_TRACE_BUFF_SIZE]; + memset(data, 0x00, LF_TRACE_BUFF_SIZE); + + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = LF_TRACE_BUFF_SIZE; + + // BiDirectional + CmdDirectionalThreshold("70 -60"); + + // Askdemod + Cmdaskdemod("1"); + + uint8_t bits[1000]; + uint8_t * bitstream = bits; + uint8_t len = 0; + len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bitstream); + if ( len > 0 ) + PrintPaddedManchester(bitstream, len, 32); + return 0; } + int CmdReadBlkPWD(const char *Cmd) { - int Block = 8; //default to invalid block + int Block = -1; //default to invalid block int Password = 0xFFFFFFFF; //default to blank Block 7 UsbCommand c; sscanf(Cmd, "%d %x", &Block, &Password); - if (Block > 7) { + if ((Block > 7) | (Block < 0)) { PrintAndLog("Block must be between 0 and 7"); return 1; } - PrintAndLog("Reading block %d with password %08X", Block, Password); + PrintAndLog("Reading page 0 block %d pwd %08X", Block, Password); c.cmd = CMD_T55XX_READ_BLOCK; c.d.asBytes[0] = 0x1; //Password mode @@ -66,9 +99,35 @@ int CmdReadBlkPWD(const char *Cmd) c.arg[1] = Block; c.arg[2] = Password; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + uint8_t data[LF_TRACE_BUFF_SIZE]; + memset(data, 0x00, LF_TRACE_BUFF_SIZE); + + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = LF_TRACE_BUFF_SIZE; + + // BiDirectional + CmdDirectionalThreshold("70 -60"); + + // Askdemod + Cmdaskdemod("1"); + + uint8_t bits[1000]; + uint8_t len = 0; + len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bits); + if ( len > 0 ) + PrintPaddedManchester(bits, len, 32); + return 0; } + int CmdWriteBlk(const char *Cmd) { int Block = 8; //default to invalid block @@ -120,11 +179,35 @@ int CmdWriteBlkPWD(const char *Cmd) int CmdReadTrace(const char *Cmd) { - - PrintAndLog("Reading traceability data"); + PrintAndLog(" Reading page 1 - tracedata"); UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}}; SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + uint8_t data[LF_TRACE_BUFF_SIZE]; + memset(data, 0x00, LF_TRACE_BUFF_SIZE); + + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]) - 128; + } + GraphTraceLen = LF_TRACE_BUFF_SIZE; + + // BiDirectional + CmdDirectionalThreshold("70 -60"); + + // Askdemod + Cmdaskdemod("1"); + + uint8_t bits[512]; + uint8_t len = 0; + len = manchester_decode(data,LF_TRACE_BUFF_SIZE,bits); + if ( len > 0 ) + PrintPaddedManchester(bits, len, 64); + return 0; } diff --git a/client/cmdlfti.c b/client/cmdlfti.c index 26128e2f..cb5fcd79 100644 --- a/client/cmdlfti.c +++ b/client/cmdlfti.c @@ -11,7 +11,6 @@ #include #include #include "crc16.h" -//#include "proxusb.h" #include "proxmark3.h" #include "data.h" #include "ui.h" diff --git a/client/cmdmain.c b/client/cmdmain.c index fa358fac..c56aaa63 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -16,7 +16,7 @@ #include "cmdparser.h" #include "proxmark3.h" #include "data.h" -#include "usb_cmd.h" +#include "../include/usb_cmd.h" #include "ui.h" #include "cmdhf.h" #include "cmddata.h" diff --git a/client/cmdmain.h b/client/cmdmain.h index 0cf2b35d..5e4ee73a 100644 --- a/client/cmdmain.h +++ b/client/cmdmain.h @@ -11,7 +11,7 @@ #ifndef CMDMAIN_H__ #define CMDMAIN_H__ -#include "usb_cmd.h" +#include "../include/usb_cmd.h" #include "cmdparser.h" void UsbCommandReceived(UsbCommand *UC); void CommandReceived(char *Cmd); diff --git a/client/data.c b/client/data.c index 51134d48..72acf8a6 100644 --- a/client/data.c +++ b/client/data.c @@ -12,7 +12,6 @@ #include #include "data.h" #include "ui.h" -//#include "proxusb.h" #include "proxmark3.h" #include "cmdmain.h" diff --git a/client/flash.c b/client/flash.c index 3a0a1cda..60c04adc 100644 --- a/client/flash.c +++ b/client/flash.c @@ -13,11 +13,10 @@ #include #include "proxmark3.h" #include "sleep.h" -//#include "proxusb.h" #include "flash.h" #include "elf.h" #include "proxendian.h" -#include "usb_cmd.h" +#include "../include/usb_cmd.h" void SendCommand(UsbCommand* txcmd); void ReceiveCommand(UsbCommand* rxcmd); diff --git a/client/flasher.c b/client/flasher.c index 2a24ba8f..1390d817 100644 --- a/client/flasher.c +++ b/client/flasher.c @@ -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) diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c new file mode 100644 index 00000000..8b1a523d --- /dev/null +++ b/client/loclass/cipher.c @@ -0,0 +1,255 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with IClassCipher. If not, see . + ****************************************************************************/ + +#include "cipher.h" +#include "cipherutils.h" +#include +#include +#include +#include +#include +#include +#include "fileutils.h" +uint8_t keytable[] = { 0,0,0,0,0,0,0,0}; + +/** +* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2 +* consisting of the following four components: +* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ; +* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ; +* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 . +* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 . +**/ +typedef struct { + uint8_t l; + uint8_t r; + uint8_t b; + uint16_t t; +} State; + +/** +* Definition 2. The feedback function for the top register T : F 16/2 → F 2 +* is defined as +* T (x 0 x 1 . . . . . . x 15 ) = x 0 ⊕ x 1 ⊕ x 5 ⊕ x 7 ⊕ x 10 ⊕ x 11 ⊕ x 14 ⊕ x 15 . +**/ +bool T(State state) +{ + bool x0 = state.t & 0x8000; + bool x1 = state.t & 0x4000; + bool x5 = state.t & 0x0400; + bool x7 = state.t & 0x0100; + bool x10 = state.t & 0x0020; + bool x11 = state.t & 0x0010; + bool x14 = state.t & 0x0002; + bool x15 = state.t & 0x0001; + return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15; +} +/** +* Similarly, the feedback function for the bottom register B : F 8/2 → F 2 is defined as +* B(x 0 x 1 . . . x 7 ) = x 1 ⊕ x 2 ⊕ x 3 ⊕ x 7 . +**/ +bool B(State state) +{ + bool x1 = state.b & 0x40; + bool x2 = state.b & 0x20; + bool x3 = state.b & 0x10; + bool x7 = state.b & 0x01; + + return x1 ^ x2 ^ x3 ^ x7; + +} + + +/** +* Definition 3 (Selection function). The selection function select : F 2 × F 2 × +* F 8/2 → F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where +* z 0 = (r 0 ∧ r 2 ) ⊕ (r 1 ∧ r 3 ) ⊕ (r 2 ∨ r 4 ) +* z 1 = (r 0 ∨ r 2 ) ⊕ (r 5 ∨ r 7 ) ⊕ r 1 ⊕ r 6 ⊕ x ⊕ y +* z 2 = (r 3 ∧ r 5 ) ⊕ (r 4 ∧ r 6 ) ⊕ r 7 ⊕ x +**/ +uint8_t _select(bool x, bool y, uint8_t r) +{ + bool r0 = r >> 7 & 0x1; + bool r1 = r >> 6 & 0x1; + bool r2 = r >> 5 & 0x1; + bool r3 = r >> 4 & 0x1; + bool r4 = r >> 3 & 0x1; + bool r5 = r >> 2 & 0x1; + bool r6 = r >> 1 & 0x1; + bool r7 = r & 0x1; + + bool z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); + bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; + bool z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; + + // The three bitz z0.. z1 are packed into a uint8_t: + // 00000ZZZ + //Return value is a uint8_t + uint8_t retval = 0; + retval |= (z0 << 2) & 4; + retval |= (z1 << 1) & 2; + retval |= z2 & 1; + + // Return value 0 <= retval <= 7 + return retval; +} + +/** +* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k ∈ (F 82 ) 8 +* be a key and y ∈ F 2 be the input bit. Then, the successor cipher state s ′ = +* l ′ , r ′ , t ′ , b ′ is defined as +* t ′ := (T (t) ⊕ r 0 ⊕ r 4 )t 0 . . . t 14 l ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l ⊞ r +* b ′ := (B(b) ⊕ r 7 )b 0 . . . b 6 r ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l +* +* @param s - state +* @param k - array containing 8 bytes +**/ +State successor(uint8_t* k, State s, bool y) +{ + bool r0 = s.r >> 7 & 0x1; + bool r4 = s.r >> 3 & 0x1; + bool r7 = s.r & 0x1; + + State successor = {0,0,0,0}; + + successor.t = s.t >> 1; + successor.t |= (T(s) ^ r0 ^ r4) << 15; + + successor.b = s.b >> 1; + successor.b |= (B(s) ^ r7) << 7; + + bool Tt = T(s); + + successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF; + successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF; + + return successor; +} +/** +* We define the successor function suc which takes a key k ∈ (F 82 ) 8 , a state s and +* an input y ∈ F 2 and outputs the successor state s ′ . We overload the function suc +* to multiple bit input x ∈ F n 2 which we define as +* @param k - array containing 8 bytes +**/ +State suc(uint8_t* k,State s, BitstreamIn *bitstream) +{ + if(bitsLeft(bitstream) == 0) + { + return s; + } + bool lastbit = tailBit(bitstream); + return successor(k,suc(k,s,bitstream), lastbit); +} + +/** +* Definition 5 (Output). Define the function output which takes an internal +* state s =< l, r, t, b > and returns the bit r 5 . We also define the function output +* on multiple bits input which takes a key k, a state s and an input x ∈ F n 2 as +* output(k, s, Ç«) = Ç« +* output(k, s, x 0 . . . x n ) = output(s) · output(k, s ′ , x 1 . . . x n ) +* where s ′ = suc(k, s, x 0 ). +**/ +void output(uint8_t* k,State s, BitstreamIn* in, BitstreamOut* out) +{ + if(bitsLeft(in) == 0) + { + return; + } + pushBit(out,(s.r >> 2) & 1); + //Remove first bit + uint8_t x0 = headBit(in); + State ss = successor(k,s,x0); + output(k,ss,in, out); +} + +/** +* Definition 6 (Initial state). Define the function init which takes as input a +* key k ∈ (F 82 ) 8 and outputs the initial cipher state s =< l, r, t, b > +**/ + +State init(uint8_t* k) +{ + State s = { + ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l + ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r + 0x4c, // b + 0xE012 // t + }; + return s; +} +void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out) +{ + uint8_t zeroes_32[] = {0,0,0,0}; + 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, int length, uint8_t *div_key_p, uint8_t mac[4]) +{ + uint8_t *cc_nr; + uint8_t div_key[8]; + cc_nr=(uint8_t*)malloc(length+1); + memcpy(cc_nr,cc_nr_p,length); + memcpy(div_key,div_key_p,8); + + reverse_arraybytes(cc_nr,length); + BitstreamIn bitstream = {cc_nr,length * 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); + //printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]); + free(cc_nr); + return; +} + +int testMAC() +{ + prnlog("[+] Testing MAC calculation..."); + + //From the "dismantling.IClass" paper: + uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0}; + //From the paper + uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9}; + uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA}; + + uint8_t calculated_mac[4] = {0}; + doMAC(cc_nr, 12,div_key, calculated_mac); + + if(memcmp(calculated_mac, correct_MAC,4) == 0) + { + prnlog("[+] MAC calculation OK!"); + + }else + { + prnlog("[+] FAILED: MAC calculation failed:"); + printarr(" Calculated_MAC", calculated_mac, 4); + printarr(" Correct_MAC ", correct_MAC, 4); + return 1; +} + + return 0; +} diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h new file mode 100644 index 00000000..4bfbe0b7 --- /dev/null +++ b/client/loclass/cipher.h @@ -0,0 +1,31 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with IClassCipher. If not, see . + ****************************************************************************/ + +#ifndef CIPHER_H +#define CIPHER_H +#include + +void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4]); +int testMAC(); + +#endif // CIPHER_H diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c new file mode 100644 index 00000000..1e08cf10 --- /dev/null +++ b/client/loclass/cipherutils.c @@ -0,0 +1,273 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with IClassCipher. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include "fileutils.h" +#include "cipherutils.h" +/** + * + * @brief Return and remove the first bit (x0) in the stream : + * @param stream + * @return + */ +bool headBit( BitstreamIn *stream) +{ + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = (stream->position++) & 7; // mask out 00000111 + return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1; +} +/** + * @brief Return and remove the last bit (xn) in the stream: + * @param stream + * @return + */ +bool tailBit( BitstreamIn *stream) +{ + int bitpos = stream->numbits -1 - (stream->position++); + + int bytepos= bitpos >> 3; + bitpos &= 7; + return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1; +} +/** + * @brief Pushes bit onto the stream + * @param stream + * @param bit + */ +void pushBit( BitstreamOut* stream, bool bit) +{ + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = stream->position & 7; + *(stream->buffer+bytepos) |= (bit & 1) << (7 - bitpos); + stream->position++; + stream->numbits++; +} + +/** + * @brief Pushes the lower six bits onto the stream + * as b0 b1 b2 b3 b4 b5 b6 + * @param stream + * @param bits + */ +void push6bits( BitstreamOut* stream, uint8_t bits) +{ + pushBit(stream, bits & 0x20); + pushBit(stream, bits & 0x10); + pushBit(stream, bits & 0x08); + pushBit(stream, bits & 0x04); + pushBit(stream, bits & 0x02); + pushBit(stream, bits & 0x01); +} + +/** + * @brief bitsLeft + * @param stream + * @return number of bits left in stream + */ +int bitsLeft( BitstreamIn *stream) +{ + return stream->numbits - stream->position; +} +/** + * @brief numBits + * @param stream + * @return Number of bits stored in stream + */ +int numBits(BitstreamOut *stream) +{ + return stream->numbits; +} + +void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest) +{ + while (len--) { + dest[len] = (uint8_t) n; + n >>= 8; + } +} + +uint64_t x_bytes_to_num(uint8_t* src, size_t len) +{ + uint64_t num = 0; + while (len--) + { + num = (num << 8) | (*src); + src++; + } + return num; +} +uint8_t reversebytes(uint8_t b) { + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} +void reverse_arraybytes(uint8_t* arr, size_t len) +{ + uint8_t i; + for( i =0; i< len ; i++) + { + arr[i] = reversebytes(arr[i]); + } +} +void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len) +{ + uint8_t i; + for( i =0; i< len ; i++) + { + dest[i] = reversebytes(arr[i]); + } +} + +void printarr(char * name, uint8_t* arr, int len) +{ + int cx; + size_t outsize = 40+strlen(name)+len*5; + char* output = malloc(outsize); + memset(output, 0,outsize); + + int i ; + cx = snprintf(output,outsize, "uint8_t %s[] = {", name); + for(i =0 ; i< len ; i++) + { + cx += snprintf(output+cx,outsize-cx,"0x%02x,",*(arr+i));//5 bytes per byte + } + cx += snprintf(output+cx,outsize-cx,"};"); + prnlog(output); +} + +void printvar(char * name, uint8_t* arr, int len) +{ + int cx; + size_t outsize = 40+strlen(name)+len*2; + char* output = malloc(outsize); + memset(output, 0,outsize); + + int i ; + cx = snprintf(output,outsize,"%s = ", name); + for(i =0 ; i< len ; i++) + { + cx += snprintf(output+cx,outsize-cx,"%02x",*(arr+i));//2 bytes per byte + } + + prnlog(output); +} + +void printarr_human_readable(char * title, uint8_t* arr, int len) +{ + int cx; + size_t outsize = 100+strlen(title)+len*4; + char* output = malloc(outsize); + memset(output, 0,outsize); + + + int i; + cx = snprintf(output,outsize, "\n\t%s\n", title); + for(i =0 ; i< len ; i++) + { + if(i % 16 == 0) + cx += snprintf(output+cx,outsize-cx,"\n%02x| ", i ); + cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i)); + } + prnlog(output); +} + +//----------------------------- +// Code for testing below +//----------------------------- + + +int testBitStream() +{ + uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF}; + uint8_t output [] = {0,0,0,0,0,0,0,0}; + BitstreamIn in = { input, sizeof(input) * 8,0}; + BitstreamOut out ={ output, 0,0} + ; + while(bitsLeft(&in) > 0) + { + pushBit(&out, headBit(&in)); + //printf("Bits left: %d\n", bitsLeft(&in)); + //printf("Bits out: %d\n", numBits(&out)); + } + if(memcmp(input, output, sizeof(input)) == 0) + { + prnlog(" Bitstream test 1 ok"); + }else + { + prnlog(" Bitstream test 1 failed"); + uint8_t i; + for(i = 0 ; i < sizeof(input) ; i++) + { + prnlog(" IN %02x, OUT %02x", input[i], output[i]); + } + return 1; + } + return 0; +} + +int testReversedBitstream() +{ + uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF}; + uint8_t reverse [] = {0,0,0,0,0,0,0,0}; + uint8_t output [] = {0,0,0,0,0,0,0,0}; + BitstreamIn in = { input, sizeof(input) * 8,0}; + BitstreamOut out ={ output, 0,0}; + BitstreamIn reversed_in ={ reverse, sizeof(input)*8,0}; + BitstreamOut reversed_out ={ reverse,0 ,0}; + + while(bitsLeft(&in) > 0) + { + pushBit(&reversed_out, tailBit(&in)); + } + while(bitsLeft(&reversed_in) > 0) + { + pushBit(&out, tailBit(&reversed_in)); + } + if(memcmp(input, output, sizeof(input)) == 0) + { + prnlog(" Bitstream test 2 ok"); + }else + { + prnlog(" Bitstream test 2 failed"); + uint8_t i; + for(i = 0 ; i < sizeof(input) ; i++) + { + prnlog(" IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]); + } + return 1; + } + return 0; +} + + +int testCipherUtils(void) +{ + prnlog("[+] Testing some internals..."); + int retval = 0; + retval |= testBitStream(); + retval |= testReversedBitstream(); + return retval; +} diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h new file mode 100644 index 00000000..acf96115 --- /dev/null +++ b/client/loclass/cipherutils.h @@ -0,0 +1,59 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with IClassCipher. If not, see . + ****************************************************************************/ + +#ifndef CIPHERUTILS_H +#define CIPHERUTILS_H +#include +#include +#include + +typedef struct { + uint8_t * buffer; + uint8_t numbits; + uint8_t position; +} BitstreamIn; + +typedef struct { + uint8_t * buffer; + uint8_t numbits; + uint8_t position; +}BitstreamOut; + +bool headBit( BitstreamIn *stream); +bool tailBit( BitstreamIn *stream); +void pushBit( BitstreamOut *stream, bool bit); +int bitsLeft( BitstreamIn *stream); + +int testCipherUtils(void); +int testMAC(); +void push6bits( BitstreamOut* stream, uint8_t bits); +void EncryptDES(bool key[56], bool outBlk[64], bool inBlk[64], int verbose) ; +void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest); +uint64_t x_bytes_to_num(uint8_t* src, size_t len); +uint8_t reversebytes(uint8_t b); +void reverse_arraybytes(uint8_t* arr, size_t len); +void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len); +void printarr(char * name, uint8_t* arr, int len); +void printvar(char * name, uint8_t* arr, int len); +void printarr_human_readable(char * title, uint8_t* arr, int len); +#endif // CIPHERUTILS_H diff --git a/client/loclass/des.c b/client/loclass/des.c new file mode 100644 index 00000000..746752d7 --- /dev/null +++ b/client/loclass/des.c @@ -0,0 +1,1014 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2014, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +//#include "polarssl/config.h" +#define POLARSSL_DES_C + +#if defined(POLARSSL_DES_C) + +#include "des.h" + +#if defined(POLARSSL_PLATFORM_C) +#include "polarssl/platform.h" +#else +#define polarssl_printf printf +#endif + +#if !defined(POLARSSL_DES_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const uint32_t SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const uint32_t SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const uint32_t SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const uint32_t SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const uint32_t SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const uint32_t SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const uint32_t SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const uint32_t SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const uint32_t LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const uint32_t RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; } + +static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, + 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44, + 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81, + 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112, + 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140, + 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168, + 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196, + 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224, + 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253, + 254 }; + +void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < DES_KEY_SIZE; i++ ) + key[i] = odd_parity_table[key[i] / 2]; +} + +/* + * Check the given key's parity, returns 1 on failure, 0 on SUCCESS + */ +int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < DES_KEY_SIZE; i++ ) + if ( key[i] != odd_parity_table[key[i] / 2] ) + return( 1 ); + + return( 0 ); +} + +/* + * Table of weak and semi-weak keys + * + * Source: http://en.wikipedia.org/wiki/Weak_key + * + * Weak: + * Alternating ones + zeros (0x0101010101010101) + * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE) + * '0xE0E0E0E0F1F1F1F1' + * '0x1F1F1F1F0E0E0E0E' + * + * Semi-weak: + * 0x011F011F010E010E and 0x1F011F010E010E01 + * 0x01E001E001F101F1 and 0xE001E001F101F101 + * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01 + * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E + * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E + * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1 + * + */ + +#define WEAK_KEY_COUNT 16 + +static const unsigned char weak_key_table[WEAK_KEY_COUNT][DES_KEY_SIZE] = +{ + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E }, + { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 }, + + { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E }, + { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 }, + { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 }, + { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 }, + { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE }, + { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 }, + { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 }, + { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E }, + { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, + { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E }, + { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE }, + { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 } +}; + +int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < WEAK_KEY_COUNT; i++ ) + if( memcmp( weak_key_table[i], key, DES_KEY_SIZE) == 0) + return( 1 ); + + return( 0 ); +} + +static void des_setkey( uint32_t SK[32], const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + uint32_t X, Y, T; + + GET_UINT32_BE( X, key, 0 ); + GET_UINT32_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} + +/* + * DES key schedule (56-bit, encryption) + */ +int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ) +{ + des_setkey( ctx->sk, key ); + + return( 0 ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } + + return( 0 ); +} + +static void des3_set2key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[DES_KEY_SIZE*2] ) +{ + int i; + + des_setkey( esk, key ); + des_setkey( dsk + 32, key + 8 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[30 - i]; + dsk[i + 1] = esk[31 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + esk[i + 64] = esk[i ]; + esk[i + 65] = esk[i + 1]; + + dsk[i + 64] = dsk[i ]; + dsk[i + 65] = dsk[i + 1]; + } +} + +/* + * Triple-DES key schedule (112-bit, encryption) + */ +int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( ctx->sk, sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (112-bit, decryption) + */ +int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( sk, ctx->sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +static void des3_set3key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[24] ) +{ + int i; + + des_setkey( esk, key ); + des_setkey( dsk + 32, key + 8 ); + des_setkey( esk + 64, key + 16 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[94 - i]; + dsk[i + 1] = esk[95 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + dsk[i + 64] = esk[30 - i]; + dsk[i + 65] = esk[31 - i]; + } +} + +/* + * Triple-DES key schedule (168-bit, encryption) + */ +int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( ctx->sk, sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (168-bit, decryption) + */ +int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( sk, ctx->sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * DES-ECB block encryption/decryption + */ +int des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} + +#if defined(POLARSSL_CIPHER_MODE_CBC) +/* + * DES-CBC buffer encryption/decryption + */ +int des_crypt_cbc( des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + des_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + des_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +/* + * 3DES-ECB block encryption/decryption + */ +int des3_crypt_ecb( des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( X, Y ); + DES_ROUND( Y, X ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} + +#if defined(POLARSSL_CIPHER_MODE_CBC) +/* + * 3DES-CBC buffer encryption/decryption + */ +int des3_crypt_cbc( des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + des3_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + des3_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +#endif /* !POLARSSL_DES_ALT */ + +#if defined(POLARSSL_SELF_TEST) + +#include + +/* + * DES and 3DES test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip + */ +static const unsigned char des3_test_keys[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_buf[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char des3_test_ecb_dec[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +static const unsigned char des3_test_ecb_enc[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +#if defined(POLARSSL_CIPHER_MODE_CBC) +static const unsigned char des3_test_iv[8] = +{ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +static const unsigned char des3_test_cbc_dec[3][8] = +{ + { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, + { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, + { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } +}; + +static const unsigned char des3_test_cbc_enc[3][8] = +{ + { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, + { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, + { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } +}; +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +/* + * Checkup routine + */ +int des_self_test( int verbose ) +{ + int i, j, u, v; + des_context ctx; + des3_context ctx3; + unsigned char key[24]; + unsigned char buf[8]; +#if defined(POLARSSL_CIPHER_MODE_CBC) + unsigned char prv[8]; + unsigned char iv[8]; +#endif + + memset( key, 0, 24 ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + polarssl_printf( " DES%c-ECB-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + des_crypt_ecb( &ctx, buf, buf ); + else + des3_crypt_ecb( &ctx3, buf, buf ); + } + + if( ( v == DES_DECRYPT && + memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || + ( v != DES_DECRYPT && + memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + polarssl_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } + + if( verbose != 0 ) + polarssl_printf( "\n" ); + +#if defined(POLARSSL_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + polarssl_printf( " DES%c-CBC-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, des3_test_iv, 8 ); + memcpy( prv, des3_test_iv, 8 ); + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + if( v == DES_DECRYPT ) + { + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + } + } + else + { + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[8]; + + if( u == 0 ) + des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + + memcpy( tmp, prv, 8 ); + memcpy( prv, buf, 8 ); + memcpy( buf, tmp, 8 ); + } + + memcpy( buf, prv, 8 ); + } + + if( ( v == DES_DECRYPT && + memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || + ( v != DES_DECRYPT && + memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + polarssl_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } +#endif /* POLARSSL_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + polarssl_printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/client/loclass/des.h b/client/loclass/des.h new file mode 100644 index 00000000..907d56b1 --- /dev/null +++ b/client/loclass/des.h @@ -0,0 +1,256 @@ +/** + * \file des.h + * + * \brief DES block cipher + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_DES_H +#define POLARSSL_DES_H + +//#include "config.h" + +#include + +#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ + +#define DES_KEY_SIZE 8 + +#if !defined(POLARSSL_DES_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + uint32_t sk[32]; /*!< DES subkeys */ +} +des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + uint32_t sk[96]; /*!< 3DES subkeys */ +} +des3_context; + +/** + * \brief Set key parity on the given key to odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + */ +void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Check that key parity on the given key is odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \return 0 is parity was ok, 1 if parity was not correct. + */ +int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Check that key is not a weak or semi-weak DES key + * + * \param key 8-byte secret key + * + * \return 0 if no weak key was found, 1 if a weak key was identified. + */ +int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(POLARSSL_CIPHER_MODE_CBC) +/** + * \brief DES-CBC buffer encryption/decryption + * + * \param ctx DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + */ +int des_crypt_cbc( des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int des3_crypt_ecb( des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(POLARSSL_CIPHER_MODE_CBC) +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \param ctx 3DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH + */ +int des3_crypt_cbc( des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* POLARSSL_CIPHER_MODE_CBC */ + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_DES_ALT */ +#include "des_alt.h" +#endif /* POLARSSL_DES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c new file mode 100644 index 00000000..1a464b6c --- /dev/null +++ b/client/loclass/elite_crack.c @@ -0,0 +1,656 @@ +#include +#include +#include +#include +#include +#include "cipherutils.h" +#include "cipher.h" +#include "ikeys.h" +#include "elite_crack.h" +#include "fileutils.h" +#include "des.h" + +/** + * @brief Permutes a key from standard NIST format to Iclass specific format + * from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220 + * + * If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below. + * + * 1 0 1 1 1 1 1 1 bf + * 0 0 0 0 0 0 0 1 01 + * 0 0 1 0 1 1 0 1 2d + * 0 0 1 0 1 0 1 0 2a + * 1 1 1 1 1 0 0 1 f9 + * 0 1 0 0 0 1 0 0 44 + * 1 0 0 0 1 1 0 1 8d + * 0 1 1 0 1 1 0 0 6c + * + * 8 0 b 8 b a 9 e + * a d 9 8 b 7 0 a + * + * @param key + * @param dest + */ +void permutekey(uint8_t key[8], uint8_t dest[8]) +{ + + int i; + for(i = 0 ; i < 8 ; i++) + { + dest[i] = (((key[7] & (0x80 >> i)) >> (7-i)) << 7) | + (((key[6] & (0x80 >> i)) >> (7-i)) << 6) | + (((key[5] & (0x80 >> i)) >> (7-i)) << 5) | + (((key[4] & (0x80 >> i)) >> (7-i)) << 4) | + (((key[3] & (0x80 >> i)) >> (7-i)) << 3) | + (((key[2] & (0x80 >> i)) >> (7-i)) << 2) | + (((key[1] & (0x80 >> i)) >> (7-i)) << 1) | + (((key[0] & (0x80 >> i)) >> (7-i)) << 0); + } + + return; +} +/** + * Permutes a key from iclass specific format to NIST format + * @brief permutekey_rev + * @param key + * @param dest + */ +void permutekey_rev(uint8_t key[8], uint8_t dest[8]) +{ + int i; + for(i = 0 ; i < 8 ; i++) + { + dest[7-i] = (((key[0] & (0x80 >> i)) >> (7-i)) << 7) | + (((key[1] & (0x80 >> i)) >> (7-i)) << 6) | + (((key[2] & (0x80 >> i)) >> (7-i)) << 5) | + (((key[3] & (0x80 >> i)) >> (7-i)) << 4) | + (((key[4] & (0x80 >> i)) >> (7-i)) << 3) | + (((key[5] & (0x80 >> i)) >> (7-i)) << 2) | + (((key[6] & (0x80 >> i)) >> (7-i)) << 1) | + (((key[7] & (0x80 >> i)) >> (7-i)) << 0); + } +} + +/** + * Helper function for hash1 + * @brief rr + * @param val + * @return + */ +uint8_t rr(uint8_t val) +{ + return val >> 1 | (( val & 1) << 7); +} +/** + * Helper function for hash1 + * @brief rl + * @param val + * @return + */ +uint8_t rl(uint8_t val) +{ + return val << 1 | (( val & 0x80) >> 7); +} +/** + * Helper function for hash1 + * @brief swap + * @param val + * @return + */ +uint8_t swap(uint8_t val) +{ + return ((val >> 4) & 0xFF) | ((val &0xFF) << 4); +} + +/** + * Hash1 takes CSN as input, and determines what bytes in the keytable will be used + * when constructing the K_sel. + * @param csn the CSN used + * @param k output + */ +void hash1(uint8_t csn[] , uint8_t k[]) +{ + k[0] = csn[0]^csn[1]^csn[2]^csn[3]^csn[4]^csn[5]^csn[6]^csn[7]; + k[1] = csn[0]+csn[1]+csn[2]+csn[3]+csn[4]+csn[5]+csn[6]+csn[7]; + k[2] = rr(swap( csn[2]+k[1] )); + k[3] = rr(swap( csn[3]+k[0] )); + k[4] = ~rr(swap( csn[4]+k[2] ))+1; + k[5] = ~rr(swap( csn[5]+k[3] ))+1; + k[6] = rr( csn[6]+(k[4]^0x3c) ); + k[7] = rl( csn[7]+(k[5]^0xc3) ); + int i; + for(i = 7; i >=0; i--) + k[i] = k[i] & 0x7F; +} +/** +Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8 as +rk(x [0] . . . x [7] , 0) = x [0] . . . x [7] +rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n) +**/ +void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) +{ + + memcpy(outp_key, key, 8); + + uint8_t j; + + while(n-- > 0) + for(j=0; j < 8 ; j++) + outp_key[j] = rl(outp_key[j]); + + return; +} + +static des_context ctx_enc = {DES_ENCRYPT,{0}}; +static des_context ctx_dec = {DES_DECRYPT,{0}}; + +void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) +{ + uint8_t key_std_format[8] = {0}; + permutekey_rev(iclass_key, key_std_format); + des_setkey_dec( &ctx_dec, key_std_format); + des_crypt_ecb(&ctx_dec,input,output); +} +void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) +{ + uint8_t key_std_format[8] = {0}; + permutekey_rev(iclass_key, key_std_format); + des_setkey_enc( &ctx_enc, key_std_format); + des_crypt_ecb(&ctx_enc,input,output); +} + +/** + * @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select. + * @param key unpermuted custom key + * @param hash1 hash1 + * @param key_sel output key_sel=h[hash1[i]] + */ +void hash2(uint8_t *key64, uint8_t *outp_keytable) +{ + /** + *Expected: + * High Security Key Table + +00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 +10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 +20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2 +30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C +40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6 +50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42 +60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95 +70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB + +**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/ + uint8_t key64_negated[8] = {0}; + uint8_t z[8][8]={{0},{0}}; + uint8_t temp_output[8]={0}; + //calculate complement of key + int i; + for(i=0;i<8;i++) + key64_negated[i]= ~key64[i]; + + // Once again, key is on iclass-format + desencrypt_iclass(key64, key64_negated, z[0]); + + prnlog("\nHigh security custom key (Kcus):"); + printvar("z0 ", z[0],8); + + uint8_t y[8][8]={{0},{0}}; + + // y[0]=DES_dec(z[0],~key) + // Once again, key is on iclass-format + desdecrypt_iclass(z[0], key64_negated, y[0]); + printvar("y0 ", y[0],8); + + for(i=1; i<8; i++) + { + + // z [i] = DES dec (rk(K cus , i), z [i−1] ) + rk(key64, i, temp_output); + //y [i] = DES enc (rk(K cus , i), y [i−1] ) + + desdecrypt_iclass(temp_output,z[i-1], z[i]); + desencrypt_iclass(temp_output,y[i-1], y[i]); + + } + if(outp_keytable != NULL) + { + for(i = 0 ; i < 8 ; i++) + { + memcpy(outp_keytable+i*16,y[i],8); + memcpy(outp_keytable+8+i*16,z[i],8); + } + }else + { + printarr_human_readable("hash2", outp_keytable,128); + } +} + +/** + * @brief Reads data from the iclass-reader-attack dump file. + * @param dump, data from a iclass reader attack dump. The format of the dumpdata is expected to be as follows: + * <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER> + * .. N times... + * + * So the first attack, with 3 bytes to recover would be : ... 03000145 + * And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000 + * And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700 + * + * @param cc_nr an array to store cc_nr into (12 bytes) + * @param csn an arracy ot store CSN into (8 bytes) + * @param received_mac an array to store MAC into (4 bytes) + * @param i the number to read. Should be less than 127, or something is wrong... + * @return + */ +int _readFromDump(uint8_t dump[], dumpdata* item, uint8_t i) +{ + size_t itemsize = sizeof(dumpdata); + //dumpdata item = {0}; + memcpy(item,dump+i*itemsize, itemsize); + if(true) + { + printvar("csn", item->csn,8); + printvar("cc_nr", item->cc_nr,12); + printvar("mac", item->mac,4); + } + return 0; +} + +static uint32_t startvalue = 0; +/** + * @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac. + *This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced + *on the fly. If it finds that more than three bytes need to be bruteforced, it aborts. + *It updates the keytable with the findings, also using the upper half of the 16-bit ints + *to signal if the particular byte has been cracked or not. + * + * @param dump The dumpdata from iclass reader attack. + * @param keytable where to write found values. + * @return + */ +int bruteforceItem(dumpdata item, uint16_t keytable[]) +{ + int errors = 0; + uint8_t key_sel_p[8] = { 0 }; + uint8_t div_key[8] = {0}; + int found = false; + uint8_t key_sel[8] = {0}; + uint8_t calculated_MAC[4] = { 0 }; + + //Get the key index (hash1) + uint8_t key_index[8] = {0}; + hash1(item.csn, key_index); + + + /* + * Determine which bytes to retrieve. A hash is typically + * 01010000454501 + * We go through that hash, and in the corresponding keytable, we put markers + * on what state that particular index is: + * - CRACKED (this has already been cracked) + * - BEING_CRACKED (this is being bruteforced now) + * - CRACK_FAILED (self-explaining...) + * + * The markers are placed in the high area of the 16 bit key-table. + * Only the lower eight bits correspond to the (hopefully cracked) key-value. + **/ + uint8_t bytes_to_recover[3] = {0}; + uint8_t numbytes_to_recover = 0 ; + int i; + for(i =0 ; i < 8 ; i++) + { + if(keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue; + bytes_to_recover[numbytes_to_recover++] = key_index[i]; + keytable[key_index[i]] |= BEING_CRACKED; + + if(numbytes_to_recover > 3) + { + prnlog("The CSN requires > 3 byte bruteforce, not supported"); + printvar("CSN", item.csn,8); + printvar("HASH1", key_index,8); + + //Before we exit, reset the 'BEING_CRACKED' to zero + keytable[bytes_to_recover[0]] &= ~BEING_CRACKED; + keytable[bytes_to_recover[1]] &= ~BEING_CRACKED; + keytable[bytes_to_recover[2]] &= ~BEING_CRACKED; + + return 1; + } + } + + /* + *A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes, + */ + uint32_t brute = startvalue; + /* + Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries, + (when brute reaches 0x100). And so on... + bytes_to_recover = 1 --> endmask = 0x0000100 + bytes_to_recover = 2 --> endmask = 0x0010000 + bytes_to_recover = 3 --> endmask = 0x1000000 + */ + + uint32_t endmask = 1 << 8*numbytes_to_recover; + + for(i =0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++) + prnlog("Bruteforcing byte %d", bytes_to_recover[i]); + + while(!found && !(brute & endmask)) + { + + //Update the keytable with the brute-values + for(i =0 ; i < numbytes_to_recover; i++) + { + keytable[bytes_to_recover[i]] &= 0xFF00; + keytable[bytes_to_recover[i]] |= (brute >> (i*8) & 0xFF); + } + + // Piece together the key + key_sel[0] = keytable[key_index[0]] & 0xFF;key_sel[1] = keytable[key_index[1]] & 0xFF; + key_sel[2] = keytable[key_index[2]] & 0xFF;key_sel[3] = keytable[key_index[3]] & 0xFF; + key_sel[4] = keytable[key_index[4]] & 0xFF;key_sel[5] = keytable[key_index[5]] & 0xFF; + key_sel[6] = keytable[key_index[6]] & 0xFF;key_sel[7] = keytable[key_index[7]] & 0xFF; + + //Permute from iclass format to standard format + permutekey_rev(key_sel,key_sel_p); + //Diversify + diversifyKey(item.csn, key_sel_p, div_key); + //Calc mac + doMAC(item.cc_nr,12, div_key,calculated_MAC); + + if(memcmp(calculated_MAC, item.mac, 4) == 0) + { + for(i =0 ; i < numbytes_to_recover; i++) + prnlog("=> %d: 0x%02x", bytes_to_recover[i],0xFF & keytable[bytes_to_recover[i]]); + found = true; + break; + } + brute++; + if((brute & 0xFFFF) == 0) + { + printf("%d",(brute >> 16) & 0xFF); + fflush(stdout); + } + } + if(! found) + { + prnlog("Failed to recover %d bytes using the following CSN",numbytes_to_recover); + printvar("CSN",item.csn,8); + errors++; + //Before we exit, reset the 'BEING_CRACKED' to zero + for(i =0 ; i < numbytes_to_recover; i++) + { + keytable[bytes_to_recover[i]] &= 0xFF; + keytable[bytes_to_recover[i]] |= CRACK_FAILED; + } + + }else + { + for(i =0 ; i < numbytes_to_recover; i++) + { + keytable[bytes_to_recover[i]] &= 0xFF; + keytable[bytes_to_recover[i]] |= CRACKED; + } + + } + return errors; +} + + +/** + * From dismantling iclass-paper: + * Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] . + * Then he can simply recover the master custom key K_cus by computing + * K_cus = ~DES(z[0] , y[0] ) . + * + * Furthermore, the adversary is able to verify that he has the correct K cus by + * checking whether z [0] = DES enc (K_cus , ~K_cus ). + * @param keytable an array (128 bytes) of hash2(kcus) + * @param master_key where to put the master key + * @return 0 for ok, 1 for failz + */ +int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ) +{ + des_context ctx_e = {DES_ENCRYPT,{0}}; + + uint8_t z_0[8] = {0}; + uint8_t y_0[8] = {0}; + uint8_t z_0_rev[8] = {0}; + uint8_t key64[8] = {0}; + uint8_t key64_negated[8] = {0}; + uint8_t result[8] = {0}; + + // y_0 and z_0 are the first 16 bytes of the keytable + memcpy(y_0,first16bytes,8); + memcpy(z_0,first16bytes+8,8); + + // Our DES-implementation uses the standard NIST + // format for keys, thus must translate from iclass + // format to NIST-format + permutekey_rev(z_0, z_0_rev); + + // ~K_cus = DESenc(z[0], y[0]) + des_setkey_enc( &ctx_e, z_0_rev ); + des_crypt_ecb(&ctx_e, y_0, key64_negated); + + int i; + for(i = 0; i < 8 ; i++) + { + key64[i] = ~key64_negated[i]; + } + + // Can we verify that the key is correct? + // Once again, key is on iclass-format + uint8_t key64_stdformat[8] = {0}; + permutekey_rev(key64, key64_stdformat); + + des_setkey_enc( &ctx_e, key64_stdformat ); + des_crypt_ecb(&ctx_e, key64_negated, result); + prnlog("\nHigh security custom key (Kcus):"); + printvar("Std format ", key64_stdformat,8); + printvar("Iclass format", key64,8); + + if(master_key != NULL) + memcpy(master_key, key64, 8); + + if(memcmp(z_0,result,4) != 0) + { + prnlog("Failed to verify calculated master key (k_cus)! Something is wrong."); + return 1; + }else{ + prnlog("Key verified ok!\n"); + } + return 0; +} +/** + * @brief Same as bruteforcefile, but uses a an array of dumpdata instead + * @param dump + * @param dumpsize + * @param keytable + * @return + */ +int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) +{ + uint8_t i; + int errors = 0; + size_t itemsize = sizeof(dumpdata); + clock_t t1 = clock(); + + dumpdata* attack = (dumpdata* ) malloc(itemsize); + + for(i = 0 ; i * itemsize < dumpsize ; i++ ) + { + memcpy(attack,dump+i*itemsize, itemsize); + errors += bruteforceItem(*attack, keytable); + } + free(attack); + clock_t t2 = clock(); + float diff = (((float)t2 - (float)t1) / CLOCKS_PER_SEC ); + prnlog("\nPerformed full crack in %f seconds",diff); + + // Pick out the first 16 bytes of the keytable. + // The keytable is now in 16-bit ints, where the upper 8 bits + // indicate crack-status. Those must be discarded for the + // master key calculation + uint8_t first16bytes[16] = {0}; + + for(i = 0 ; i < 16 ; i++) + { + first16bytes[i] = keytable[i] & 0xFF; + if(!(keytable[i] & CRACKED)) + { + prnlog("Error, we are missing byte %d, custom key calculation will fail...", i); + } + } + errors += calculateMasterKey(first16bytes, NULL); + return errors; +} +/** + * Perform a bruteforce against a file which has been saved by pm3 + * + * @brief bruteforceFile + * @param filename + * @return + */ +int bruteforceFile(const char *filename, uint16_t keytable[]) +{ + + FILE *f = fopen(filename, "rb"); + if(!f) { + prnlog("Failed to read from file '%s'", filename); + return 1; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + uint8_t *dump = malloc(fsize); + size_t bytes_read = fread(dump, fsize, 1, f); + + fclose(f); + if (bytes_read < fsize) + { + prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize ); + } + return bruteforceDump(dump,fsize,keytable); +} +/** + * + * @brief Same as above, if you don't care about the returned keytable (results only printed on screen) + * @param filename + * @return + */ +int bruteforceFileNoKeys(const char *filename) +{ + uint16_t keytable[128] = {0}; + return bruteforceFile(filename, keytable); +} + +// --------------------------------------------------------------------------------- +// ALL CODE BELOW THIS LINE IS PURELY TESTING +// --------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// TEST CODE BELOW +// ---------------------------------------------------------------------------- + +int _testBruteforce() +{ + int errors = 0; + if(true){ + // First test + prnlog("[+] Testing crack from dumpfile..."); + + /** + Expected values for the dumpfile: + High Security Key Table + + 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 + 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 + 20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2 + 30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C + 40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6 + 50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42 + 60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95 + 70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB + + **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 **** + **/ + uint16_t keytable[128] = {0}; + //save some time... + startvalue = 0x7B0000; + errors |= bruteforceFile("iclass_dump.bin",keytable); + } + return errors; +} + +int _test_iclass_key_permutation() +{ + uint8_t testcase[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf}; + uint8_t testcase_output[8] = {0}; + uint8_t testcase_output_correct[8] = {0x8a,0x0d,0xb9,0x88,0xbb,0xa7,0x90,0xea}; + uint8_t testcase_output_rev[8] = {0}; + permutekey(testcase, testcase_output); + permutekey_rev(testcase_output, testcase_output_rev); + + + if(memcmp(testcase_output, testcase_output_correct,8) != 0) + { + prnlog("Error with iclass key permute!"); + printarr("testcase_output", testcase_output, 8); + printarr("testcase_output_correct", testcase_output_correct, 8); + return 1; + + } + if(memcmp(testcase, testcase_output_rev, 8) != 0) + { + prnlog("Error with reverse iclass key permute"); + printarr("testcase", testcase, 8); + printarr("testcase_output_rev", testcase_output_rev, 8); + return 1; + } + + prnlog("[+] Iclass key permutation OK!"); + return 0; +} + +int testElite() +{ + prnlog("[+] Testing iClass Elite functinality..."); + prnlog("[+] Testing hash2"); + uint8_t k_cus[8] = {0x5B,0x7C,0x62,0xC4,0x91,0xC1,0x1B,0x39}; + + /** + *Expected: + * High Security Key Table + +00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 +10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 +20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2 +30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C +40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6 +50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42 +60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95 +70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB + + + +**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 **** + */ + uint8_t keytable[128] = {0}; + hash2(k_cus, keytable); + printarr_human_readable("Hash2", keytable, 128); + if(keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95) + { + prnlog("[+] Hash2 looks fine..."); + } + + prnlog("[+] Testing key diversification ..."); + + int errors = 0 ; + errors +=_test_iclass_key_permutation(); + errors += _testBruteforce(); + return errors; + +} + diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h new file mode 100644 index 00000000..21004e59 --- /dev/null +++ b/client/loclass/elite_crack.h @@ -0,0 +1,108 @@ +#ifndef ELITE_CRACK_H +#define ELITE_CRACK_H +void permutekey(uint8_t key[8], uint8_t dest[8]); +/** + * Permutes a key from iclass specific format to NIST format + * @brief permutekey_rev + * @param key + * @param dest + */ +void permutekey_rev(uint8_t key[8], uint8_t dest[8]); +//Crack status, see below +#define CRACKED 0x0100 +#define BEING_CRACKED 0x0200 +#define CRACK_FAILED 0x0400 + +/** + * Perform a bruteforce against a file which has been saved by pm3 + * + * @brief bruteforceFile + * @param filename + * @param keytable an arrah (128 x 16 bit ints). This is where the keydata is stored. + * OBS! the upper part of the 16 bits store crack-status, + * @return + */ +int bruteforceFile(const char *filename, uint16_t keytable[]); +/** + * + * @brief Same as above, if you don't care about the returned keytable (results only printed on screen) + * @param filename + * @return + */ +int bruteforceFileNoKeys(const char *filename); +/** + * @brief Same as bruteforcefile, but uses a an array of dumpdata instead + * @param dump + * @param dumpsize + * @param keytable + * @return + */ +int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]); + +/** + This is how we expect each 'entry' in a dumpfile to look +**/ +typedef struct { + uint8_t csn[8]; + uint8_t cc_nr[12]; + uint8_t mac[4]; + +}dumpdata; + +/** + * @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac. + *This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced + *on the fly. If it finds that more than three bytes need to be bruteforced, it aborts. + *It updates the keytable with the findings, also using the upper half of the 16-bit ints + *to signal if the particular byte has been cracked or not. + * + * @param dump The dumpdata from iclass reader attack. + * @param keytable where to write found values. + * @return + */ +int bruteforceItem(dumpdata item, uint16_t keytable[]); +/** + * Hash1 takes CSN as input, and determines what bytes in the keytable will be used + * when constructing the K_sel. + * @param csn the CSN used + * @param k output + */ +void hash1(uint8_t csn[] , uint8_t k[]); +void hash2(uint8_t *key64, uint8_t *outp_keytable); +/** + * From dismantling iclass-paper: + * Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] . + * Then he can simply recover the master custom key K_cus by computing + * K_cus = ~DES(z[0] , y[0] ) . + * + * Furthermore, the adversary is able to verify that he has the correct K cus by + * checking whether z [0] = DES enc (K_cus , ~K_cus ). + * @param keytable an array (128 bytes) of hash2(kcus) + * @param master_key where to put the master key + * @return 0 for ok, 1 for failz + */ +int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ); + +/** + * @brief Test function + * @return + */ +int testElite(); + +/** + Here are some pretty optimal values that can be used to recover necessary data in only + eight auth attempts. +// CSN HASH1 Bytes recovered // +{ {0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0} , {0x01,0x01,0x00,0x00,0x45,0x01,0x45,0x45 } ,{0,1 }}, +{ {0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0} , {0x02,0x0c,0x01,0x00,0x45,0x01,0x45,0x45} , {2,12}}, +{ {0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0} , {0x07,0x45,0x0b,0x00,0x45,0x01,0x45,0x45} , {7,11}}, +{ {0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0} , {0x03,0x0f,0x00,0x00,0x45,0x01,0x45,0x45} , {3,15}}, +{ {0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0} , {0x04,0x00,0x08,0x00,0x45,0x01,0x45,0x45} , {4,8}}, +{ {0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0} , {0x0e,0x06,0x08,0x00,0x45,0x01,0x45,0x45} , {6,14}}, +{ {0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0} , {0x0b,0x09,0x0f,0x00,0x45,0x01,0x05,0x45} , {9,5}}, +{ {0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0} , {0x0d,0x0f,0x0a,0x00,0x45,0x01,0x05,0x45} , {10,13}}, + +**/ + + +#endif diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c new file mode 100644 index 00000000..08b81ec0 --- /dev/null +++ b/client/loclass/fileutils.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include "fileutils.h" +#include "ui.h" +/** + * @brief checks if a file exists + * @param filename + * @return + */ +int fileExists(const char *filename) { + struct _stat st; + int result = stat(filename, &st); + return result == 0; +} + +int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen) +{ + int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5); + char * fileName = malloc(size); + + memset(fileName,0,size); + int num = 1; + sprintf(fileName,"%s.%s", preferredName, suffix); + while(fileExists(fileName)) + { + sprintf(fileName,"%s-%d.%s", preferredName, num, suffix); + num++; + } + /* We should have a valid filename now, e.g. dumpdata-3.bin */ + + /*Opening file for writing in binary mode*/ + FILE *fileHandle=fopen(fileName,"wb"); + if(!fileHandle) { + prnlog("Failed to write to file '%s'", fileName); + return 1; + } + fwrite(data, 1, datalen, fileHandle); + fclose(fileHandle); + prnlog("Saved data to '%s'", fileName); + free(fileName); + + return 0; +} + +/** + * Utility function to print to console. This is used consistently within the library instead + * of printf, but it actually only calls printf (and adds a linebreak). + * The reason to have this method is to + * make it simple to plug this library into proxmark, which has this function already to + * write also to a logfile. When doing so, just delete this function. + * @param fmt + */ +void prnlog(char *fmt, ...) +{ + + va_list args; + va_start(args,fmt); + PrintAndLog(fmt, args); + //vprintf(fmt,args); + va_end(args); + //printf("\n"); +} diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h new file mode 100644 index 00000000..a0f5a799 --- /dev/null +++ b/client/loclass/fileutils.h @@ -0,0 +1,24 @@ +#ifndef FILEUTILS_H +#define FILEUTILS_H +/** + * @brief Utility function to save data to a file. This method takes a preferred name, but if that + * file already exists, it tries with another name until it finds something suitable. + * E.g. dumpdata-15.txt + * @param preferredName + * @param suffix the file suffix. Leave out the ".". + * @param data The binary data to write to the file + * @param datalen the length of the data + * @return 0 for ok, 1 for failz + */ +int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen); + + +/** + * Utility function to print to console. This is used consistently within the library instead + * of printf, but it actually only calls printf. The reason to have this method is to + *make it simple to plug this library into proxmark, which has this function already to + * write also to a logfile. When doing so, just point this function to use PrintAndLog + * @param fmt + */ +void prnlog(char *fmt, ...); +#endif // FILEUTILS_H diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c new file mode 100644 index 00000000..cd2b72ee --- /dev/null +++ b/client/loclass/ikeys.c @@ -0,0 +1,878 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * This is a reference implementation of iclass key diversification. I'm sure it can be + * optimized heavily. It is written for ease of understanding and correctness, please take it + * and tweak it and make a super fast version instead, using this for testing and verification. + + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with IClassCipher. If not, see . + ****************************************************************************/ +/** + + +From "Dismantling iclass": + This section describes in detail the built-in key diversification algorithm of iClass. + Besides the obvious purpose of deriving a card key from a master key, this + algorithm intends to circumvent weaknesses in the cipher by preventing the + usage of certain ‘weak’ keys. In order to compute a diversified key, the iClass + reader first encrypts the card identity id with the master key K, using single + DES. The resulting ciphertext is then input to a function called hash0 which + outputs the diversified key k. + + k = hash0(DES enc (id, K)) + + Here the DES encryption of id with master key K outputs a cryptogram c + of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] ∈ F 82 × F 82 × (F 62 ) 8 + which is used as input to the hash0 function. This function introduces some + obfuscation by performing a number of permutations, complement and modulo + operations, see Figure 2.5. Besides that, it checks for and removes patterns like + similar key bytes, which could produce a strong bias in the cipher. Finally, the + output of hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 . + + +**/ + + +#include +#include +#include +#include +#include +#include "fileutils.h" +#include "cipherutils.h" +#include "des.h" + +uint8_t pi[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78}; + +static des_context ctx_enc = {DES_ENCRYPT,{0}}; +static des_context ctx_dec = {DES_DECRYPT,{0}}; + +static int debug_print = 0; + +/** + * @brief The key diversification algorithm uses 6-bit bytes. + * This implementation uses 64 bit uint to pack seven of them into one + * variable. When they are there, they are placed as follows: + * XXXX XXXX N0 .... N7, occupying the lsat 48 bits. + * + * This function picks out one from such a collection + * @param all + * @param n bitnumber + * @return + */ +uint8_t getSixBitByte(uint64_t c, int n) +{ + return (c >> (42-6*n)) & 0x3F; +} + +/** + * @brief Puts back a six-bit 'byte' into a uint64_t. + * @param c buffer + * @param z the value to place there + * @param n bitnumber. + */ +void pushbackSixBitByte(uint64_t *c, uint8_t z, int n) +{ + //0x XXXX YYYY ZZZZ ZZZZ ZZZZ + // ^z0 ^z7 + //z0: 1111 1100 0000 0000 + + uint64_t masked = z & 0x3F; + uint64_t eraser = 0x3F; + masked <<= 42-6*n; + eraser <<= 42-6*n; + + //masked <<= 6*n; + //eraser <<= 6*n; + + eraser = ~eraser; + (*c) &= eraser; + (*c) |= masked; + +} +/** + * @brief Swaps the z-values. + * If the input value has format XYZ0Z1...Z7, the output will have the format + * XYZ7Z6...Z0 instead + * @param c + * @return + */ +uint64_t swapZvalues(uint64_t c) +{ + uint64_t newz = 0; + pushbackSixBitByte(&newz, getSixBitByte(c,0),7); + pushbackSixBitByte(&newz, getSixBitByte(c,1),6); + pushbackSixBitByte(&newz, getSixBitByte(c,2),5); + pushbackSixBitByte(&newz, getSixBitByte(c,3),4); + pushbackSixBitByte(&newz, getSixBitByte(c,4),3); + pushbackSixBitByte(&newz, getSixBitByte(c,5),2); + pushbackSixBitByte(&newz, getSixBitByte(c,6),1); + pushbackSixBitByte(&newz, getSixBitByte(c,7),0); + newz |= (c & 0xFFFF000000000000); + return newz; +} + +/** +* @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3 +*/ +uint64_t ck(int i, int j, uint64_t z) +{ + + if(i == 1 && j == -1) + { + // ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] + return z; + + }else if( j == -1) + { + // ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] ) + return ck(i-1,i-2, z); + } + + if(getSixBitByte(z,i) == getSixBitByte(z,j)) + { + + //ck(i, j − 1, z [0] . . . z [i] ↠j . . . z [3] ) + uint64_t newz = 0; + int c; + for(c = 0; c < 4 ;c++) + { + uint8_t val = getSixBitByte(z,c); + if(c == i) + { + pushbackSixBitByte(&newz, j, c); + }else + { + pushbackSixBitByte(&newz, val, c); + } + } + return ck(i,j-1,newz); + }else + { + return ck(i,j-1,z); + } +} +/** + + Definition 8. + Let the function check : (F 62 ) 8 → (F 62 ) 8 be defined as + check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] ) + + where ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as + + ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] + ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] ) + ck(i, j, z [0] . . . z [3] ) = + ck(i, j − 1, z [0] . . . z [i] ↠j . . . z [3] ), if z [i] = z [j] ; + ck(i, j − 1, z [0] . . . z [3] ), otherwise + + otherwise. +**/ + +uint64_t check(uint64_t z) +{ + //These 64 bits are divided as c = x, y, z [0] , . . . , z [7] + + // ck(3, 2, z [0] . . . z [3] ) + uint64_t ck1 = ck(3,2, z ); + + // ck(3, 2, z [4] . . . z [7] ) + uint64_t ck2 = ck(3,2, z << 24); + + //The ck function will place the values + // in the middle of z. + ck1 &= 0x00000000FFFFFF000000; + ck2 &= 0x00000000FFFFFF000000; + + return ck1 | ck2 >> 24; + +} + +void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out) +{ + if(bitsLeft(p_in) == 0) + { + return; + } + bool pn = tailBit(p_in); + if( pn ) // pn = 1 + { + uint8_t zl = getSixBitByte(z,l); + + push6bits(out, zl+1); + permute(p_in, z, l+1,r, out); + }else // otherwise + { + uint8_t zr = getSixBitByte(z,r); + + push6bits(out, zr); + permute(p_in,z,l,r+1,out); + } +} +void printbegin() +{ + if(debug_print <2) + return ; + + prnlog(" | x| y|z0|z1|z2|z3|z4|z5|z6|z7|"); +} + +void printState(char* desc, uint64_t c) +{ + if(debug_print < 2) + return ; + + printf("%s : ", desc); + uint8_t x = (c & 0xFF00000000000000 ) >> 56; + uint8_t y = (c & 0x00FF000000000000 ) >> 48; + printf(" %02x %02x", x,y); + int i ; + for(i =0 ; i < 8 ; i++) + { + printf(" %02x", getSixBitByte(c,i)); + } + printf("\n"); +} + +/** + * @brief + *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as + * hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where + * z'[i] = (z[i] mod (63-i)) + i i = 0...3 + * z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3 + * ẑ = check(z'); + * @param c + * @param k this is where the diversified key is put (should be 8 bytes) + * @return + */ +void hash0(uint64_t c, uint8_t k[8]) +{ + c = swapZvalues(c); + + printbegin(); + printState("origin",c); + //These 64 bits are divided as c = x, y, z [0] , . . . , z [7] + // x = 8 bits + // y = 8 bits + // z0-z7 6 bits each : 48 bits + uint8_t x = (c & 0xFF00000000000000 ) >> 56; + uint8_t y = (c & 0x00FF000000000000 ) >> 48; + int n; + uint8_t zn, zn4, _zn, _zn4; + uint64_t zP = 0; + + for(n = 0; n < 4 ; n++) + { + zn = getSixBitByte(c,n); + + zn4 = getSixBitByte(c,n+4); + + _zn = (zn % (63-n)) + n; + _zn4 = (zn4 % (64-n)) + n; + + + pushbackSixBitByte(&zP, _zn,n); + pushbackSixBitByte(&zP, _zn4,n+4); + + } + printState("0|0|z'",zP); + + uint64_t zCaret = check(zP); + printState("0|0|z^",zP); + + + uint8_t p = pi[x % 35]; + + if(x & 1) //Check if x7 is 1 + { + p = ~p; + } + + if(debug_print >= 2) prnlog("p:%02x", p); + + BitstreamIn p_in = { &p, 8,0 }; + uint8_t outbuffer[] = {0,0,0,0,0,0,0,0}; + BitstreamOut out = {outbuffer,0,0}; + permute(&p_in,zCaret,0,4,&out);//returns 48 bits? or 6 8-bytes + + //Out is now a buffer containing six-bit bytes, should be 48 bits + // if all went well + //Shift z-values down onto the lower segment + + uint64_t zTilde = x_bytes_to_num(outbuffer,8); + + zTilde >>= 16; + + printState("0|0|z~", zTilde); + + int i; + int zerocounter =0 ; + for(i =0 ; i < 8 ; i++) + { + + // the key on index i is first a bit from y + // then six bits from z, + // then a bit from p + + // Init with zeroes + k[i] = 0; + // First, place yi leftmost in k + //k[i] |= (y << i) & 0x80 ; + + // First, place y(7-i) leftmost in k + k[i] |= (y << (7-i)) & 0x80 ; + + + + uint8_t zTilde_i = getSixBitByte(zTilde, i); + // zTildeI is now on the form 00XXXXXX + // with one leftshift, it'll be + // 0XXXXXX0 + // So after leftshift, we can OR it into k + // However, when doing complement, we need to + // again MASK 0XXXXXX0 (0x7E) + zTilde_i <<= 1; + + //Finally, add bit from p or p-mod + //Shift bit i into rightmost location (mask only after complement) + uint8_t p_i = p >> i & 0x1; + + if( k[i] )// yi = 1 + { + //printf("k[%d] +1\n", i); + k[i] |= ~zTilde_i & 0x7E; + k[i] |= p_i & 1; + k[i] += 1; + + }else // otherwise + { + k[i] |= zTilde_i & 0x7E; + k[i] |= (~p_i) & 1; + } + if((k[i] & 1 )== 0) + { + zerocounter ++; + } + } +} +/** + * @brief Performs Elite-class key diversification + * @param csn + * @param key + * @param div_key + */ +void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]) +{ + + // Prepare the DES key + des_setkey_enc( &ctx_enc, key); + + uint8_t crypted_csn[8] = {0}; + + // Calculate DES(CSN, KEY) + des_crypt_ecb(&ctx_enc,csn, crypted_csn); + + //Calculate HASH0(DES)) + uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8); + //uint64_t crypted_csn_swapped = swapZvalues(crypt_csn); + + hash0(crypt_csn,div_key); +} + + + + + +void testPermute() +{ + + uint64_t x = 0; + pushbackSixBitByte(&x,0x00,0); + pushbackSixBitByte(&x,0x01,1); + pushbackSixBitByte(&x,0x02,2); + pushbackSixBitByte(&x,0x03,3); + pushbackSixBitByte(&x,0x04,4); + pushbackSixBitByte(&x,0x05,5); + pushbackSixBitByte(&x,0x06,6); + pushbackSixBitByte(&x,0x07,7); + + uint8_t mres[8] = { getSixBitByte(x, 0), + getSixBitByte(x, 1), + getSixBitByte(x, 2), + getSixBitByte(x, 3), + getSixBitByte(x, 4), + getSixBitByte(x, 5), + getSixBitByte(x, 6), + getSixBitByte(x, 7)}; + printarr("input_perm", mres,8); + + uint8_t p = ~pi[0]; + BitstreamIn p_in = { &p, 8,0 }; + uint8_t outbuffer[] = {0,0,0,0,0,0,0,0}; + BitstreamOut out = {outbuffer,0,0}; + + permute(&p_in, x,0,4, &out); + + uint64_t permuted = x_bytes_to_num(outbuffer,8); + //printf("zTilde 0x%"PRIX64"\n", zTilde); + permuted >>= 16; + + uint8_t res[8] = { getSixBitByte(permuted, 0), + getSixBitByte(permuted, 1), + getSixBitByte(permuted, 2), + getSixBitByte(permuted, 3), + getSixBitByte(permuted, 4), + getSixBitByte(permuted, 5), + getSixBitByte(permuted, 6), + getSixBitByte(permuted, 7)}; + printarr("permuted", res, 8); +} + +//These testcases are +//{ UID , TEMP_KEY, DIV_KEY} using the specific key +typedef struct +{ + uint8_t uid[8]; + uint8_t t_key[8]; + uint8_t div_key[8]; +} Testcase; + + +int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec) +{ + uint8_t des_encrypted_csn[8] = {0}; + uint8_t decrypted[8] = {0}; + uint8_t div_key[8] = {0}; + int retval = des_crypt_ecb(&ctx_enc,testcase.uid,des_encrypted_csn); + retval |= des_crypt_ecb(&ctx_dec,des_encrypted_csn,decrypted); + + if(memcmp(testcase.uid,decrypted,8) != 0) + { + //Decryption fail + prnlog("Encryption <-> Decryption FAIL"); + printarr("Input", testcase.uid, 8); + printarr("Decrypted", decrypted, 8); + retval = 1; + } + + if(memcmp(des_encrypted_csn,testcase.t_key,8) != 0) + { + //Encryption fail + prnlog("Encryption != Expected result"); + printarr("Output", des_encrypted_csn, 8); + printarr("Expected", testcase.t_key, 8); + retval = 1; + } + uint64_t crypted_csn = x_bytes_to_num(des_encrypted_csn,8); + hash0(crypted_csn, div_key); + + if(memcmp(div_key, testcase.div_key ,8) != 0) + { + //Key diversification fail + prnlog("Div key != expected result"); + printarr(" csn ", testcase.uid,8); + printarr("{csn} ", des_encrypted_csn,8); + printarr("hash0 ", div_key, 8); + printarr("Expected", testcase.div_key, 8); + retval = 1; + + } + return retval; +} +bool des_getParityBitFromKey(uint8_t key) +{//The top 7 bits is used + bool parity = ((key & 0x80) >> 7) + ^ ((key & 0x40) >> 6) ^ ((key & 0x20) >> 5) + ^ ((key & 0x10) >> 4) ^ ((key & 0x08) >> 3) + ^ ((key & 0x04) >> 2) ^ ((key & 0x02) >> 1); + return !parity; +} + + +void des_checkParity(uint8_t* key) +{ + int i; + int fails =0; + for(i =0 ; i < 8 ; i++) + { + bool parity = des_getParityBitFromKey(key[i]); + if(parity != (key[i] & 0x1)) + { + fails++; + prnlog("[+] parity1 fail, byte %d [%02x] was %d, should be %d",i,key[i],(key[i] & 0x1),parity); + } + } + if(fails) + { + prnlog("[+] parity fails: %d", fails); + }else + { + prnlog("[+] Key syntax is with parity bits inside each byte"); + } +} + +Testcase testcases[] ={ + + {{0x8B,0xAC,0x60,0x1F,0x53,0xB8,0xED,0x11},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0xAE,0x51,0xE5,0x62,0xE7,0x9A,0x99,0x39},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01},{0x04,0x02,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x9B,0x21,0xE4,0x31,0x6A,0x00,0x29,0x62},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02},{0x06,0x04,0x02,0x08,0x01,0x03,0x05,0x07}}, + {{0x65,0x24,0x0C,0x41,0x4F,0xC2,0x21,0x93},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04},{0x0A,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x7F,0xEB,0xAE,0x93,0xE5,0x30,0x08,0xBD},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08},{0x12,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x49,0x7B,0x70,0x74,0x9B,0x35,0x1B,0x83},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10},{0x22,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x02,0x3C,0x15,0x6B,0xED,0xA5,0x64,0x6C},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20},{0x42,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0xE8,0x37,0xE0,0xE2,0xC6,0x45,0x24,0xF3},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40},{0x02,0x06,0x04,0x08,0x01,0x03,0x05,0x07}}, + {{0xAB,0xBD,0x30,0x05,0x29,0xC8,0xF7,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},{0x02,0x08,0x06,0x04,0x01,0x03,0x05,0x07}}, + {{0x17,0xE8,0x97,0xF0,0x99,0xB6,0x79,0x31},{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00},{0x02,0x0C,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x49,0xA4,0xF0,0x8F,0x5F,0x96,0x83,0x16},{0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00},{0x02,0x14,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x60,0xF5,0x7E,0x54,0xAA,0x41,0x83,0xD4},{0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00},{0x02,0x24,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x1D,0xF6,0x3B,0x6B,0x85,0x55,0xF0,0x4B},{0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00},{0x02,0x44,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x1F,0xDC,0x95,0x1A,0xEA,0x6B,0x4B,0xB4},{0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00},{0x02,0x04,0x08,0x06,0x01,0x03,0x05,0x07}}, + {{0xEC,0x93,0x72,0xF0,0x3B,0xA9,0xF5,0x0B},{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00},{0x02,0x04,0x0A,0x08,0x01,0x03,0x05,0x07}}, + {{0xDE,0x57,0x5C,0xBE,0x2D,0x55,0x03,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00},{0x02,0x04,0x0E,0x08,0x01,0x03,0x05,0x07}}, + {{0x1E,0xD2,0xB5,0xCE,0x90,0xC9,0xC1,0xCC},{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00},{0x02,0x04,0x16,0x08,0x01,0x03,0x05,0x07}}, + {{0xD8,0x65,0x96,0x4E,0xE7,0x74,0x99,0xB8},{0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00},{0x02,0x04,0x26,0x08,0x01,0x03,0x05,0x07}}, + {{0xE3,0x7A,0x29,0x83,0x31,0xD5,0x3A,0x54},{0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00},{0x02,0x04,0x46,0x08,0x01,0x03,0x05,0x07}}, + {{0x3A,0xB5,0x1A,0x34,0x34,0x25,0x12,0xF0},{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00},{0x02,0x04,0x06,0x0A,0x01,0x03,0x05,0x07}}, + {{0xF2,0x88,0xEE,0x6F,0x70,0x6F,0xC2,0x52},{0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00},{0x02,0x04,0x06,0x0C,0x01,0x03,0x05,0x07}}, + {{0x76,0xEF,0xEB,0x80,0x52,0x43,0x83,0x57},{0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00},{0x02,0x04,0x06,0x10,0x01,0x03,0x05,0x07}}, + {{0x1C,0x09,0x8E,0x3B,0x23,0x23,0x52,0xB5},{0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00},{0x02,0x04,0x06,0x18,0x01,0x03,0x05,0x07}}, + {{0xA9,0x13,0xA2,0xBE,0xCF,0x1A,0xC4,0x9A},{0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00},{0x02,0x04,0x06,0x28,0x01,0x03,0x05,0x07}}, + {{0x25,0x56,0x4B,0xB0,0xC8,0x2A,0xD4,0x27},{0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00},{0x02,0x04,0x06,0x48,0x01,0x03,0x05,0x07}}, + {{0xB1,0x04,0x57,0x3F,0xA7,0x16,0x62,0xD4},{0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x03,0x01,0x05,0x07}}, + {{0x45,0x46,0xED,0xCC,0xE7,0xD3,0x8E,0xA3},{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x05,0x03,0x01,0x07}}, + {{0x22,0x6D,0xB5,0x35,0xE0,0x5A,0xE0,0x90},{0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x09,0x03,0x05,0x07}}, + {{0xB8,0xF5,0xE5,0x44,0xC5,0x98,0x4A,0xBD},{0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x11,0x03,0x05,0x07}}, + {{0xAC,0x78,0x0A,0x23,0x9E,0xF6,0xBC,0xA0},{0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x21,0x03,0x05,0x07}}, + {{0x46,0x6B,0x2D,0x70,0x41,0x17,0xBF,0x3D},{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x41,0x03,0x05,0x07}}, + {{0x64,0x44,0x24,0x71,0xA2,0x56,0xDF,0xB5},{0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x05,0x03,0x07}}, + {{0xC4,0x00,0x52,0x24,0xA2,0xD6,0x16,0x7A},{0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x07,0x05,0x03}}, + {{0xD8,0x4A,0x80,0x1E,0x95,0x5B,0x70,0xC4},{0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x0B,0x05,0x07}}, + {{0x08,0x56,0x6E,0xB5,0x64,0xD6,0x47,0x4E},{0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x13,0x05,0x07}}, + {{0x41,0x6F,0xBA,0xA4,0xEB,0xAE,0xA0,0x55},{0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x23,0x05,0x07}}, + {{0x62,0x9D,0xDE,0x72,0x84,0x4A,0x53,0xD5},{0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x43,0x05,0x07}}, + {{0x39,0xD3,0x2B,0x66,0xB8,0x08,0x40,0x2E},{0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x07,0x05}}, + {{0xAF,0x67,0xA9,0x18,0x57,0x21,0xAF,0x8D},{0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x09,0x07}}, + {{0x34,0xBC,0x9D,0xBC,0xC4,0xC2,0x3B,0xC8},{0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x0D,0x07}}, + {{0xB6,0x50,0xF9,0x81,0xF6,0xBF,0x90,0x3C},{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x15,0x07}}, + {{0x71,0x41,0x93,0xA1,0x59,0x81,0xA5,0x52},{0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x25,0x07}}, + {{0x6B,0x00,0xBD,0x74,0x1C,0x3C,0xE0,0x1A},{0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x45,0x07}}, + {{0x76,0xFD,0x0B,0xD0,0x41,0xD2,0x82,0x5D},{0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x09}}, + {{0xC6,0x3A,0x1C,0x25,0x63,0x5A,0x2F,0x0E},{0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0B}}, + {{0xD9,0x0E,0xD7,0x30,0xE2,0xAD,0xA9,0x87},{0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0F}}, + {{0x6B,0x81,0xC6,0xD1,0x05,0x09,0x87,0x1E},{0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x17}}, + {{0xB4,0xA7,0x1E,0x02,0x54,0x37,0x43,0x35},{0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x27}}, + {{0x45,0x14,0x7C,0x7F,0xE0,0xDE,0x09,0x65},{0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x47}}, + {{0x78,0xB0,0xF5,0x20,0x8B,0x7D,0xF3,0xDD},{0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00},{0xFE,0x04,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x88,0xB3,0x3C,0xE1,0xF7,0x87,0x42,0xA1},{0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0xFC,0x06,0x08,0x01,0x03,0x05,0x07}}, + {{0x11,0x2F,0xB2,0xF7,0xE2,0xB2,0x4F,0x6E},{0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0xFA,0x08,0x01,0x03,0x05,0x07}}, + {{0x25,0x56,0x4E,0xC6,0xEB,0x2D,0x74,0x5B},{0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0xF8,0x01,0x03,0x05,0x07}}, + {{0x7E,0x98,0x37,0xF9,0x80,0x8F,0x09,0x82},{0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0xFF,0x03,0x05,0x07}}, + {{0xF9,0xB5,0x62,0x3B,0xD8,0x7B,0x3C,0x3F},{0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0xFD,0x05,0x07}}, + {{0x29,0xC5,0x2B,0xFA,0xD1,0xFC,0x5C,0xC7},{0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0xFB,0x07}}, + {{0xC1,0xA3,0x09,0x71,0xBD,0x8E,0xAF,0x2F},{0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0xF9}}, + {{0xB6,0xDD,0xD1,0xAD,0xAA,0x15,0x6F,0x29},{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x03,0x05,0x02,0x07,0x04,0x06,0x08}}, + {{0x65,0x34,0x03,0x19,0x17,0xB3,0xA3,0x96},{0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x08,0x03,0x05,0x07}}, + {{0xF9,0x38,0x43,0x56,0x52,0xE5,0xB1,0xA9},{0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x08,0x03,0x05,0x07}}, + + {{0xA4,0xA0,0xAF,0xDA,0x48,0xB0,0xA1,0x10},{0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x03,0x08,0x05,0x07}}, + {{0x55,0x15,0x8A,0x0D,0x48,0x29,0x01,0xD8},{0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x03,0x05,0x08,0x07}}, + {{0xC4,0x81,0x96,0x7D,0xA3,0xB7,0x73,0x50},{0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x05,0x04,0x06,0x08,0x07}}, + {{0x36,0x73,0xDF,0xC1,0x1B,0x98,0xA8,0x1D},{0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x07}}, + {{0xCE,0xE0,0xB3,0x1B,0x41,0xEB,0x15,0x12},{0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x06,0x05,0x08,0x07}}, + {{0},{0},{0}} +}; + + +int testKeyDiversificationWithMasterkeyTestcases() +{ + + int error = 0; + int i; + + uint8_t empty[8]={0}; + prnlog("[+} Testing encryption/decryption"); + + for (i = 0; memcmp(testcases+i,empty,8) ; i++) { + error += testDES(testcases[i],ctx_enc, ctx_dec); + } + if(error) + { + prnlog("[+] %d errors occurred (%d testcases)", error, i); + }else + { + prnlog("[+] Hashing seems to work (%d testcases)", i); + } + return error; +} + + +void print64bits(char*name, uint64_t val) +{ + printf("%s%08x%08x\n",name,(uint32_t) (val >> 32) ,(uint32_t) (val & 0xFFFFFFFF)); +} + +uint64_t testCryptedCSN(uint64_t crypted_csn, uint64_t expected) +{ + int retval = 0; + uint8_t result[8] = {0}; + if(debug_print) prnlog("debug_print %d", debug_print); + if(debug_print) print64bits(" {csn} ", crypted_csn ); + + uint64_t crypted_csn_swapped = swapZvalues(crypted_csn); + + if(debug_print) print64bits(" {csn-revz} ", crypted_csn_swapped); + + hash0(crypted_csn, result); + uint64_t resultbyte = x_bytes_to_num(result,8 ); + if(debug_print) print64bits(" hash0 " , resultbyte ); + + if(resultbyte != expected ) + { + + if(debug_print) { + prnlog("\n[+] FAIL!"); + print64bits(" expected " , expected ); + } + retval = 1; + + }else + { + if(debug_print) prnlog(" [OK]"); + } + return retval; +} + +int testDES2(uint64_t csn, uint64_t expected) +{ + uint8_t result[8] = {0}; + uint8_t input[8] = {0}; + + print64bits(" csn ", csn); + x_num_to_bytes(csn, 8,input); + + des_crypt_ecb(&ctx_enc,input, result); + + uint64_t crypt_csn = x_bytes_to_num(result, 8); + print64bits(" {csn} ", crypt_csn ); + print64bits(" expected ", expected ); + + if( expected == crypt_csn ) + { + prnlog("[+] OK"); + return 0; + }else + { + return 1; + } +} + +/** + * These testcases come from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977 + * @brief doTestsWithKnownInputs + * @return + */ +int doTestsWithKnownInputs() +{ + + // KSel from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977 + int errors = 0; + prnlog("[+] Testing DES encryption"); +// uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf}; + prnlog("[+] Testing foo"); + uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf}; + + des_setkey_enc( &ctx_enc, key); + testDES2(0xbbbbaaaabbbbeeee,0xd6ad3ca619659e6b); + + prnlog("[+] Testing hashing algorithm"); + + errors += testCryptedCSN(0x0102030405060708,0x0bdd6512073c460a); + errors += testCryptedCSN(0x1020304050607080,0x0208211405f3381f); + errors += testCryptedCSN(0x1122334455667788,0x2bee256d40ac1f3a); + errors += testCryptedCSN(0xabcdabcdabcdabcd,0xa91c9ec66f7da592); + errors += testCryptedCSN(0xbcdabcdabcdabcda,0x79ca5796a474e19b); + errors += testCryptedCSN(0xcdabcdabcdabcdab,0xa8901b9f7ec76da4); + errors += testCryptedCSN(0xdabcdabcdabcdabc,0x357aa8e0979a5b8d); + errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea); + errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3); + + if(errors) + { + prnlog("[+] %d errors occurred (9 testcases)", errors); + }else + { + prnlog("[+] Hashing seems to work (9 testcases)" ); + } + return errors; +} + +int readKeyFile(uint8_t key[8]) +{ + + FILE *f; + + f = fopen("iclass_key.bin", "rb"); + if (f) + { + if(fread(key, sizeof(key), 1, f) == 1) return 0; + } + return 1; + +} + + +int doKeyTests(uint8_t debuglevel) +{ + debug_print = debuglevel; + + prnlog("[+] Checking if the master key is present (iclass_key.bin)..."); + uint8_t key[8] = {0}; + if(readKeyFile(key)) + { + prnlog("[+] Master key not present, will not be able to do all testcases"); + }else + { + + //Test if it's the right key... + uint8_t i; + uint8_t j = 0; + for(i =0 ; i < sizeof(key) ; i++) + j += key[i]; + + if(j != 185) + { + prnlog("[+] A key was loaded, but it does not seem to be the correct one. Aborting these tests"); + }else + { + prnlog("[+] Key present"); + + prnlog("[+] Checking key parity..."); + des_checkParity(key); + des_setkey_enc( &ctx_enc, key); + des_setkey_dec( &ctx_dec, key); + // Test hashing functions + prnlog("[+] The following tests require the correct 8-byte master key"); + testKeyDiversificationWithMasterkeyTestcases(); + } + } + prnlog("[+] Testing key diversification with non-sensitive keys..."); + doTestsWithKnownInputs(); + return 0; +} + +/** + +void checkParity2(uint8_t* key) +{ + + uint8_t stored_parity = key[7]; + printf("Parity byte: 0x%02x\n", stored_parity); + int i; + int byte; + int fails =0; + BitstreamIn bits = {key, 56, 0}; + + bool parity = 0; + + for(i =0 ; i < 56; i++) + { + + if ( i > 0 && i % 7 == 0) + { + parity = !parity; + bool pbit = stored_parity & (0x80 >> (byte)); + if(parity != pbit) + { + printf("parity2 fail byte %d, should be %d, was %d\n", (i / 7), parity, pbit); + fails++; + } + parity =0 ; + byte = i / 7; + } + parity = parity ^ headBit(&bits); + } + if(fails) + { + printf("parity2 fails: %d\n", fails); + }else + { + printf("Key syntax is with parity bits grouped in the last byte!\n"); + } +} +void modifyKey_put_parity_last(uint8_t * key, uint8_t* output) +{ + uint8_t paritybits = 0; + bool parity =0; + BitstreamOut out = { output, 0,0}; + unsigned int bbyte, bbit; + for(bbyte=0; bbyte <8 ; bbyte++ ) + { + for(bbit =0 ; bbit< 7 ; bbit++) + { + bool bit = *(key+bbyte) & (1 << (7-bbit)); + pushBit(&out,bit); + parity ^= bit; + } + bool paritybit = *(key+bbyte) & 1; + paritybits |= paritybit << (7-bbyte); + parity = 0; + + } + output[7] = paritybits; + printf("Parity byte: %02x\n", paritybits); +} + + * @brief Modifies a key with parity bits last, so that it is formed with parity + * bits inside each byte + * @param key + * @param output + +void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output) +{ + bool parity =0; + BitstreamOut out = { output, 0,0}; + BitstreamIn in = {key, 0,0}; + unsigned int bbyte, bbit; + for(bbit =0 ; bbit < 56 ; bbit++) + { + + if( bbit > 0 && bbit % 7 == 0) + { + pushBit(&out,!parity); + parity = 0; + } + bool bit = headBit(&in); + pushBit(&out,bit ); + parity ^= bit; + + } + pushBit(&out, !parity); + + + if( des_key_check_key_parity(output)) + { + printf("modifyKey_put_parity_allover fail, DES key invalid parity!"); + } + +} + +*/ + + diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h new file mode 100644 index 00000000..629fa75b --- /dev/null +++ b/client/loclass/ikeys.h @@ -0,0 +1,32 @@ +#ifndef IKEYS_H +#define IKEYS_H + + +/** + * @brief + *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 ? (F 82 ) 8 be defined as + * hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where + * z'[i] = (z[i] mod (63-i)) + i i = 0...3 + * z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3 + * ? = check(z'); + * @param c + * @param k this is where the diversified key is put (should be 8 bytes) + * @return + */ +void hash0(uint64_t c, uint8_t k[8]); +int doKeyTests(uint8_t debuglevel); +/** + * @brief Performs Elite-class key diversification + * @param csn + * @param key + * @param div_key + */ + +void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]); +/** + * @brief Permutes a key from standard NIST format to Iclass specific format + * @param key + * @param dest + */ + +#endif // IKEYS_H diff --git a/client/loclass/main.c b/client/loclass/main.c new file mode 100644 index 00000000..42019072 --- /dev/null +++ b/client/loclass/main.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with IClassCipher. If not, see . + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "cipherutils.h" +#include "cipher.h" +#include "ikeys.h" +#include "fileutils.h" +#include "elite_crack.h" + +int unitTests() +{ + int errors = testCipherUtils(); + errors += testMAC(); + errors += doKeyTests(0); + errors += testElite(); + return errors; +} +int showHelp() +{ + prnlog("Usage: iclazz [options]"); + prnlog("Options:"); + prnlog("-t Perform self-test"); + prnlog("-h Show this help"); + prnlog("-f Bruteforce iclass dumpfile"); + prnlog(" An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses"); + prnlog(" The the binary format of the file is expected to be as follows: "); + prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + prnlog(" ... totalling N*24 bytes"); + prnlog(" Check iclass_dump.bin for an example"); + + return 0; +} + +int main (int argc, char **argv) +{ + prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n"); + prnlog("Comes with ABSOLUTELY NO WARRANTY"); + prnlog("This is free software, and you are welcome to use, abuse and repackage, please keep the credits\n"); + char *fileName = NULL; + int c; + while ((c = getopt (argc, argv, "thf:")) != -1) + switch (c) + { + case 't': + return unitTests(); + case 'h': + return showHelp(); + case 'f': + fileName = optarg; + return bruteforceFileNoKeys(fileName); + case '?': + if (optopt == 'f') + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf (stderr, + "Unknown option character `\\x%x'.\n", + optopt); + return 1; + //default: + //showHelp(); + } + showHelp(); + return 0; +} + diff --git a/client/mifarehost.h b/client/mifarehost.h index 5de082ce..f21b9139 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -15,7 +15,6 @@ #include "cmdmain.h" #include "ui.h" #include "data.h" -//#include "proxusb.h" #include "util.h" #include "nonce2key/nonce2key.h" #include "nonce2key/crapto1.h" diff --git a/client/proxmark3.c b/client/proxmark3.c index 528cae34..a9819b54 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -62,21 +62,6 @@ struct main_loop_arg { char *script_cmds_file; }; -//static void *usb_receiver(void *targ) { -// struct receiver_arg *arg = (struct receiver_arg*)targ; -// UsbCommand cmdbuf; -// -// while (arg->run) { -// if (ReceiveCommandPoll(&cmdbuf)) { -// UsbCommandReceived(&cmdbuf); -// fflush(NULL); -// } -// } -// -// pthread_exit(NULL); -// return NULL; -//} - byte_t rx[0x1000000]; byte_t* prx = rx; @@ -207,14 +192,6 @@ static void *main_loop(void *targ) { return NULL; } -//static void dumpHelp(char *parent, ...) -//{ -// printf("## %s\n\n", parent); -// CommandReceived(parent); -// -// printf("\n"); -//} - static void dumpAllHelp(int markdown) { printf("\n%sProxmark3 command dump%s\n\n",markdown?"# ":"",markdown?"":"\n======================"); @@ -254,17 +231,6 @@ int main(int argc, char* argv[]) { }; pthread_t main_loop_t; -/* - usb_init(); - if (!OpenProxmark(1)) { - fprintf(stderr,"PROXMARK3: NOT FOUND!\n"); - marg.usb_present = 0; - offline = 1; - } else { - marg.usb_present = 1; - offline = 0; - } -*/ sp = uart_open(argv[1]); if (sp == INVALID_SERIAL_PORT) { @@ -305,10 +271,6 @@ int main(int argc, char* argv[]) { pthread_join(main_loop_t, NULL); -// if (marg.usb_present == 1) { -// CloseProxmark(); -// } - // Clean up the port uart_close(sp); diff --git a/client/proxmark3.h b/client/proxmark3.h index 8236bfe7..a634fd68 100644 --- a/client/proxmark3.h +++ b/client/proxmark3.h @@ -20,7 +20,7 @@ #include "usb_cmd.h" -#define PROXPROMPT "proxmark3> " +#define PROXPROMPT "pm3 --> " void SendCommand(UsbCommand *c); diff --git a/client/ui.c b/client/ui.c index c0d01bc3..6486d524 100644 --- a/client/ui.c +++ b/client/ui.c @@ -90,3 +90,195 @@ void SetLogFilename(char *fn) { logfilename = fn; } + + +uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout){ + + size_t bytelength = len; + + uint8_t bitStream[bytelength]; + memset(bitStream, 0x00, bytelength); + + int clock,high, low, bit, hithigh, hitlow, first, bit2idx, lastpeak; + int i,invert, lastval; + int bitidx = 0; + int lc = 0; + int warnings = 0; + high = 1; + low = bit = bit2idx = lastpeak = invert = lastval = hithigh = hitlow = first = 0; + clock = 0xFFFF; + + /* Detect high and lows */ + for (i = 0; i < bytelength; i++) { + if (data[i] > high) + high = data[i]; + else if (data[i] < low) + low = data[i]; + } + + /* get clock */ + int j=0; + for (i = 1; i < bytelength; i++) { + /* if this is the beginning of a peak */ + j = i-1; + if ( data[j] != data[i] && + data[i] == high) + { + /* find lowest difference between peaks */ + if (lastpeak && i - lastpeak < clock) + clock = i - lastpeak; + lastpeak = i; + } + } + + int tolerance = clock/4; + PrintAndLog(" Detected clock: %d",clock); + + /* Detect first transition */ + /* Lo-Hi (arbitrary) */ + /* skip to the first high */ + for (i= 0; i < bytelength; i++) + if (data[i] == high) + break; + + /* now look for the first low */ + for (; i < bytelength; i++) { + if (data[i] == low) { + lastval = i; + break; + } + } + + /* If we're not working with 1/0s, demod based off clock */ + if (high != 1) + { + bit = 0; /* We assume the 1st bit is zero, it may not be + * the case: this routine (I think) has an init problem. + * Ed. + */ + for (; i < (int)(bytelength / clock); i++) + { + hithigh = 0; + hitlow = 0; + first = 1; + + /* Find out if we hit both high and low peaks */ + for (j = 0; j < clock; j++) + { + if (data[(i * clock) + j] == high) + hithigh = 1; + else if (data[(i * clock) + j] == low) + hitlow = 1; + + /* it doesn't count if it's the first part of our read + because it's really just trailing from the last sequence */ + if (first && (hithigh || hitlow)) + hithigh = hitlow = 0; + else + first = 0; + + if (hithigh && hitlow) + break; + } + + /* If we didn't hit both high and low peaks, we had a bit transition */ + if (!hithigh || !hitlow) + bit ^= 1; + + bitStream[bit2idx++] = bit ^ invert; + } + } + /* standard 1/0 bitstream */ + else { + /* Then detect duration between 2 successive transitions */ + for (bitidx = 1; i < bytelength; i++) { + + if (data[i-1] != data[i]) { + lc = i-lastval; + lastval = i; + + // Error check: if bitidx becomes too large, we do not + // have a Manchester encoded bitstream or the clock is really + // wrong! + if (bitidx > (bytelength*2/clock+8) ) { + 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" + bitStream[bitidx++] = data[i-1]; + } else if (abs(lc-clock) < tolerance) { + // Long pulse: either "11" or "00" + bitStream[bitidx++] = data[i-1]; + bitStream[bitidx++] = data[i-1]; + } else { + // Error + warnings++; + PrintAndLog("Warning: Manchester decode error for pulse width detection."); + if (warnings > 10) { + PrintAndLog("Error: too many detection errors, aborting."); + return 0; + } + } + } + } + } + // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream + // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful + // to stop output at the final bitidx2 value, not bitidx + for (i = 0; i < bitidx; i += 2) { + if ((bitStream[i] == 0) && (bitStream[i+1] == 1)) { + bitStream[bit2idx++] = 1 ^ invert; + } + else if ((bitStream[i] == 1) && (bitStream[i+1] == 0)) { + bitStream[bit2idx++] = 0 ^ invert; + } + else { + // We cannot end up in this state, this means we are unsynchronized, + // move up 1 bit: + i++; + warnings++; + PrintAndLog("Unsynchronized, resync..."); + if (warnings > 10) { + PrintAndLog("Error: too many decode errors, aborting."); + return 0; + } + } + } + + // PrintAndLog(" Manchester decoded bitstream : %d bits", (bit2idx-16)); + // uint8_t mod = (bit2idx-16) % blocksize; + // uint8_t div = (bit2idx-16) / blocksize; + + // // 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) ); + // } + + if ( bit2idx > 0 ) + memcpy(dataout, bitStream, bit2idx); + + free(bitStream); + return bit2idx; +} + +void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){ + + PrintAndLog(" Manchester decoded bitstream : %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) ); + } +} diff --git a/client/ui.h b/client/ui.h index a45799d5..2f2ed189 100644 --- a/client/ui.h +++ b/client/ui.h @@ -11,6 +11,8 @@ #ifndef UI_H__ #define UI_H__ +#include "util.h" + void ShowGui(void); void HideGraphWindow(void); void ShowGraphWindow(void); @@ -23,4 +25,6 @@ extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault; extern int offline; extern int flushAfterWrite; //buzzy +uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout); +void PrintPaddedManchester( uint8_t * bitStream, size_t len, size_t blocksize); #endif diff --git a/client/util.c b/client/util.c index 15e911a1..1ebfebea 100644 --- a/client/util.c +++ b/client/util.c @@ -13,6 +13,7 @@ #ifndef _WIN32 #include #include + int ukbhit(void) { int cnt = 0; @@ -112,6 +113,17 @@ char * sprint_hex(const uint8_t * data, const size_t len) { return buf; } +char * sprint_bin(const uint8_t * data, const size_t len) { + static char buf[1024]; + char * tmp = buf; + size_t i; + + for (i=0; i < len && i < 1024; i++, tmp++) + sprintf(tmp, "%u", data[i]); + + return buf; +} + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { @@ -131,6 +143,28 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } +//assumes little endian +char * printBits(size_t const size, void const * const ptr) +{ + unsigned char *b = (unsigned char*) ptr; + unsigned char byte; + static char buf[1024]; + char * tmp = buf; + int i, j; + + for (i=size-1;i>=0;i--) + { + for (j=7;j>=0;j--) + { + byte = b[i] & (1<>= j; + sprintf(tmp, "%u", byte); + tmp++; + } + } + return buf; +} + // ------------------------------------------------------------------------- // string parameters lib // ------------------------------------------------------------------------- diff --git a/client/util.h b/client/util.h index ce8876ed..2677ab84 100644 --- a/client/util.h +++ b/client/util.h @@ -33,9 +33,11 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount); void print_hex(const uint8_t * data, const size_t len); char * sprint_hex(const uint8_t * data, const size_t len); +char * sprint_bin(const uint8_t * data, const size_t len); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); +char * printBits(size_t const size, void const * const ptr); char param_getchar(const char *line, int paramnum); uint8_t param_get8(const char *line, int paramnum); @@ -45,3 +47,4 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base); int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt); int param_getstr(const char *line, int paramnum, char * str); + diff --git a/common/Makefile.common b/common/Makefile.common index 2befd456..2b2bb2fb 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -54,7 +54,8 @@ DELETE=del /q MOVE=ren COPY=copy PATHSEP=\\# -FLASH_TOOL=winsrc\\prox.exe +#FLASH_TOOL=winsrc\\prox.exe +FLASH_TOOL=winsrc\\flash.exe DETECTED_OS=Windows endif @@ -67,6 +68,7 @@ INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gp CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 $(APP_CFLAGS) -Os LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n + LIBS = -lgcc THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(THUMBSRC)) diff --git a/common/cmd.c b/common/cmd.c index 49d9d942..dae3a8da 100644 --- a/common/cmd.c +++ b/common/cmd.c @@ -32,7 +32,7 @@ #include "cmd.h" #include "string.h" -#include "proxmark3.h" +#include "../include/proxmark3.h" //static UsbCommand txcmd; diff --git a/common/cmd.h b/common/cmd.h index b330a219..35885de4 100644 --- a/common/cmd.h +++ b/common/cmd.h @@ -33,8 +33,8 @@ #ifndef _PROXMARK_CMD_H_ #define _PROXMARK_CMD_H_ -#include -#include +#include "../include/common.h" +#include "../include/usb_cmd.h" #include "usb_cdc.h" bool cmd_receive(UsbCommand* cmd); diff --git a/include/crc.h b/common/crc.h similarity index 100% rename from include/crc.h rename to common/crc.h diff --git a/common/crc32.c b/common/crc32.c new file mode 100644 index 00000000..69d770f4 --- /dev/null +++ b/common/crc32.c @@ -0,0 +1,35 @@ +#include +#include +#include "crc32.h" + +#define htole32(x) (x) +#define CRC32_PRESET 0xFFFFFFFF + + +static void crc32_byte (uint32_t *crc, const uint8_t value); + +static void crc32_byte (uint32_t *crc, const uint8_t value) { + /* x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 */ + const uint32_t poly = 0xEDB88320; + + *crc ^= value; + for (int current_bit = 7; current_bit >= 0; current_bit--) { + int bit_out = (*crc) & 0x00000001; + *crc >>= 1; + if (bit_out) + *crc ^= poly; + } +} + +void crc32 (const uint8_t *data, const size_t len, uint8_t *crc) { + uint32_t desfire_crc = CRC32_PRESET; + for (size_t i = 0; i < len; i++) { + crc32_byte (&desfire_crc, data[i]); + } + + *((uint32_t *)(crc)) = htole32 (desfire_crc); +} + +void crc32_append (uint8_t *data, const size_t len) { + crc32 (data, len, data + len); +} diff --git a/common/crc32.h b/common/crc32.h new file mode 100644 index 00000000..0dd2a328 --- /dev/null +++ b/common/crc32.h @@ -0,0 +1,15 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// CRC32 +//----------------------------------------------------------------------------- + +#ifndef __CRC32_H +#define __CRC32_H + +void crc32 (const uint8_t *data, const size_t len, uint8_t *crc); +void crc32_append (uint8_t *data, const size_t len); + +#endif diff --git a/common/desfire.h b/common/desfire.h new file mode 100644 index 00000000..912ca9ff --- /dev/null +++ b/common/desfire.h @@ -0,0 +1,177 @@ +#ifndef __DESFIRE_H +#define __DESFIRE_H + +#include "aes.h" +#define DESFIRE(tag) ((struct desfire_tag *) tag) +#define DESFIRE_KEY(key) ((struct desfire_key *) key) + +#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 +}; + +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; + +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 + diff --git a/common/iso14443crc.c b/common/iso14443crc.c index a6def1a9..851546ae 100644 --- a/common/iso14443crc.c +++ b/common/iso14443crc.c @@ -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) { diff --git a/common/iso14443crc.h b/common/iso14443crc.h index 87347714..80941116 100644 --- a/common/iso14443crc.h +++ b/common/iso14443crc.h @@ -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) diff --git a/common/iso15693tools.c b/common/iso15693tools.c index add0ba69..964059ce 100644 --- a/common/iso15693tools.c +++ b/common/iso15693tools.c @@ -7,11 +7,14 @@ //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include "../include/proxmark3.h" #include #include //#include "iso15693tools.h" +#define POLY 0x8408 + + // The CRC as described in ISO 15693-Part 3-Annex C // v buffer with data // n length @@ -63,5 +66,31 @@ char* Iso15693sprintUID(char *target,uint8_t *uid) { return target; } +unsigned short iclass_crc16(char *data_p, unsigned short length) +{ + unsigned char i; + unsigned int data; + unsigned int crc = 0xffff; + if (length == 0) + return (~crc); + + do + { + for (i=0, data=(unsigned int)0xff & *data_p++; + i < 8; + i++, data >>= 1) + { + if ((crc & 0x0001) ^ (data & 0x0001)) + crc = (crc >> 1) ^ POLY; + else crc >>= 1; + } + } while (--length); + + crc = ~crc; + data = crc; + crc = (crc << 8) | (data >> 8 & 0xff); + crc = crc ^ 0xBC3; + return (crc); +} diff --git a/common/iso15693tools.h b/common/iso15693tools.h index c831fec4..ec63728f 100644 --- a/common/iso15693tools.h +++ b/common/iso15693tools.h @@ -70,6 +70,7 @@ uint16_t Iso15693Crc(uint8_t *v, int n); int Iso15693AddCrc(uint8_t *req, int n); char* Iso15693sprintUID(char *target,uint8_t *uid); +unsigned short iclass_crc16(char *data_p, unsigned short length); //----------------------------------------------------------------------------- // Map a sequence of octets (~layer 2 command) into the set of bits to feed diff --git a/common/legic_prng.c b/common/legic_prng.c index 4f3b1ffe..322429ad 100644 --- a/common/legic_prng.c +++ b/common/legic_prng.c @@ -6,7 +6,7 @@ // LEFIC's obfuscation function //----------------------------------------------------------------------------- -#include "legic_prng.h" +#include "../include/legic_prng.h" struct lfsr { uint8_t a; diff --git a/common/usb_cdc.c b/common/usb_cdc.c index e2787fb6..097d9a4e 100644 --- a/common/usb_cdc.c +++ b/common/usb_cdc.c @@ -33,7 +33,7 @@ */ #include "usb_cdc.h" -#include "config_gpio.h" +#include "../include/config_gpio.h" #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) diff --git a/common/usb_cdc.h b/common/usb_cdc.h index d7b9c2e5..b6489937 100644 --- a/common/usb_cdc.h +++ b/common/usb_cdc.h @@ -35,7 +35,7 @@ #ifndef _USB_CDC_H_ #define _USB_CDC_H_ -#include +#include "../include/common.h" void usb_disable(); void usb_enable(); diff --git a/include/crc.h.old b/include/crc.h.old new file mode 100644 index 00000000..8e68f3b3 --- /dev/null +++ b/include/crc.h.old @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// Generic CRC calculation code. +//----------------------------------------------------------------------------- + +#ifndef __CRC_H +#define __CRC_H + +#include + +typedef struct crc { + uint32_t state; + int order; + uint32_t polynom; + uint32_t initial_value; + uint32_t final_xor; + uint32_t mask; +} crc_t; + +/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32 + * polynom is the CRC polynom. initial_value is the initial value of a clean state. + * final_xor is XORed onto the state before returning it from crc_result(). */ +extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor); + +/* Update the crc state. data is the data of length data_width bits (only the the + * data_width lower-most bits are used). + */ +extern void crc_update(crc_t *crc, uint32_t data, int data_width); + +/* Clean the crc state, e.g. reset it to initial_value */ +extern void crc_clear(crc_t *crc); + +/* Get the result of the crc calculation */ +extern uint32_t crc_finish(crc_t *crc); + +/* Static initialization of a crc structure */ +#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \ + .state = ((_initial_value) & ((1L<<(_order))-1)), \ + .order = (_order), \ + .polynom = (_polynom), \ + .initial_value = (_initial_value), \ + .final_xor = (_final_xor), \ + .mask = ((1L<<(_order))-1) } + +#endif /* __CRC_H */ diff --git a/include/mifare.h b/include/mifare.h index e2b7a7c5..403132ac 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -11,7 +11,7 @@ #ifndef _MIFARE_H_ #define _MIFARE_H_ -#include "common.h" +#include "../include/common.h" //----------------------------------------------------------------------------- // ISO 14443A diff --git a/include/proxmark3.h b/include/proxmark3.h index 8c9417da..b3530c64 100644 --- a/include/proxmark3.h +++ b/include/proxmark3.h @@ -14,6 +14,7 @@ // Might as well have the hardware-specific defines everywhere. #include "at91sam7s512.h" #include "config_gpio.h" +#include "usb_cmd.h" #define WDT_HIT() AT91C_BASE_WDTC->WDTC_WDCR = 0xa5000001 @@ -67,8 +68,6 @@ #define TRUE 1 #define FALSE 0 -#include - //#define PACKED __attribute__((__packed__)) #define LED_A_ON() HIGH(GPIO_LED_A) diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 4b1fc2b6..23555ab4 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -117,6 +117,8 @@ typedef struct { #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 // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400 @@ -151,6 +153,19 @@ typedef struct { #define CMD_MIFARE_CHKKEYS 0x0623 #define CMD_MIFARE_SNIFFER 0x0630 +//ultralightC +#define CMD_MIFAREUC_AUTH1 0x0724 +#define CMD_MIFAREUC_AUTH2 0x0725 +#define CMD_MIFAREUC_READCARD 0x0726 + + +// mifare desfire +#define CMD_MIFARE_DESFIRE_READBL 0x0728 +#define CMD_MIFARE_DESFIRE_WRITEBL 0x0729 +#define CMD_MIFARE_DESFIRE_AUTH1 0x072a +#define CMD_MIFARE_DESFIRE_AUTH2 0x072b +#define CMD_MIFARE_DES_READER 0x072c +#define CMD_MIFARE_DESFIRE_INFO 0x072d #define CMD_UNKNOWN 0xFFFF @@ -162,6 +177,8 @@ typedef struct { #define FLAG_NR_AR_ATTACK 0x08 +//Iclass reader flags +#define FLAG_ICLASS_READER_ONLY_ONCE 0x01 // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ From b44e523300b3fbe0a5d9b3081aaa588be3095b14 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 16 Sep 2014 13:56:06 +0200 Subject: [PATCH 03/78] LF t55xx and LF em4x commands now should manchester decode data. However t55xx can have other settings and different encodings. --- armsrc/appmain.c | 2 +- armsrc/mifaredesfire.c | 13 +- armsrc/mifaredesfire.h | 1 - client/cmddata.c | 5 +- client/cmdhfmf.c | 59 +++++---- client/cmdlfem4x.c | 115 ++++++++-------- client/cmdlft55xx.c | 97 +++++++------- client/ui.c | 294 ++++++++++++++++++++++++++--------------- client/ui.h | 7 +- 9 files changed, 351 insertions(+), 242 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 6f8b0150..9e4b32cd 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -993,7 +993,7 @@ void __attribute__((noreturn)) AppMain(void) LED_B_OFF(); LED_A_OFF(); - // Init USB device` + // Init USB device usb_enable(); // The FPGA gets its clock from us from PCK0 output, so set that up. diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index d3b04fb0..14c6aa34 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -131,16 +131,15 @@ void MifareDesfireGetInformation(){ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain){ uint8_t null_key_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t new_key_data[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; - int res; + //uint8_t new_key_data[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; + int res = 0; - MifareDESFireKey default_key = mifare_desfire_des_key_new_with_version (null_key_data); + desfirekey_t default_key = Desfire_des_key_new_with_version (null_key_data); - res = mifare_desfire_select_application (tags[i], aid); + // res = Desfire_select_application (tags[i], aid); if (res < 0) { - freefare_perror (tags[i], "mifare_desfire_select_application"); - error = EXIT_FAILURE; - break; + print_result("default key: ", default_key->data, 24 ); + return; } return; diff --git a/armsrc/mifaredesfire.h b/armsrc/mifaredesfire.h index 5d490e2e..fc661f22 100644 --- a/armsrc/mifaredesfire.h +++ b/armsrc/mifaredesfire.h @@ -12,5 +12,4 @@ #include "mifareutil.h" #include "../include/common.h" - #endif diff --git a/client/cmddata.c b/client/cmddata.c index fa54d01a..72bc52e6 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -588,13 +588,16 @@ int CmdManchesterDemod(const char *Cmd) } } + PrintAndLog("Clock: %d", clock); + /* If we're not working with 1/0s, demod based off clock */ if (high != 1) { + PrintAndLog("Entering path A"); bit = 0; /* We assume the 1st bit is zero, it may not be * the case: this routine (I think) has an init problem. * Ed. - */ + */ for (; i < (int)(GraphTraceLen / clock); i++) { hithigh = 0; diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index e892b377..8448731e 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -524,7 +524,7 @@ int CmdHF14AMfDump(const char *Cmd) PrintAndLog("Got %d",size); - return; + return 0; if ( size > -1) cmdp = (char)48+size; @@ -1027,6 +1027,18 @@ int CmdHF14AMfNested(const char *Cmd) int CmdHF14AMfChk(const char *Cmd) { + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mf chk |<*card memory> [t|d] [] []"); + PrintAndLog(" * - all sectors"); + PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLog("d - write keys to binary file\n"); + PrintAndLog("t - write keys to emulator memory"); + PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic"); + PrintAndLog(" hf mf chk *1 ? t"); + PrintAndLog(" hf mf chk *1 ? d"); + return 0; + } + FILE * f; char filename[256]={0}; char buf[13]; @@ -1070,16 +1082,6 @@ int CmdHF14AMfChk(const char *Cmd) num_to_bytes(defaultKeys[defaultKeyCounter], 6, (uint8_t*)(keyBlock + defaultKeyCounter * 6)); } - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf mf chk |<*card memory> [t] [] []"); - PrintAndLog(" * - all sectors"); - PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); - PrintAndLog("d - write keys to binary file\n"); - PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic"); - PrintAndLog(" hf mf chk *1 ? t"); - return 0; - } - if (param_getchar(Cmd, 0)=='*') { blockNo = 3; switch(param_getchar(Cmd+1, 0)) { @@ -2090,49 +2092,56 @@ int GetCardSize() // NXP MIFARE Mini 0.3k - if ( (atqa && 0xff0f == 0x0004) && (sak == 0x09) ) return 0; + if ( ( (atqa & 0xff0f) == 0x0004) && (sak == 0x09) ) return 0; // MIFARE Classic 1K - if ( (atqa && 0xff0f == 0x0004) && (sak == 0x08) ) return 1; + if ( ((atqa & 0xff0f) == 0x0004) && (sak == 0x08) ) return 1; // MIFARE Classik 4K - if ( (atqa && 0xff0f == 0x0002) && (sak == 0x18) ) return 4; + if ( ((atqa & 0xff0f) == 0x0002) && (sak == 0x18) ) return 4; // SmartMX with MIFARE 1K emulation - if ( (atqa && 0xf0ff == 0x0004) ) return 1; + if ( ((atqa & 0xf0ff) == 0x0004) ) return 1; // SmartMX with MIFARE 4K emulation - if ( (atqa && 0xf0ff == 0x0002) ) return 4; + if ( ((atqa & 0xf0ff) == 0x0002) ) return 4; // Infineon MIFARE CLASSIC 1K - if ( (atqa && 0xffff == 0x0004) && (sak == 0x88) ) return 1; + if ( ((atqa & 0xffff) == 0x0004) && (sak == 0x88) ) return 1; // MFC 4K emulated by Nokia 6212 Classic - if ( (atqa && 0xffff == 0x0002) && (sak == 0x38) ) return 4; + if ( ((atqa & 0xffff) == 0x0002) && (sak == 0x38) ) return 4; // MFC 4K emulated by Nokia 6131 NFC - if ( (atqa && 0xffff == 0x0008) && (sak == 0x38) ) return 4; + if ( ((atqa & 0xffff) == 0x0008) && (sak == 0x38) ) return 4; + + PrintAndLog("BEFOOO 1K %02X", (atqa & 0xff0f)); + // MIFARE Plus (4 Byte UID or 4 Byte RID) // MIFARE Plus (7 Byte UID) if ( - (atqa && 0xffff == 0x0002) || - (atqa && 0xffff == 0x0004) || - (atqa && 0xffff == 0x0042) || - (atqa && 0xffff == 0x0044) + ((atqa & 0xffff) == 0x0002) | + ((atqa & 0xffff) == 0x0004) | + ((atqa & 0xffff) == 0x0042) | + ((atqa & 0xffff) == 0x0044) ) { switch(sak){ case 0x08: - case 0x10: + case 0x10: { //case 0x20: + PrintAndLog("2"); return 2; break; + } case 0x11: - case 0x18: + case 0x18:{ //case 0x20: + PrintAndLog("4"); return 4; break; + } } } diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index be31e1ea..3c46d3b1 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -21,6 +21,7 @@ #include "cmdlfem4x.h" #include "util.h" #include "data.h" +#define LF_TRACE_BUFF_SIZE 16000 char *global_em410xId; @@ -506,41 +507,47 @@ int CmdEM410xWrite(const char *Cmd) int CmdReadWord(const char *Cmd) { int Word = -1; //default to invalid word - UsbCommand c; + UsbCommand c; - sscanf(Cmd, "%d", &Word); + sscanf(Cmd, "%d", &Word); if ( (Word > 15) | (Word < 0) ) { - PrintAndLog("Word must be between 0 and 15"); - return 1; - } + PrintAndLog("Word must be between 0 and 15"); + return 1; + } - PrintAndLog("Reading word %d", Word); + PrintAndLog("Reading word %d", Word); - c.cmd = CMD_EM4X_READ_WORD; - c.d.asBytes[0] = 0x0; //Normal mode - c.arg[0] = 0; - c.arg[1] = Word; - c.arg[2] = 0; - SendCommand(&c); + c.cmd = CMD_EM4X_READ_WORD; + c.d.asBytes[0] = 0x0; //Normal mode + c.arg[0] = 0; + c.arg[1] = Word; + c.arg[2] = 0; + SendCommand(&c); WaitForResponse(CMD_ACK, NULL); - size_t bytelength = 4096; - uint8_t data[bytelength]; - memset(data, 0x00, bytelength); + uint8_t data[LF_TRACE_BUFF_SIZE]; + memset(data, 0x00, LF_TRACE_BUFF_SIZE); - GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset.. + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); - for (int j = 0; j < bytelength; j++) { + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { GraphBuffer[j] = ((int)data[j]) - 128; } - GraphTraceLen = bytelength; - RepaintGraphWindow(); - - manchester_decode(data, bytelength); - - free(data); + GraphTraceLen = LF_TRACE_BUFF_SIZE; + + // BiDirectional + //CmdDirectionalThreshold("70 -60"); + + // Askdemod + //Cmdaskdemod("1"); + + uint8_t bits[1000]; + uint8_t * bitstream = bits; + memset(bitstream, 0x00, sizeof(bits)); + + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); return 0; } @@ -548,42 +555,48 @@ int CmdReadWord(const char *Cmd) int CmdReadWordPWD(const char *Cmd) { int Word = -1; //default to invalid word - int Password = 0xFFFFFFFF; //default to blank password - UsbCommand c; - - sscanf(Cmd, "%d %x", &Word, &Password); - + int Password = 0xFFFFFFFF; //default to blank password + UsbCommand c; + + sscanf(Cmd, "%d %x", &Word, &Password); + if ( (Word > 15) | (Word < 0) ) { - PrintAndLog("Word must be between 0 and 15"); - return 1; - } + PrintAndLog("Word must be between 0 and 15"); + return 1; + } - PrintAndLog("Reading word %d with password %08X", Word, Password); - - c.cmd = CMD_EM4X_READ_WORD; - c.d.asBytes[0] = 0x1; //Password mode - c.arg[0] = 0; - c.arg[1] = Word; - c.arg[2] = Password; - SendCommand(&c); + PrintAndLog("Reading word %d with password %08X", Word, Password); + + c.cmd = CMD_EM4X_READ_WORD; + c.d.asBytes[0] = 0x1; //Password mode + c.arg[0] = 0; + c.arg[1] = Word; + c.arg[2] = Password; + SendCommand(&c); WaitForResponse(CMD_ACK, NULL); + + uint8_t data[LF_TRACE_BUFF_SIZE]; + memset(data, 0x00, LF_TRACE_BUFF_SIZE); - size_t bytelength = 4096; - uint8_t data[bytelength]; - memset(data, 0x00, bytelength); - - GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset.. + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); - for (int j = 0; j < bytelength; j++) { + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { GraphBuffer[j] = ((int)data[j]) - 128; } - GraphTraceLen = bytelength; - RepaintGraphWindow(); + GraphTraceLen = LF_TRACE_BUFF_SIZE; - manchester_decode(data, bytelength); - - free(data); + // BiDirectional + //CmdDirectionalThreshold("70 -60"); + + // Askdemod + //Cmdaskdemod("1"); + + uint8_t bits[1000]; + uint8_t * bitstream = bits; + memset(bitstream, 0x00, sizeof(bits)); + + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); return 0; } @@ -636,8 +649,6 @@ int CmdWriteWordPWD(const char *Cmd) return 0; } - - static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 5a464ddb..a002bf34 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -29,25 +29,25 @@ int CmdReadBlk(const char *Cmd) { //default to invalid block int Block = -1; - UsbCommand c; + UsbCommand c; - sscanf(Cmd, "%d", &Block); + sscanf(Cmd, "%d", &Block); if ((Block > 7) | (Block < 0)) { - PrintAndLog("Block must be between 0 and 7"); - return 1; - } + PrintAndLog("Block must be between 0 and 7"); + return 1; + } PrintAndLog(" Reading page 0 block : %d", Block); // this command fills up BigBuff // - c.cmd = CMD_T55XX_READ_BLOCK; + c.cmd = CMD_T55XX_READ_BLOCK; c.d.asBytes[0] = 0x00; - c.arg[0] = 0; - c.arg[1] = Block; - c.arg[2] = 0; - SendCommand(&c); + c.arg[0] = 0; + c.arg[1] = Block; + c.arg[2] = 0; + SendCommand(&c); WaitForResponse(CMD_ACK, NULL); uint8_t data[LF_TRACE_BUFF_SIZE]; @@ -62,18 +62,17 @@ int CmdReadBlk(const char *Cmd) GraphTraceLen = LF_TRACE_BUFF_SIZE; // BiDirectional - CmdDirectionalThreshold("70 -60"); + //CmdDirectionalThreshold("70 60"); // Askdemod - Cmdaskdemod("1"); + //Cmdaskdemod("1"); uint8_t bits[1000]; uint8_t * bitstream = bits; - uint8_t len = 0; - len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bitstream); - if ( len > 0 ) - PrintPaddedManchester(bitstream, len, 32); - + memset(bitstream, 0x00, sizeof(bits)); + + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + return 0; } @@ -81,24 +80,24 @@ int CmdReadBlk(const char *Cmd) int CmdReadBlkPWD(const char *Cmd) { int Block = -1; //default to invalid block - int Password = 0xFFFFFFFF; //default to blank Block 7 - UsbCommand c; + int Password = 0xFFFFFFFF; //default to blank Block 7 + UsbCommand c; - sscanf(Cmd, "%d %x", &Block, &Password); + sscanf(Cmd, "%d %x", &Block, &Password); if ((Block > 7) | (Block < 0)) { - PrintAndLog("Block must be between 0 and 7"); - return 1; - } + PrintAndLog("Block must be between 0 and 7"); + return 1; + } PrintAndLog("Reading page 0 block %d pwd %08X", Block, Password); - c.cmd = CMD_T55XX_READ_BLOCK; - c.d.asBytes[0] = 0x1; //Password mode - c.arg[0] = 0; - c.arg[1] = Block; - c.arg[2] = Password; - SendCommand(&c); + c.cmd = CMD_T55XX_READ_BLOCK; + c.d.asBytes[0] = 0x1; //Password mode + c.arg[0] = 0; + c.arg[1] = Block; + c.arg[2] = Password; + SendCommand(&c); WaitForResponse(CMD_ACK, NULL); uint8_t data[LF_TRACE_BUFF_SIZE]; @@ -113,17 +112,16 @@ int CmdReadBlkPWD(const char *Cmd) GraphTraceLen = LF_TRACE_BUFF_SIZE; // BiDirectional - CmdDirectionalThreshold("70 -60"); + //CmdDirectionalThreshold("70 -60"); // Askdemod - Cmdaskdemod("1"); + //Cmdaskdemod("1"); uint8_t bits[1000]; - uint8_t len = 0; - len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bits); - if ( len > 0 ) - PrintPaddedManchester(bits, len, 32); - + uint8_t * bitstream = bits; + memset(bitstream, 0x00, sizeof(bits)); + + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); return 0; } @@ -197,28 +195,29 @@ int CmdReadTrace(const char *Cmd) GraphTraceLen = LF_TRACE_BUFF_SIZE; // BiDirectional - CmdDirectionalThreshold("70 -60"); + //CmdDirectionalThreshold("70 -60"); // Askdemod - Cmdaskdemod("1"); + //Cmdaskdemod("1"); - uint8_t bits[512]; - uint8_t len = 0; - len = manchester_decode(data,LF_TRACE_BUFF_SIZE,bits); - if ( len > 0 ) - PrintPaddedManchester(bits, len, 64); + + uint8_t bits[1000]; + uint8_t * bitstream = bits; + memset(bitstream, 0x00, sizeof(bits)); + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + return 0; } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"readblock", CmdReadBlk, 1, " -- Read T55xx block data (page 0)"}, - {"readblockPWD", CmdReadBlkPWD, 1, " -- Read T55xx block data in password mode(page 0)"}, - {"writeblock", CmdWriteBlk, 1, " -- Write T55xx block data (page 0)"}, - {"writeblockPWD", CmdWriteBlkPWD, 1, " -- Write T55xx block data in password mode(page 0)"}, - {"readtrace", CmdReadTrace, 1, "Read T55xx traceability data (page 1)"}, + {"help", CmdHelp, 1, "This help"}, + {"rd", CmdReadBlk, 0, " -- Read T55xx block data (page 0)"}, + {"rdPWD", CmdReadBlkPWD, 0, " -- Read T55xx block data in password mode(page 0)"}, + {"wr", CmdWriteBlk, 0, " -- Write T55xx block data (page 0)"}, + {"wrPWD", CmdWriteBlkPWD, 0, " -- Write T55xx block data in password mode(page 0)"}, + {"trace", CmdReadTrace, 0, "Read T55xx traceability data (page 1)"}, {NULL, NULL, 0, NULL} }; diff --git a/client/ui.c b/client/ui.c index 6486d524..4f1b5d85 100644 --- a/client/ui.c +++ b/client/ui.c @@ -92,24 +92,18 @@ void SetLogFilename(char *fn) } -uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout){ +int manchester_decode(const int * data, const size_t len, uint8_t * dataout){ - size_t bytelength = len; - - uint8_t bitStream[bytelength]; - memset(bitStream, 0x00, bytelength); - - int clock,high, low, bit, hithigh, hitlow, first, bit2idx, lastpeak; - int i,invert, lastval; - int bitidx = 0; - int lc = 0; - int warnings = 0; + int bitlength = 0; + int i, clock, high, low, startindex; + low = startindex = 0; high = 1; - low = bit = bit2idx = lastpeak = invert = lastval = hithigh = hitlow = first = 0; - clock = 0xFFFF; + uint8_t bitStream[len]; + memset(bitStream, 0x00, len); + /* Detect high and lows */ - for (i = 0; i < bytelength; i++) { + for (i = 0; i < len; i++) { if (data[i] > high) high = data[i]; else if (data[i] < low) @@ -117,47 +111,106 @@ uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * data } /* get clock */ - int j=0; - for (i = 1; i < bytelength; i++) { + clock = GetT55x7Clock( data, len, high ); + startindex = DetectFirstTransition(data, len, high, low); + + PrintAndLog(" Clock : %d", clock); + PrintAndLog(" startindex : %d", startindex); + + if (high != 1) + bitlength = ManchesterConvertFrom255(data, len, bitStream, high, low, clock, startindex); + else + bitlength= ManchesterConvertFrom1(data, len, bitStream, clock, startindex); + + if ( bitlength > 0 ){ + PrintPaddedManchester(bitStream, bitlength, clock); + } + + memcpy(dataout, bitStream, bitlength); + + free(bitStream); + return bitlength; +} + + int GetT55x7Clock( const int * data, const size_t len, int peak ){ + + int i,lastpeak,clock; + clock = 0xFFFF; + lastpeak = 0; + + /* Detect peak if we don't have one */ + if (!peak) { + for (i = 0; i < len; ++i) { + if (data[i] > peak) { + peak = data[i]; + } + } + } + + for (i = 1; i < len; ++i) { /* if this is the beginning of a peak */ - j = i-1; - if ( data[j] != data[i] && - data[i] == high) - { + if ( data[i-1] != data[i] && data[i] == peak) { /* find lowest difference between peaks */ if (lastpeak && i - lastpeak < clock) clock = i - lastpeak; lastpeak = i; } } - - int tolerance = clock/4; - PrintAndLog(" Detected clock: %d",clock); + //return clock; + //defaults clock to precise values. + switch(clock){ + case 8: + case 16: + case 32: + case 40: + case 50: + case 64: + case 100: + case 128: + return clock; + break; + default: break; + } + return 32; + } + + int DetectFirstTransition(const int * data, const size_t len, int high, int low){ - /* Detect first transition */ - /* Lo-Hi (arbitrary) */ - /* skip to the first high */ - for (i= 0; i < bytelength; i++) + int i, retval; + retval = 0; + /* + Detect first transition Lo-Hi (arbitrary) + skip to the first high + */ + for (i = 0; i < len; ++i) if (data[i] == high) break; /* now look for the first low */ - for (; i < bytelength; i++) { + for (; i < len; ++i) { if (data[i] == low) { - lastval = i; + retval = i; break; } } - - /* If we're not working with 1/0s, demod based off clock */ - if (high != 1) + return retval; + } + + int ManchesterConvertFrom255(const int * data, const size_t len, uint8_t * dataout, int high, int low, int clock, int startIndex){ + + int i, j, hithigh, hitlow, first, bit, bitIndex; + i = startIndex; + bitIndex = 0; + + /* + * We assume the 1st bit is zero, it may not be + * the case: this routine (I think) has an init problem. + * Ed. + */ + bit = 0; + + for (; i < (int)(len / clock); i++) { - bit = 0; /* We assume the 1st bit is zero, it may not be - * the case: this routine (I think) has an init problem. - * Ed. - */ - for (; i < (int)(bytelength / clock); i++) - { hithigh = 0; hitlow = 0; first = 1; @@ -179,94 +232,125 @@ uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * data if (hithigh && hitlow) break; - } + } - /* If we didn't hit both high and low peaks, we had a bit transition */ - if (!hithigh || !hitlow) + /* If we didn't hit both high and low peaks, we had a bit transition */ + if (!hithigh || !hitlow) bit ^= 1; - bitStream[bit2idx++] = bit ^ invert; - } + dataout[bitIndex++] = bit; } - /* standard 1/0 bitstream */ - else { - /* Then detect duration between 2 successive transitions */ - for (bitidx = 1; i < bytelength; i++) { - - if (data[i-1] != data[i]) { - lc = i-lastval; - lastval = i; + return bitIndex; + } + + int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout, int clock, int startIndex){ - // Error check: if bitidx becomes too large, we do not - // have a Manchester encoded bitstream or the clock is really - // wrong! - if (bitidx > (bytelength*2/clock+8) ) { - 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" - bitStream[bitidx++] = data[i-1]; - } else if (abs(lc-clock) < tolerance) { - // Long pulse: either "11" or "00" - bitStream[bitidx++] = data[i-1]; - bitStream[bitidx++] = data[i-1]; - } else { - // Error - warnings++; - PrintAndLog("Warning: Manchester decode error for pulse width detection."); - if (warnings > 10) { - PrintAndLog("Error: too many detection errors, aborting."); - return 0; - } + 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]; + + /* Then 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; } } } } - // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream - // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful - // to stop output at the final bitidx2 value, not bitidx - for (i = 0; i < bitidx; i += 2) { - if ((bitStream[i] == 0) && (bitStream[i+1] == 1)) { - bitStream[bit2idx++] = 1 ^ invert; - } - else if ((bitStream[i] == 1) && (bitStream[i+1] == 0)) { - bitStream[bit2idx++] = 0 ^ invert; - } - else { - // We cannot end up in this state, this means we are unsynchronized, - // move up 1 bit: + + /* + * 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..."); - if (warnings > 10) { + 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]; - // PrintAndLog(" Manchester decoded bitstream : %d bits", (bit2idx-16)); - // uint8_t mod = (bit2idx-16) % blocksize; - // uint8_t div = (bit2idx-16) / blocksize; - - // // 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) ); - // } + j = warnings = 0; - if ( bit2idx > 0 ) - memcpy(dataout, bitStream, bit2idx); + uint8_t lastbit = 0; - free(bitStream); - return bit2idx; + 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 bitstream : %d bits", len); diff --git a/client/ui.h b/client/ui.h index 2f2ed189..f599ef3c 100644 --- a/client/ui.h +++ b/client/ui.h @@ -25,6 +25,11 @@ extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault; extern int offline; extern int flushAfterWrite; //buzzy -uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout); +int manchester_decode(const int * data, const size_t len, uint8_t * dataout); +int GetT55x7Clock( const int * data, const size_t len, int high ); +int DetectFirstTransition(const int * data, const size_t len, int high, 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 high, int low, int clock, int startIndex); +int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout, int clock, int startIndex); #endif From 313ee67ea2e748e13cb9979bc8549f05fda7996c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 18 Sep 2014 12:38:31 +0200 Subject: [PATCH 04/78] Fixed: "hf mfdes info" --- armsrc/appmain.c | 22 +-- armsrc/apps.h | 28 ++-- armsrc/iso14443a.c | 9 +- armsrc/iso14443a.h | 1 - armsrc/mifarecmd.c | 3 - armsrc/mifaredesfire.c | 293 +++++++++++++++++++------------------ client/cmdhfmfdes.c | 57 ++++++-- client/cmdhfmfdes.h | 38 +++++ client/loclass/fileutils.c | 4 +- include/usb_cmd.h | 13 +- 10 files changed, 268 insertions(+), 200 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 9e4b32cd..6fd6cdcc 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -597,7 +597,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 @@ -846,10 +846,14 @@ void UsbPacketReceived(uint8_t *packet, int len) break; // case CMD_MIFARE_DES_READER: // ReaderMifareDES(c->arg[0], c->arg[1], c->d.asBytes); - break; + //break; case CMD_MIFARE_DESFIRE_INFO: MifareDesfireGetInformation(); break; + case CMD_MIFARE_DESFIRE: + MifareSendCommand(c->arg[0], c->arg[1], c->d.asBytes); + break; + #endif #ifdef WITH_ICLASS @@ -994,7 +998,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; @@ -1024,12 +1028,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 diff --git a/armsrc/apps.h b/armsrc/apps.h index 7c389e7c..38c1d689 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -209,13 +209,15 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // mifaredesfire.h +bool InitDesfireCard(); +void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); void MifareDesfireGetInformation(); void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); void MifareDES_Auth2(uint32_t arg0, uint8_t *datain); int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); -int SendDesfireCommand(enum DESFIRE_CMD desfire_cmd, uint8_t *dataout, uint8_t fromscratch); -uint8_t* CreateAPDU( uint8_t *datain, size_t len); +int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); +size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); void OnSuccess(); void OnError(); @@ -233,18 +235,16 @@ void Desfire_key_set_version (desfirekey_t key, uint8_t version); desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey); // 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); - - +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); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 0cd9053b..f87527ea 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1615,13 +1615,6 @@ int ReaderReceive(uint8_t* receivedAnswer) return ReaderReceiveOffset(receivedAnswer, 0); } -int ReaderReceiveDesfiresAuthTiming(uint8_t *receivedAnswer, uint32_t *elapsedTime) -{ - int len = ReaderReceiveOffset(receivedAnswer, 0); - *elapsedTime = (Demod.endTime*16 - DELAY_AIR2ARM_AS_READER) - (Demod.startTime*16 - DELAY_AIR2ARM_AS_READER); - return len; -} - int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr) { if (!GetIso14443aAnswerFromTag(receivedAnswer,0,160)) return FALSE; @@ -1856,7 +1849,7 @@ void ReaderIso14443a(UsbCommand *c) } if(param & ISO14A_SET_TIMEOUT) { - iso14a_timeout = c->arg[2]; + iso14a_set_timeout(c->arg[2]); } if(param & ISO14A_APDU) { diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index af650a9e..3c3993ba 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -84,7 +84,6 @@ extern void ReaderTransmitBitsPar(uint8_t *frame, int bits, uint32_t par, uint32 extern void ReaderTransmitPar(uint8_t *frame, int len, uint32_t par, uint32_t *timing); extern int ReaderReceive(uint8_t *receivedAnswer); extern int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr); -extern int ReaderReceiveDesfiresAuthTiming(uint8_t *receivedAnswer, uint32_t *elapsedTime); extern void iso14443a_setup(uint8_t fpga_minor_mode); extern int iso14_apdu(uint8_t *cmd, size_t cmd_len, void *data); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index ff853a57..7e3e9293 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -106,9 +106,6 @@ void MifareUC_Auth1(uint8_t arg0, uint8_t *datain){ if(!iso14443a_select_card(uid, NULL, &cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card, something went wrong before auth"); }; - - - if(mifare_ultra_auth1(cuid, dataoutbuf)){ if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part1: Fail."); diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 14c6aa34..ee7dc8f3 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -6,42 +6,103 @@ #define NOT_YET_AUTHENTICATED 255 #define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) +// 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]; -void MifareDesfireGetInformation(){ +bool InitDesfireCard(){ + + // Make sure it is off. +// FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +// SpinDelay(300); + + byte_t cardbuf[USB_CMD_DATA_SIZE]; + memset(cardbuf,0,sizeof(cardbuf)); + + iso14a_set_tracing(TRUE); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; + int len = iso14443a_select_card(NULL,card,NULL); + + if (!len) { + if (MF_DBGLEVEL >= 1) { + Dbprintf("Can't select card"); + } + OnError(); + return false; + } + return true; +} + +void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){ + + /* ARG0 contains flags. + 0x01 = init card. + 0x02 = + 0x03 + */ + uint8_t flags = arg0; + size_t datalen = arg1; + uint8_t resp[RECV_RES_SIZE]; + memset(resp,0,sizeof(resp)); + + if (MF_DBGLEVEL >= 4) { + Dbprintf(" flags: %02X", flags); + Dbprintf(" len : %02X", datalen); + print_result("to send: ", datain, datalen); + } + + if ( flags & 0x01 ){ + if ( !InitDesfireCard() ) + return; + } + + int len = DesfireAPDU(datain, datalen, resp); + if ( !len ) { + if (MF_DBGLEVEL >= 4) { + print_result("ERR <--: ", resp, len); + } + OnError(); + return; + } + cmd_send(CMD_ACK,1,0,0,resp,len); - uint8_t len = 0; - uint8_t resp[RECV_RES_SIZE]; - uint8_t dataout[RECV_CMD_SIZE]; - byte_t buf[RECV_RES_SIZE]; + OnSuccess(); +} + +void MifareDesfireGetInformation(){ + + int len = 0; + uint8_t resp[USB_CMD_DATA_SIZE]; + uint8_t dataout[USB_CMD_DATA_SIZE]; + byte_t cardbuf[USB_CMD_DATA_SIZE]; memset(resp,0,sizeof(resp)); memset(dataout,0, sizeof(dataout)); - memset(buf,0,sizeof(buf)); + memset(cardbuf,0,sizeof(cardbuf)); /* 1 = PCB 1 2 = cid 2 3 = desfire command 3 4-5 = crc 4 key - 5-6 crc - + 5-6 crc PCB == 0x0A because sending CID byte. - CID == 0x00 first card? - + CID == 0x00 first card? */ - uint8_t cmd1[] = {0x0a,0x00,GET_VERSION, 0x00, 0x00 }; - uint8_t cmd2[] = {0x0a,0x00,GET_KEY_VERSION, 0x00, 0x00, 0x00 }; - iso14a_clear_trace(); iso14a_set_tracing(TRUE); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); // card select - information - iso14a_card_select_t *card = (iso14a_card_select_t*)buf; + iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; byte_t isOK = iso14443a_select_card(NULL, card, NULL); if (isOK != 1) { if (MF_DBGLEVEL >= 1) { @@ -51,45 +112,42 @@ void MifareDesfireGetInformation(){ return; } - memcpy(dataout,card->uid,7); LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - // GET INFORMATION - AppendCrc14443a(cmd1, 3); - ReaderTransmit(cmd1, sizeof(cmd1), NULL); - len = ReaderReceive(resp); - if ( resp[2] != ADDITIONAL_FRAME) { + 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(); return; } - + + LED_A_OFF(); + LED_B_ON(); memcpy(dataout+7,resp+3,7); // ADDITION_FRAME 1 - ++cmd1[0]; - cmd1[2] = ADDITIONAL_FRAME; - AppendCrc14443a(cmd1, 3); - ReaderTransmit(cmd1, sizeof(cmd1), NULL); - len = ReaderReceive(resp); - - if ( resp[2] != ADDITIONAL_FRAME) { + cmd[0] = ADDITIONAL_FRAME; + len = DesfireAPDU(cmd, cmd_len, resp); + if ( !len ) { print_result("ERROR <--: ", resp, len); OnError(); return; } + + LED_B_OFF(); + LED_C_ON(); memcpy(dataout+7+7,resp+3,7); // ADDITION_FRAME 2 - --cmd1[0]; - AppendCrc14443a(cmd1, 3); - ReaderTransmit(cmd1, sizeof(cmd1), NULL); - len = ReaderReceive(resp); - if ( resp[2] != OPERATION_OK) { + len = DesfireAPDU(cmd, cmd_len, resp); + if ( !len ) { print_result("ERROR <--: ", resp, len); OnError(); return; @@ -97,34 +155,10 @@ void MifareDesfireGetInformation(){ memcpy(dataout+7+7+7,resp+3,14); - // GET MASTER KEYSETTINGS - cmd1[2] = GET_KEY_SETTINGS; - AppendCrc14443a(cmd1, 3); - ReaderTransmit(cmd1, sizeof(cmd1), NULL); - len = ReaderReceive(resp); - if (len){ - memcpy(dataout+7+7+7+14,resp+3,2); - } - - - // GET MASTER KEY VERSION - AppendCrc14443a(cmd2, 4); - ReaderTransmit(cmd2, sizeof(cmd2), NULL); - len = ReaderReceive(resp); - if (len){ - memcpy(dataout+7+7+7+14+2,resp+3,1); - } - - // GET FREE MEMORY - cmd1[2] = GET_FREE_MEMORY; - AppendCrc14443a(cmd1, 3); - ReaderTransmit(cmd1, sizeof(cmd1), NULL); - len = ReaderReceive(resp); - if (len){ - memcpy(dataout+7+7+7+14+2+1,resp+3,3); - } - cmd_send(CMD_ACK,1,0,0,dataout,sizeof(dataout)); + + // reset the pcb_blocknum, + pcb_blocknum = 0; OnSuccess(); } @@ -309,51 +343,60 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain OnSuccess(resp); } +// 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){ + + uint32_t status = 0; + size_t wrappedLen = 0; + uint8_t wCmd[USB_CMD_DATA_SIZE]; -// desfire_cmd = enum DESFIRE_CMD in desfire.h -// cmd = pointer to -// dataout = point to array for response data. -int SendDesfireCommand(enum DESFIRE_CMD desfire_cmd,uint8_t *dataout, uint8_t fromscratch){ - - uint8_t resp[80]; - uint8_t len; - - if ( fromscratch){ - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - // power up the field - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - // select the card - iso14443a_select_card(NULL, NULL, NULL); - } - - // 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat ISO) - uint8_t real_cmd[4]; - real_cmd[0] = 0x02; - real_cmd[1] = desfire_cmd; - AppendCrc14443a(real_cmd, 2); - ReaderTransmit(real_cmd, sizeof(real_cmd), NULL); - len = ReaderReceive(resp); - if(!len) - return -1; //DATA LINK ERROR - - if ( fromscratch){ - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + wrappedLen = CreateAPDU( cmd, cmd_len, wCmd); + + if (MF_DBGLEVEL >= 4) { + print_result("WCMD <--: ", wCmd, wrappedLen); } + ReaderTransmit( wCmd, wrappedLen, NULL); - enum DESFIRE_STATUS status = resp[1]; - //1 bytes iso, 1 byte status, in the end: 2 bytes crc - if ( status == OPERATION_OK || status == ADDITIONAL_FRAME) { - memcpy(dataout, resp+2, 2); - return len; - } - else { - Dbprintf("unexpected desfire response: %X (to %X)", status, desfire_cmd); - return -status; - } + status = ReaderReceive(dataout); + + if(!status){ + 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 (status >= 4 // PCB+CID+CRC = 4 bytes + && ((dataout[0] & 0xC0) == 0 // I-Block + || (dataout[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 + && (dataout[0] & 0x01) == pcb_blocknum) // equal block numbers + { + pcb_blocknum ^= 1; //toggle next block + } + return status; } +// 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 //FIXME: 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); @@ -512,56 +555,20 @@ void MifareDES_Auth2(uint32_t arg0, uint8_t *datain){ LEDsoff(); } -// CreateAPDU -uint8_t* CreateAPDU( uint8_t *datain, size_t len){ - - len = MIN(len, USB_CMD_DATA_SIZE); - - uint8_t tmpcmd[len]; - uint8_t *cmd = tmpcmd; - memset(cmd, 0, len); - cmd[0] = 0x0a; - cmd[1] = 0x00; - - memcpy(cmd, datain,len); - AppendCrc14443a(cmd, len+2); - return cmd; -} - -void SelectCard(){ - - uint8_t resp[RECV_RES_SIZE]; - byte_t buf[RECV_RES_SIZE]; - - memset(resp,0,sizeof(resp)); - memset(buf,0,sizeof(buf)); - - iso14a_clear_trace(); - iso14a_set_tracing(TRUE); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - // card select - information - iso14a_card_select_t *card = (iso14a_card_select_t*)buf; - byte_t isOK = iso14443a_select_card(NULL, card, NULL); - if (isOK != 1) { - if (MF_DBGLEVEL >= 1) { - Dbprintf("Can't select card"); - } - OnError(); - return; - } -} - void OnSuccess(){ - // Deselect card by sending a s-block. the crc is precalced for speed - uint8_t cmd[] = {0xc2,0xe0,0xb4}; - ReaderTransmit(cmd, sizeof(cmd), NULL); + // transmit a DESELECT COMMAND for Desfire. + ReaderTransmit(deselect_cmd, 3 , NULL); + // reset the pcb_blocknum, + pcb_blocknum = 0; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } void OnError(){ cmd_send(CMD_ACK,0,0,0,0,0); + ReaderTransmit(deselect_cmd, 3 , NULL); + // reset the pcb_blocknum, + pcb_blocknum = 0; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index 93a972f4..5df89d5a 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -134,17 +134,18 @@ int CmdHF14ADesRb(const char *Cmd) int CmdHF14ADesInfo(const char *Cmd){ - UsbCommand c = {CMD_MIFARE_DESFIRE_INFO, { 0x00 }}; - + UsbCommand c = {CMD_MIFARE_DESFIRE_INFO}; SendCommand(&c); UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { + if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { PrintAndLog("Command execute timeout"); return 0; + } + uint8_t isOK = resp.arg[0] & 0xff; + if ( !isOK ){ + PrintAndLog("Command unsuccessfull"); + return 0; } PrintAndLog("---Desfire Information---------------------------------------"); @@ -170,34 +171,59 @@ int CmdHF14ADesInfo(const char *Cmd){ PrintAndLog(" Protocol : %s", GetProtocolStr(resp.d.asBytes[20])); PrintAndLog("-------------------------------------------------------------"); + + UsbCommand c1 = {CMD_MIFARE_DESFIRE, { 0x01, 0x01 }}; + c1.d.asBytes[0] = GET_KEY_SETTINGS; + SendCommand(&c1); + if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + return 0; + } + PrintAndLog(" Master Key settings"); - if ( resp.d.asBytes[35] & (1 << 3 ) ) + if ( resp.d.asBytes[3] & (1 << 3 ) ) PrintAndLog(" 0x08 Configuration changeable;"); else PrintAndLog(" 0x08 Configuration NOT changeable;"); - if ( resp.d.asBytes[35] & (1 << 2 ) ) + if ( resp.d.asBytes[3] & (1 << 2 ) ) PrintAndLog(" 0x04 PICC Master Key not required for create / delete;"); else PrintAndLog(" 0x04 PICC Master Key required for create / delete;"); - if ( resp.d.asBytes[35] & (1 << 1 ) ) + if ( resp.d.asBytes[3] & (1 << 1 ) ) PrintAndLog(" 0x02 Free directory list access without PICC Master Key;"); else PrintAndLog(" 0x02 Directory list access with PICC Master Key;"); - if ( resp.d.asBytes[35] & (1 << 0 ) ) + if ( resp.d.asBytes[3] & (1 << 0 ) ) PrintAndLog(" 0x01 Allow changing the Master Key;"); else PrintAndLog(" 0x01 Master Key is not changeable anymore;"); - PrintAndLog(""); - PrintAndLog(" Max number of keys : %d", resp.d.asBytes[36]); - PrintAndLog(" Master key Version : %d (0x%02x)", resp.d.asBytes[37], resp.d.asBytes[37]); + // init len + UsbCommand c2 = {CMD_MIFARE_DESFIRE, { 0x01, 0x02 }}; + c2.d.asBytes[0] = GET_KEY_VERSION; + c2.d.asBytes[1] = 0x00; + SendCommand(&c2); + if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + return 0; + } + + PrintAndLog(""); + PrintAndLog(" Max number of keys : %d", resp.d.asBytes[2]); + PrintAndLog(" Master key Version : %d (0x%02x)", resp.d.asBytes[3], resp.d.asBytes[3]); PrintAndLog("-------------------------------------------------------------"); + + UsbCommand c3 = {CMD_MIFARE_DESFIRE, { 0x01, 0x01 }}; + c3.d.asBytes[0] = GET_FREE_MEMORY; + SendCommand(&c3); + if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + return 0; + } + uint8_t tmp[3]; - memcpy(tmp, resp.d.asBytes+38,3); + memcpy(tmp, resp.d.asBytes+3,3); PrintAndLog(" Free memory on card : %d bytes", le24toh( tmp )); PrintAndLog("-------------------------------------------------------------"); @@ -226,7 +252,6 @@ int CmdHF14ADesInfo(const char *Cmd){ AES 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte12-byte15) + RndB(byte12-byte15) */ - PrintAndLog(" RX :%s",sprint_hex(resp.d.asBytes, 40)); return 1; } @@ -434,3 +459,5 @@ int CmdHelp(const char *Cmd) CmdsHelp(CommandTable); return 0; } + + diff --git a/client/cmdhfmfdes.h b/client/cmdhfmfdes.h index 5a4997e5..12cb8e86 100644 --- a/client/cmdhfmfdes.h +++ b/client/cmdhfmfdes.h @@ -18,3 +18,41 @@ int CmdHF14ADesNonces(const char *Cmd); char * GetCardSizeStr( uint8_t fsize ); char * GetVendorStr( uint8_t id); char * GetProtocolStr(uint8_t id); + + + +#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_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 \ No newline at end of file diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index 08b81ec0..08e1c1a7 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -11,8 +11,8 @@ * @return */ int fileExists(const char *filename) { - struct _stat st; - int result = stat(filename, &st); + struct _stat fileStat; + int result = _stat(filename, &fileStat); return result == 0; } diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 23555ab4..36fcf248 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -144,12 +144,15 @@ typedef struct { #define CMD_MIFARE_NESTED 0x0612 #define CMD_MIFARE_READBL 0x0620 -#define CMD_MIFAREU_READBL 0x0720 +#define CMD_MIFAREU_READBL 0x0720 + #define CMD_MIFARE_READSC 0x0621 -#define CMD_MIFAREU_READCARD 0x0721 +#define CMD_MIFAREU_READCARD 0x0721 + #define CMD_MIFARE_WRITEBL 0x0622 -#define CMD_MIFAREU_WRITEBL_COMPAT 0x0722 -#define CMD_MIFAREU_WRITEBL 0x0723 +#define CMD_MIFAREU_WRITEBL_COMPAT 0x0722 + +#define CMD_MIFAREU_WRITEBL 0x0723 #define CMD_MIFARE_CHKKEYS 0x0623 #define CMD_MIFARE_SNIFFER 0x0630 @@ -158,7 +161,6 @@ typedef struct { #define CMD_MIFAREUC_AUTH2 0x0725 #define CMD_MIFAREUC_READCARD 0x0726 - // mifare desfire #define CMD_MIFARE_DESFIRE_READBL 0x0728 #define CMD_MIFARE_DESFIRE_WRITEBL 0x0729 @@ -166,6 +168,7 @@ typedef struct { #define CMD_MIFARE_DESFIRE_AUTH2 0x072b #define CMD_MIFARE_DES_READER 0x072c #define CMD_MIFARE_DESFIRE_INFO 0x072d +#define CMD_MIFARE_DESFIRE 0x072e #define CMD_UNKNOWN 0xFFFF From 3d93d4f940e3251b3d18dfb1aa0839aa784cd573 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 18 Sep 2014 14:15:48 +0200 Subject: [PATCH 05/78] Add: simple Application enum. Fix: Minor overflows found by Holiman. --- armsrc/mifaredesfire.c | 8 +++---- client/cmdhfmfdes.c | 54 ++++++++++++++++++++++++++++++++++++------ client/cmdhfmfdes.h | 9 ++++++- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index ee7dc8f3..6660ef75 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -71,7 +71,7 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){ OnError(); return; } - cmd_send(CMD_ACK,1,0,0,resp,len); + cmd_send(CMD_ACK,1,len,0,resp,len); OnSuccess(); @@ -279,7 +279,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain real_cmd[2] = AUTHENTICATE_AES; real_cmd[3] = keyno; - AppendCrc14443a(real_cmd, 2); + AppendCrc14443a(real_cmd, 4); ReaderTransmit(real_cmd, sizeof(real_cmd), NULL); int len = ReaderReceive(resp); @@ -321,7 +321,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain real_cmd_A[1] = ADDITIONAL_FRAME; memcpy(real_cmd_A+2, encBoth, sizeof(encBoth) ); - AppendCrc14443a(real_cmd_A, sizeof(real_cmd_A)); + AppendCrc14443a(real_cmd_A, 34); ReaderTransmit(real_cmd_A, sizeof(real_cmd_A), NULL); len = ReaderReceive(resp); @@ -514,7 +514,7 @@ int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ if (len == 11){ if (MF_DBGLEVEL >= 1) { - Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + Dbprintf("Auth2 Resp: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", buffer[0],buffer[1],buffer[2],buffer[3],buffer[4], buffer[5],buffer[6],buffer[7],buffer[8],buffer[9], buffer[10]); diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index 5df89d5a..824236be 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -144,7 +144,7 @@ int CmdHF14ADesInfo(const char *Cmd){ } uint8_t isOK = resp.arg[0] & 0xff; if ( !isOK ){ - PrintAndLog("Command unsuccessfull"); + PrintAndLog("Command unsuccessful"); return 0; } @@ -227,10 +227,9 @@ int CmdHF14ADesInfo(const char *Cmd){ PrintAndLog(" Free memory on card : %d bytes", le24toh( tmp )); PrintAndLog("-------------------------------------------------------------"); + /* - Card Master key (CMK) 0x00 on AID = 00 00 00 (card level) - 0x1 - + Card Master key (CMK) 0x00 on AID = 00 00 00 (card level) 0x1 Application Master Key (AMK) 0x00 on AID != 00 00 00 Application keys (APK) = 0x01-0x0D Application free = 0x0E @@ -242,9 +241,6 @@ int CmdHF14ADesInfo(const char *Cmd){ keys 8,9,10,11 W keys 12,13,14,15 R - KEY Versioning. - Se GetKeyVersion (samma nyckel kan ha olika versionen?) - Session key: 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte4-byte7) + RndB(byte4-byte7) 8 : RndA(byte0-byte3) + RndB(byte0-byte3) @@ -301,6 +297,50 @@ char * GetProtocolStr(uint8_t id){ } int CmdHF14ADesEnumApplications(const char *Cmd){ + + UsbCommand c = {CMD_MIFARE_DESFIRE, { 0x01, 0x01 }}; + c.d.asBytes[0] = GET_APPLICATION_IDS; + SendCommand(&c); + UsbCommand resp; + + if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + return 0; + } + + uint8_t isOK = resp.arg[0] & 0xff; + if ( !isOK ){ + PrintAndLog("Command unsuccessful"); + return 0; + } + + PrintAndLog("---Desfire Enum Applications --------------------------------"); + PrintAndLog("-------------------------------------------------------------"); + + //UsbCommand respFiles; + + uint8_t num = 0; + int max = resp.arg[1] -3 -2; + + for(int i=3; i<=max; i+=3){ + PrintAndLog(" Aid %d : %s ",num ,sprint_hex(resp.d.asBytes+i,3)); + num++; + + // UsbCommand cFiles = {CMD_MIFARE_DESFIRE, { 0x01, 0x04 }}; + // cFiles.d.asBytes[0] = GET_FILE_IDS; + // cFiles.d.asBytes[1] = resp.d.asBytes+i; + // cFiles.d.asBytes[2] = resp.d.asBytes+i+1; + // cFiles.d.asBytes[3] = resp.d.asBytes+i+2; + // SendCommand(&cFiles); + + // if ( !WaitForResponseTimeout(CMD_ACK,&respFiles,1500) ) { + // PrintAndLog(" No files found"); + // break; + // } + + } + PrintAndLog("-------------------------------------------------------------"); + + return 1; } diff --git a/client/cmdhfmfdes.h b/client/cmdhfmfdes.h index 12cb8e86..15bb9a23 100644 --- a/client/cmdhfmfdes.h +++ b/client/cmdhfmfdes.h @@ -55,4 +55,11 @@ char * GetProtocolStr(uint8_t id); #define GET_KEY_SETTINGS 0x45 #define CHANGE_KEY 0xc4 #define GET_KEY_VERSION 0x64 -#define AUTHENTICATION_FRAME 0xAF \ No newline at end of file +#define AUTHENTICATION_FRAME 0xAF + + +#define MAX_APPLICATION_COUNT 28 +#define MAX_FILE_COUNT 16 +#define MAX_FRAME_SIZE 60 +#define NOT_YET_AUTHENTICATED 255 +#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) \ No newline at end of file From f6c18637ca504d2eea0bc3accaabddd132d749fb Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Oct 2014 19:42:50 +0200 Subject: [PATCH 06/78] chg: LF t55xx trace new: LF t55xx info --- armsrc/Makefile | 13 +- armsrc/appmain.c | 4 +- armsrc/apps.h | 44 ++--- armsrc/crapto1.c | 2 +- armsrc/desfire_crypto.h | 1 - armsrc/desfire_key.c | 85 +++++---- armsrc/desfire_key.h | 23 ++- armsrc/iso14443a.c | 10 +- armsrc/lfops.c | 232 +++++++++++------------- armsrc/mifaredesfire.c | 376 +++++++++------------------------------ armsrc/mifaredesfire.h | 2 +- armsrc/util.c | 4 +- client/.history | 8 + client/cmddata.c | 16 +- client/cmdhfmfdes.c | 385 ++++++++++++++++++++++++++++------------ client/cmdhfmfdes.h | 18 +- client/cmdlfem4x.c | 34 +--- client/cmdlft55xx.c | 282 ++++++++++++++++++++++++----- client/cmdlft55xx.h | 6 +- client/ui.c | 168 +++++++++++------- client/ui.h | 4 +- common/Makefile.common | 2 +- common/desfire.h | 10 +- cp2tau | 4 + iceman.txt | 0 25 files changed, 929 insertions(+), 804 deletions(-) create mode 100644 client/.history create mode 100644 cp2tau create mode 100644 iceman.txt diff --git a/armsrc/Makefile b/armsrc/Makefile index ea19491a..d37e935a 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -16,10 +16,10 @@ APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ #SRC_LCD = fonts.c LCD.c SRC_LF = lfops.c hitag2.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_CRC = iso14443crc.c crc.c crc16.c crc32.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 desfire_key.c desfire_crypto.c +SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c THUMBSRC = start.c \ $(SRC_LCD) \ @@ -41,9 +41,8 @@ ARMSRC = fpgaloader.c \ $(SRC_CRC) \ legic_prng.c \ iclass.c \ - mifaredesfire.c \ - desfire_crypto.c \ - desfire_key.c + mifaredesfire.c + # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS += -I. diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 6fd6cdcc..afed56b7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -18,9 +18,9 @@ #include "util.h" #include "printf.h" #include "string.h" - #include + #include "legicrf.h" #include "../include/hitag2.h" @@ -842,7 +842,7 @@ void UsbPacketReceived(uint8_t *packet, int len) 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); + //MifareDES_Auth2(c->arg[0],c->d.asBytes); break; // case CMD_MIFARE_DES_READER: // ReaderMifareDES(c->arg[0], c->arg[1], c->d.asBytes); diff --git a/armsrc/apps.h b/armsrc/apps.h index 90313aec..6f96875b 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -14,27 +14,21 @@ #include #include -#include - #include +#include #include #include - #include "../include/common.h" #include "../include/hitag2.h" #include "../include/mifare.h" //#include //#include - //#include "des.h" //#include "aes.h" #include "../common/desfire.h" #include "../common/crc32.h" -//#include "desfire_crypto.h" -//#include "desfire_key.h" - // The large multi-purpose buffer, typically used to hold A/D samples, // maybe processed in some way. @@ -156,6 +150,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); @@ -209,30 +204,17 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // mifaredesfire.h -bool InitDesfireCard(); -void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); -void MifareDesfireGetInformation(); -void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); -void MifareDES_Auth2(uint32_t arg0, uint8_t *datain); -int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); -void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); -int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); -size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); -void OnSuccess(); -void OnError(); +bool InitDesfireCard(); +void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); +void MifareDesfireGetInformation(); +void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); +void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); +int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); +size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); +void OnSuccess(); +void OnError(); + -// desfire_key.h -desfirekey_t Desfire_des_key_new (const uint8_t value[8]); -desfirekey_t Desfire_3des_key_new (const uint8_t value[16]); -desfirekey_t Desfire_des_key_new_with_version (const uint8_t value[8]); -desfirekey_t Desfire_3des_key_new_with_version (const uint8_t value[16]); -desfirekey_t Desfire_3k3des_key_new (const uint8_t value[24]); -desfirekey_t Desfire_3k3des_key_new_with_version (const uint8_t value[24]); -desfirekey_t Desfire_aes_key_new (const uint8_t value[16]); -desfirekey_t Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version); -uint8_t Desfire_key_get_version (desfirekey_t key); -void Desfire_key_set_version (desfirekey_t key, uint8_t version); -desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey); // desfire_crypto.h void *mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, off_t offset, int communication_settings); @@ -247,8 +229,6 @@ 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 void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); diff --git a/armsrc/crapto1.c b/armsrc/crapto1.c index 9d491d12..17b78e32 100644 --- a/armsrc/crapto1.c +++ b/armsrc/crapto1.c @@ -454,7 +454,7 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) odd = lfsr_prefix_ks(ks, 1); even = lfsr_prefix_ks(ks, 0); - + s = statelist = malloc((sizeof *statelist) << 20); if(!s || !odd || !even) { free(statelist); diff --git a/armsrc/desfire_crypto.h b/armsrc/desfire_crypto.h index d580ccc8..698f11e3 100644 --- a/armsrc/desfire_crypto.h +++ b/armsrc/desfire_crypto.h @@ -11,5 +11,4 @@ #include "des.h" //#include "aes.h" - #endif diff --git a/armsrc/desfire_key.c b/armsrc/desfire_key.c index b829013e..b3aa14e9 100644 --- a/armsrc/desfire_key.c +++ b/armsrc/desfire_key.c @@ -16,8 +16,8 @@ * * $Id$ */ - - #include "desfire_key.h" +#include +#include "desfire_key.h" static inline void update_key_schedules (desfirekey_t key); @@ -29,67 +29,68 @@ static inline void update_key_schedules (desfirekey_t key) { // } } -desfirekey_t Desfire_des_key_new (const uint8_t value[8]) { +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; - return Desfire_des_key_new_with_version (data); + Desfire_des_key_new_with_version (data, key); } -desfirekey_t Desfire_des_key_new_with_version (const uint8_t value[8]) { - desfirekey_t key = NULL; - key->type = T_DES; - memcpy (key->data, value, 8); - memcpy (key->data+8, value, 8); - update_key_schedules (key); - return 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); + } } -desfirekey_t Desfire_3des_key_new (const uint8_t value[16]) { +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; - return Desfire_3des_key_new_with_version (data); + Desfire_3des_key_new_with_version (data, key); } -desfirekey_t Desfire_3des_key_new_with_version (const uint8_t value[16]) { - desfirekey_t key = NULL; - key->type = T_3DES; - memcpy (key->data, value, 16); - update_key_schedules (key); - return 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); + } } -desfirekey_t Desfire_3k3des_key_new (const uint8_t value[24]) { +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; - return Desfire_3k3des_key_new_with_version (data); + Desfire_3k3des_key_new_with_version (data, key); } -desfirekey_t Desfire_3k3des_key_new_with_version (const uint8_t value[24]) { - desfirekey_t key = NULL; - key->type = T_3K3DES; - memcpy (key->data, value, 24); - update_key_schedules (key); - return 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); + } } -desfirekey_t Desfire_aes_key_new (const uint8_t value[16]) { - return Desfire_aes_key_new_with_version (value, 0); + void Desfire_aes_key_new (const uint8_t value[16], desfirekey_t key) { + Desfire_aes_key_new_with_version (value, 0, key); } -desfirekey_t Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version) { - desfirekey_t key = NULL; - memcpy (key->data, value, 16); - key->type = T_AES; - key->aes_version = version; - return 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) { @@ -98,7 +99,6 @@ uint8_t Desfire_key_get_version (desfirekey_t key) { for (int n = 0; n < 8; n++) { version |= ((key->data[n] & 1) << (7 - n)); } - return version; } @@ -118,9 +118,7 @@ void Desfire_key_set_version (desfirekey_t key, uint8_t version) } } -desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey) { - - desfirekey_t key = NULL; +void Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key) { uint8_t buffer[24]; @@ -128,14 +126,14 @@ desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[] case T_DES: memcpy (buffer, rnda, 4); memcpy (buffer+4, rndb, 4); - key = Desfire_des_key_new_with_version (buffer); + 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); - key = Desfire_3des_key_new_with_version (buffer); + Desfire_3des_key_new_with_version (buffer, key); break; case T_3K3DES: memcpy (buffer, rnda, 4); @@ -144,15 +142,14 @@ desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[] memcpy (buffer+12, rndb+6, 4); memcpy (buffer+16, rnda+12, 4); memcpy (buffer+20, rndb+12, 4); - key = Desfire_3k3des_key_new (buffer); + 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); - key = Desfire_aes_key_new (buffer); + Desfire_aes_key_new (buffer, key); break; } - return key; } \ No newline at end of file diff --git a/armsrc/desfire_key.h b/armsrc/desfire_key.h index ae1249b4..0d99903e 100644 --- a/armsrc/desfire_key.h +++ b/armsrc/desfire_key.h @@ -1,10 +1,17 @@ -#ifndef __DESFIRE_KEY_H -#define __DESFIRE_KEY_H - -#include -#include -#include - +#ifndef __DESFIRE_KEY_INCLUDED +#define __DESFIRE_KEY_INCLUDED #include "iso14443a.h" -#include "../common/desfire.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 diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index f87527ea..3b17bd4b 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1205,13 +1205,6 @@ static void TransmitFor14443a(const uint8_t *cmd, int len, uint32_t *timing) // clear TXRDY AT91C_BASE_SSC->SSC_THR = SEC_Y; - // for(uint16_t c = 0; c < 10;) { // standard delay for each transfer (allow tag to be ready after last transmission) - // if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - // AT91C_BASE_SSC->SSC_THR = SEC_Y; - // c++; - // } - // } - uint16_t c = 0; for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { @@ -1223,8 +1216,7 @@ static void TransmitFor14443a(const uint8_t *cmd, int len, uint32_t *timing) } } - NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); - + NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); } diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 11fc8c50..0c0f0275 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -31,8 +31,10 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) // Connect the A/D to the peak-detected low-frequency path. SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); + SpinDelay(150); + // Now set up the SSC to get the ADC samples that are now streaming at us. FpgaSetupSsc(); } @@ -1090,14 +1092,14 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) */ /* T55x7 configuration register definitions */ -#define T55x7_POR_DELAY 0x00000001 -#define T55x7_ST_TERMINATOR 0x00000008 -#define T55x7_PWD 0x00000010 +#define T55x7_POR_DELAY 0x00000001 +#define T55x7_ST_TERMINATOR 0x00000008 +#define T55x7_PWD 0x00000010 #define T55x7_MAXBLOCK_SHIFT 5 -#define T55x7_AOR 0x00000200 -#define T55x7_PSKCF_RF_2 0 -#define T55x7_PSKCF_RF_4 0x00000400 -#define T55x7_PSKCF_RF_8 0x00000800 +#define T55x7_AOR 0x00000200 +#define T55x7_PSKCF_RF_2 0 +#define T55x7_PSKCF_RF_4 0x00000400 +#define T55x7_PSKCF_RF_8 0x00000800 #define T55x7_MODULATION_DIRECT 0 #define T55x7_MODULATION_PSK1 0x00001000 #define T55x7_MODULATION_PSK2 0x00002000 @@ -1108,17 +1110,17 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define T55x7_MODULATION_FSK2a 0x00007000 #define T55x7_MODULATION_MANCHESTER 0x00008000 #define T55x7_MODULATION_BIPHASE 0x00010000 -#define T55x7_BITRATE_RF_8 0 -#define T55x7_BITRATE_RF_16 0x00040000 -#define T55x7_BITRATE_RF_32 0x00080000 -#define T55x7_BITRATE_RF_40 0x000C0000 -#define T55x7_BITRATE_RF_50 0x00100000 -#define T55x7_BITRATE_RF_64 0x00140000 +#define T55x7_BITRATE_RF_8 0 +#define T55x7_BITRATE_RF_16 0x00040000 +#define T55x7_BITRATE_RF_32 0x00080000 +#define T55x7_BITRATE_RF_40 0x000C0000 +#define T55x7_BITRATE_RF_50 0x00100000 +#define T55x7_BITRATE_RF_64 0x00140000 #define T55x7_BITRATE_RF_100 0x00180000 #define T55x7_BITRATE_RF_128 0x001C0000 /* T5555 (Q5) configuration register definitions */ -#define T5555_ST_TERMINATOR 0x00000001 +#define T5555_ST_TERMINATOR 0x00000001 #define T5555_MAXBLOCK_SHIFT 0x00000001 #define T5555_MODULATION_MANCHESTER 0 #define T5555_MODULATION_PSK1 0x00000010 @@ -1128,34 +1130,35 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define T5555_MODULATION_FSK2 0x00000050 #define T5555_MODULATION_BIPHASE 0x00000060 #define T5555_MODULATION_DIRECT 0x00000070 -#define T5555_INVERT_OUTPUT 0x00000080 -#define T5555_PSK_RF_2 0 -#define T5555_PSK_RF_4 0x00000100 -#define T5555_PSK_RF_8 0x00000200 -#define T5555_USE_PWD 0x00000400 -#define T5555_USE_AOR 0x00000800 -#define T5555_BITRATE_SHIFT 12 -#define T5555_FAST_WRITE 0x00004000 -#define T5555_PAGE_SELECT 0x00008000 +#define T5555_INVERT_OUTPUT 0x00000080 +#define T5555_PSK_RF_2 0 +#define T5555_PSK_RF_4 0x00000100 +#define T5555_PSK_RF_8 0x00000200 +#define T5555_USE_PWD 0x00000400 +#define T5555_USE_AOR 0x00000800 +#define T5555_BITRATE_SHIFT 12 +#define T5555_FAST_WRITE 0x00004000 +#define T5555_PAGE_SELECT 0x00008000 /* * Relevant times in microsecond * To compensate antenna falling times shorten the write times * and enlarge the gap ones. */ -#define START_GAP 250 -#define WRITE_GAP 160 -#define WRITE_0 144 // 192 -#define WRITE_1 400 // 432 for T55x7; 448 for E5550 +#define START_GAP 30*8 // 10 - 50fc 250 +#define WRITE_GAP 20*8 // 8 - 30fc +#define WRITE_0 24*8 // 16 - 31fc 24fc 192 +#define WRITE_1 54*8 // 48 - 63fc 54fc 432 for T55x7; 448 for E5550 -// VALUES TAKEN FROM EM4x function: SendForward -// START_GAP = 440; //(55*8) -// WRITE_GAP = 128; //(16*8) -// WRITE_1 = 256 32*8; //32 cycles at 125Khz (8us each) 1 -// //These timings work for 4469/4269/4305 (with the 55*8 above) -// WRITE_0 = 23*8 , 9*8 SpinDelayUs(23*8); // (8us each) 0 +// 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); +#define T55xx_SAMPLES_SIZE 12000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) // Write one bit to card void T55xxWriteBit(int bit) @@ -1163,7 +1166,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); @@ -1174,15 +1177,11 @@ void T55xxWriteBit(int bit) // Write one card block in page 0, no lock void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMode) { - unsigned int i; + uint32_t i = 0; - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - - // Give it a bit of time for the resonant antenna to settle. - // And for the tag to fully power up - SpinDelay(150); + // Set up FPGA, 125kHz + // Wait for config.. (192+8190xPOW)x8 == 67ms + LFSetupFPGAForADC(0, true); // Now start writting FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -1191,11 +1190,11 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod // Opcode T55xxWriteBit(1); T55xxWriteBit(0); //Page 0 - if (PwdMode == 1){ - // Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } + if (PwdMode == 1){ + // Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(Pwd & i); + } // Lock bit T55xxWriteBit(0); @@ -1219,28 +1218,16 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) { uint8_t *dest = mifare_get_bigbufptr(); - uint16_t bufferlength = 16000; + uint16_t bufferlength = T55xx_SAMPLES_SIZE; uint32_t i = 0; // Clear destination buffer before sending the command 0x80 = average. memset(dest, 0x80, bufferlength); - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - // 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. - FpgaSetupSsc(); - - LED_D_ON(); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - - // Give it a bit of time for the resonant antenna to settle. - // And for the tag to fully power up - SpinDelay(150); - - // Now start writting + + // Set up FPGA, 125kHz + // Wait for config.. (192+8190xPOW)x8 == 67ms + LFSetupFPGAForADC(0, true); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelayUs(START_GAP); @@ -1258,9 +1245,8 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) for (i = 0x04; i != 0; i >>= 1) T55xxWriteBit(Block & i); - // Turn field on to read the response - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + // Turn field on to read the response + TurnReadLFOn(); // Now do the acquisition i = 0; @@ -1271,43 +1257,28 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - LED_D_OFF(); ++i; + LED_D_OFF(); if (i > bufferlength) break; } } cmd_send(CMD_ACK,0,0,0,0,0); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); } // Read card traceability data (page 1) void T55xxReadTrace(void){ uint8_t *dest = mifare_get_bigbufptr(); - uint16_t bufferlength = 16000; + uint16_t bufferlength = T55xx_SAMPLES_SIZE; int i=0; // Clear destination buffer before sending the command 0x80 = average memset(dest, 0x80, bufferlength); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - // 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. - FpgaSetupSsc(); + LFSetupFPGAForADC(0, true); - LED_D_ON(); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - - // Give it a bit of time for the resonant antenna to settle. - // And for the tag to fully power up - SpinDelay(150); - - // Now start writting FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelayUs(START_GAP); @@ -1315,12 +1286,10 @@ void T55xxReadTrace(void){ T55xxWriteBit(1); T55xxWriteBit(1); //Page 1 - // Turn field on to read the response - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + // Turn field on to read the response + TurnReadLFOn(); // Now do the acquisition - i = 0; for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { AT91C_BASE_SSC->SSC_THR = 0x43; @@ -1328,18 +1297,26 @@ void T55xxReadTrace(void){ } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + ++i; LED_D_OFF(); - ++i; + if (i >= bufferlength) break; } } cmd_send(CMD_ACK,0,0,0,0,0); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); } +void TurnReadLFOn(){ + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + // Give it a bit of time for the resonant antenna to settle. + //SpinDelay(30); + SpinDelayUs(8*150); +} + /*-------------- Cloning routines -----------*/ // Copy HID id to card and setup block 0 config void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) @@ -1453,7 +1430,7 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) } // Config for HID (RF/50, FSK2a, Maxblock=3 for short/6 for long) - T55xxWriteBlock(T55x7_BITRATE_RF_50 | + T55xxWriteBlock(T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2a | last_block << T55x7_MAXBLOCK_SHIFT, 0,0,0); @@ -1596,7 +1573,6 @@ void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo) // Clone Indala 64-bit tag by UID to T55x7 void CopyIndala64toT55x7(int hi, int lo) { - //Program the 2 data blocks for supplied 64bit UID // and the block 0 for Indala64 format T55xxWriteBlock(hi,1,0,0); @@ -1607,15 +1583,13 @@ void CopyIndala64toT55x7(int hi, int lo) 2 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0); //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data) -// T5567WriteBlock(0x603E1042,0); + // T5567WriteBlock(0x603E1042,0); DbpString("DONE!"); - } void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int uid6, int uid7) { - //Program the 7 data blocks for supplied 224bit UID // and the block 0 for Indala224 format T55xxWriteBlock(uid1,1,0,0); @@ -1631,10 +1605,9 @@ void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int 7 << T55x7_MAXBLOCK_SHIFT, 0,0,0); //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data) -// T5567WriteBlock(0x603E10E2,0); + // T5567WriteBlock(0x603E10E2,0); DbpString("DONE!"); - } @@ -2059,44 +2032,47 @@ void EM4xLogin(uint32_t Password) { void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { uint8_t *dest = mifare_get_bigbufptr(); - uint16_t bufferlength = 16000; + uint16_t bufferlength = 12000; uint32_t i = 0; // Clear destination buffer before sending the command 0x80 = average. memset(dest, 0x80, bufferlength); - uint8_t fwd_bit_count; + uint8_t fwd_bit_count; - //If password mode do login - if (PwdMode == 1) EM4xLogin(Pwd); + //If password mode do login + if (PwdMode == 1) EM4xLogin(Pwd); - forward_ptr = forwardLink_data; - fwd_bit_count = Prepare_Cmd( FWD_CMD_READ ); - fwd_bit_count += Prepare_Addr( Address ); + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_READ ); + fwd_bit_count += Prepare_Addr( Address ); - // 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. - FpgaSetupSsc(); + // 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. + FpgaSetupSsc(); - SendForward(fwd_bit_count); + SendForward(fwd_bit_count); - // Now do the acquisition - i = 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) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - ++i; - if (i >= bufferlength) break; - } - } + // // Turn field on to read the response + // TurnReadLFOn(); + + // Now do the acquisition + i = 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) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + ++i; + if (i >= bufferlength) break; + } + } cmd_send(CMD_ACK,0,0,0,0,0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_D_OFF(); } void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 60f5ec03..60c941eb 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -45,7 +45,7 @@ enum { NONE = 0x00, INIT = 0x01, DISCONNECT = 0x02, - FOO = 0x04, + CLEARTRACE = 0x04, BAR = 0x08, } CmdOptions ; @@ -53,7 +53,7 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){ /* ARG0 contains flags. 0x01 = init card. - 0x02 = No Disconnect + 0x02 = Disconnect 0x03 */ uint8_t flags = arg0; @@ -67,17 +67,21 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){ print_result(" RX : ", datain, datalen); } + if ( flags & CLEARTRACE ){ + iso14a_clear_trace(); + } + if ( flags & INIT ){ if ( !InitDesfireCard() ) return; } int len = DesfireAPDU(datain, datalen, resp); - print_result(" <--: ", resp, len); - if ( !len ) { if (MF_DBGLEVEL >= 4) { print_result("ERR <--: ", resp, len); } + + if ( !len ) { OnError(); return; } @@ -85,8 +89,9 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){ // reset the pcb_blocknum, pcb_blocknum = 0; - if ( flags & DISCONNECT ) + if ( flags & DISCONNECT ){ OnSuccess(); + } cmd_send(CMD_ACK,1,len,0,resp,len); } @@ -178,87 +183,28 @@ void MifareDesfireGetInformation(){ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain){ - uint8_t null_key_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - //uint8_t new_key_data[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; - int res = 0; - - desfirekey_t default_key = Desfire_des_key_new_with_version (null_key_data); - - // res = Desfire_select_application (tags[i], aid); - if (res < 0) { - print_result("default key: ", default_key->data, 24 ); - return; - } - - return; - // pcb cid cmd key crc1 cr2 - //uint8_t cmd2[] = {0x02,0x00,GET_KEY_VERSION, 0x00, 0x00, 0x00 }; + 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* bigbuffer = mifare_get_bigbufptr(); - byte_t isOK = 1; - uint8_t resp[256]; - uint8_t key[24]; - uint8_t IV[16]; + uint8_t resp[256] = {0x00}; + uint8_t IV[16] = {0x00}; + + size_t datalen = datain[0]; - // första byten håller keylength. - uint8_t keylen = datain[0]; - memcpy(key, datain+1, keylen); - - if (MF_DBGLEVEL >= 1) { - - Dbprintf("MODE: %d", mode); - Dbprintf("ALGO: %d", algo); - Dbprintf("KEYNO: %d", keyno); - Dbprintf("KEYLEN: %d", keylen); - - print_result("KEY", key, keylen); - } - - // card select - information - byte_t buf[USB_CMD_DATA_SIZE]; - iso14a_card_select_t *card = (iso14a_card_select_t*)buf; - - // test of DES on ARM side. - /* - if ( mode == 1){ - uint8_t IV[8]; - uint8_t plain[16]; - uint8_t encData[16]; + 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}; - uint8_t tmpData[8]; - uint8_t tmpPlain[8]; - - memset(IV, 0, 8); - memset(tmpData, 0 ,8); - memset(tmpPlain,0 ,8); - memcpy(key, datain, 8); - memcpy(plain, datain+30, 16); - - for(uint8_t i=0; i< sizeof(plain); i=i+8 ){ - - memcpy(tmpPlain, plain+i, 8); - des_enc( &tmpData, &tmpPlain, &key); - memcpy(encData+i, tmpData, 8); - } - } -*/ - - iso14a_clear_trace(); - - iso14a_set_tracing(TRUE); - - // power up the field - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - // select the card - isOK = iso14443a_select_card(resp, card, NULL); - if (isOK != 1) { - if (MF_DBGLEVEL >= 1) { - Dbprintf("CAN'T SELECT CARD, SOMETHING WENT WRONG BEFORE AUTH"); - } - OnError(); - return; - } + InitDesfireCard(); LED_A_ON(); LED_B_OFF(); @@ -279,82 +225,78 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain //SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp); break; case 3:{ + + //defaultkey + uint8_t keybytes[16]; + if (datain[1] == 0xff){ + memcpy(keybytes,PICC_MASTER_KEY16,16); + } else{ + memcpy(keybytes, datain+1, datalen); + } + + struct desfire_key defaultkey = {0}; + desfirekey_t key = &defaultkey; + Desfire_aes_key_new( keybytes, key); + AesCtx ctx; - if ( AesCtxIni(&ctx, IV, key, KEY128, CBC) < 0 ){ - if (MF_DBGLEVEL >= 1) { + if ( AesCtxIni(&ctx, IV, key->data, KEY128, CBC) < 0 ){ + if( MF_DBGLEVEL >= 4) { Dbprintf("AES context failed to init"); } OnError(); return; } - uint8_t real_cmd[6]; - real_cmd[0] = 0x90; - real_cmd[1] = 0x02; - real_cmd[2] = AUTHENTICATE_AES; - real_cmd[3] = keyno; - AppendCrc14443a(real_cmd, 4); - ReaderTransmit(real_cmd, sizeof(real_cmd), NULL); - - int len = ReaderReceive(resp); - if(!len) { - OnError(); - return; - } - - print_result("RX:", resp, len); - - enum DESFIRE_STATUS status = resp[1]; - if ( status != ADDITIONAL_FRAME) { + cmd[0] = AUTHENTICATE_AES; + cmd[1] = 0x00; //keynumber + len = DesfireAPDU(cmd, 2, resp); + if ( !len ) { + if (MF_DBGLEVEL >= 1) { + DbpString("Authentication failed. Card timeout."); + } OnError(); return; } - // tags enc nonce - uint8_t encRndB[16]; - uint8_t decRndB[16]; - uint8_t nonce[16]; - uint8_t both[32]; - uint8_t encBoth[32]; - - memset(nonce, 0, 16); - memcpy( encRndB, resp+2, 16); - + 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 ); - - uint8_t real_cmd_A[36]; - real_cmd_A[0] = 0x03; - real_cmd_A[1] = ADDITIONAL_FRAME; - memcpy(real_cmd_A+2, encBoth, sizeof(encBoth) ); - AppendCrc14443a(real_cmd_A, 34); - ReaderTransmit(real_cmd_A, sizeof(real_cmd_A), NULL); - - len = ReaderReceive(resp); - - print_result("Auth1a ", resp, 36); + cmd[0] = ADDITIONAL_FRAME; + memcpy(cmd+1, encBoth, 32 ); - status = resp[1]; - if ( status != OPERATION_OK) { - Dbprintf("Cmd Error: %02x Len: %d", status,len); + len = DesfireAPDU(cmd, 33, resp); // 1 + 32 == 33 + if ( !len ) { + if (MF_DBGLEVEL >= 1) { + DbpString("Authentication failed. Card timeout."); + } + OnError(); + 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(); return; } - - break; - } + break; + } } - OnSuccess(resp); + OnSuccess(); + cmd_send(CMD_ACK,1,len,0,resp,len); } // 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat ISO) @@ -365,7 +307,7 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ uint32_t status = 0; size_t wrappedLen = 0; - uint8_t wCmd[USB_CMD_DATA_SIZE]; + uint8_t wCmd[USB_CMD_DATA_SIZE] = {0}; wrappedLen = CreateAPDU( cmd, cmd_len, wCmd); @@ -376,7 +318,10 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ status = ReaderReceive(dataout); - if(!status){ + if( status == 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 @@ -411,163 +356,10 @@ size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout){ 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); - - - /* Version - - //uint8_t versionCmd1[] = {0x02, 0x60}; - //uint8_t versionCmd2[] = {0x03, 0xaf}; - //uint8_t versionCmd3[] = {0x02, 0xaf}; - - // AUTH 1 - CMD: 0x02, 0x0A, 0x00 = Auth - // 0x02 = status byte för simpla svar?!? - // 0x0a = krypto typ - // 0x00 = key nr - //uint8_t initAuthCmdDES[] = {0x02, 0x0a, 0x00}; // DES - //uint8_t initAuthCmd3DES[] = {0x02, 0x1a, 0x00}; // 3DES - //uint8_t initAuthCmdAES[] = {0x02, 0xaa, 0x00}; // AES - // auth 1 - answer command - // 0x03 = status byte för komplexa typer? - // 0xaf = additional frame - // LEN = 1+1+32+2 = 36 - //uint8_t answerAuthCmd[34] = {0x03, 0xaf}; - - // Lägg till CRC - //AppendCrc14443a(versionCmd1,sizeof(versionCmd1)); -*/ - - // Sending commands - /*ReaderTransmit(versionCmd1,sizeof(versionCmd1)+2, NULL); - len = ReaderReceive(buffer); - print_result("Get Version 3", buffer, 9); - */ - - // for( int i = 0; i < 8; i++){ - // // Auth 1 - Request authentication - // ReaderTransmit(initAuthCmdAES,sizeof(initAuthCmdAES)+2, NULL); - // //len = ReaderReceive(buffer); - - // // 0xAE = authentication error - // if (buffer[1] == 0xae) { - // Dbprintf("Cmd Error: %02x", buffer[1]); - // OnError(); - // return; - // } - - // // tags enc nonce - // memcpy(encRndB, buffer+2, 16); - - // // dekryptera svaret från tag. - // AesDecrypt(&ctx, encRndB, decRndB, 16); - - // rol8(decRndB,16); - // memcpy(RndARndB, RndA,16); - // memcpy(RndARndB+16, decRndB ,16 ); - - // AesEncrypt(&ctx, RndARndB, encRndARndB, 32 ); - - // memcpy(answerAuthCmd+2, encRndARndB, 32); - // AppendCrc14443a(answerAuthCmd,sizeof(answerAuthCmd)); - - // ReaderTransmit(answerAuthCmd,sizeof(answerAuthCmd)+2, NULL); - - // len = ReaderReceive(buffer); - - // print_result("Auth1a ", buffer, 8); - // Dbprintf("Rx len: %02x", len); - - // if (buffer[1] == 0xCA) { - // Dbprintf("Cmd Error: %02x Len: %d", buffer[1],len); - // cmd_send(CMD_ACK,0,0,0,0,0); - // key[1] = i; - // AesCtxIni(&ctx, iv, key, KEY128, CBC); - // } - // } - - //des_dec(decRndB, encRndB, key); - - //Do crypto magic - /* - DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); - memcpy(RndARndB,RndA,8); - memcpy(RndARndB+8,RndB,8); - PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); - DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); - PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); - */ - - -int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ - - uint8_t* buffer = mifare_get_bigbufptr(); - uint8_t dcmd[19]; - - dcmd[0] = 0xAF; - memcpy(dcmd+1,key,16); - AppendCrc14443a(dcmd, 17); - - - ReaderTransmit(dcmd, sizeof(dcmd), NULL); - int len = ReaderReceive(buffer); - if(!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); - len = ReaderReceive(buffer); - } - - if(len==1) { - if (MF_DBGLEVEL >= 1) { - Dbprintf("NAK - Authentication failed."); - Dbprintf("Cmd Error: %02x", buffer[0]); - } - return 1; - } - - if (len == 11){ - if (MF_DBGLEVEL >= 1) { - Dbprintf("Auth2 Resp: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - buffer[0],buffer[1],buffer[2],buffer[3],buffer[4], - buffer[5],buffer[6],buffer[7],buffer[8],buffer[9], - buffer[10]); - } - return 0; - } - return 1; -} - -void MifareDES_Auth2(uint32_t arg0, uint8_t *datain){ - - return; - uint32_t cuid = arg0; - uint8_t key[16]; - - byte_t isOK = 0; - byte_t dataoutbuf[16]; - - memset(key, 0, 16); - memcpy(key, datain, 16); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - if(mifare_des_auth2(cuid, key, dataoutbuf)){ - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail..."); - } - isOK=1; - if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED"); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,11); - LED_B_OFF(); - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} + // 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; diff --git a/armsrc/mifaredesfire.h b/armsrc/mifaredesfire.h index fc661f22..659e0057 100644 --- a/armsrc/mifaredesfire.h +++ b/armsrc/mifaredesfire.h @@ -8,7 +8,7 @@ #include "../common/iso14443crc.h" #include "iso14443a.h" -#include "crapto1.h" +#include "desfire_key.h" #include "mifareutil.h" #include "../include/common.h" diff --git a/armsrc/util.c b/armsrc/util.c index f20e4b42..8ff5b68d 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -20,7 +20,7 @@ void print_result(char *name, uint8_t *buf, size_t len) { if ( len % 16 == 0 ) { for(; p-buf < len; p += 16) - Dbprintf("[%s:%02x/%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, @@ -29,7 +29,7 @@ void print_result(char *name, uint8_t *buf, size_t len) { } else { for(; p-buf < len; p += 8) - Dbprintf("[%s:%02x/%02x] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); } } diff --git a/client/.history b/client/.history new file mode 100644 index 00000000..176dec98 --- /dev/null +++ b/client/.history @@ -0,0 +1,8 @@ +hw tune +lf read +data plot +data sample 4000 +lf t55xx rd 0 +lf t55xx trac +lf t55xx rd 1 +lf t55xx rd 2 diff --git a/client/cmddata.c b/client/cmddata.c index 72bc52e6..e7be9884 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -74,12 +74,14 @@ int Cmdaskdemod(const char *Cmd) int i; int c, high = 0, low = 0; - // TODO: complain if we do not give 2 arguments here ! - // (AL - this doesn't make sense! we're only using one argument!!!) sscanf(Cmd, "%i", &c); - /* Detect high and lows and clock */ - // (AL - clock???) + if (c != 0 && c != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + + /* Detect high and lows */ for (i = 0; i < GraphTraceLen; ++i) { if (GraphBuffer[i] > high) @@ -87,11 +89,7 @@ int Cmdaskdemod(const char *Cmd) else if (GraphBuffer[i] < low) low = GraphBuffer[i]; } - if (c != 0 && c != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - + if (GraphBuffer[0] > 0) { GraphBuffer[0] = 1-c; } else { diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index f3217df2..c0c7a67e 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -24,11 +24,13 @@ #include "util.h" #include "cmdhfmfdes.h" +uint8_t CMDPOS = 0; +uint8_t LENPOS = 1; uint8_t key_zero_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; 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_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }; - +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); static void xor(unsigned char * dst, unsigned char * src, size_t len); @@ -147,13 +149,13 @@ int CmdHF14ADesInfo(const char *Cmd){ PrintAndLog("Command unsuccessful"); return 0; } - - PrintAndLog("---Desfire Information---------------------------------------"); + 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(" -----------------------------------------------------------"); PrintAndLog(" Hardware Information"); PrintAndLog(" Vendor Id : %s", GetVendorStr(resp.d.asBytes[7])); PrintAndLog(" Type : 0x%02X",resp.d.asBytes[8]); @@ -161,7 +163,7 @@ int CmdHF14ADesInfo(const char *Cmd){ 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(" -----------------------------------------------------------"); PrintAndLog(" Software Information"); PrintAndLog(" Vendor Id : %s",GetVendorStr(resp.d.asBytes[14])); PrintAndLog(" Type : 0x%02X",resp.d.asBytes[15]); @@ -171,53 +173,15 @@ int CmdHF14ADesInfo(const char *Cmd){ PrintAndLog(" Protocol : %s", GetProtocolStr(resp.d.asBytes[20])); PrintAndLog("-------------------------------------------------------------"); + // Master Key settings + GetKeySettings(NULL); - UsbCommand c1 = {CMD_MIFARE_DESFIRE, { 0x03, 0x01 }}; - c1.d.asBytes[0] = GET_KEY_SETTINGS; - SendCommand(&c1); - if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - return 0; - } - - PrintAndLog(" Master Key settings"); - if ( resp.d.asBytes[3] & (1 << 3 ) ) - PrintAndLog(" 0x08 Configuration changeable"); - else - PrintAndLog(" 0x08 Configuration NOT changeable"); - - if ( resp.d.asBytes[3] & (1 << 2 ) ) - PrintAndLog(" 0x04 PICC Master Key not required for create / delete"); - else - PrintAndLog(" 0x04 PICC Master Key required for create / delete"); - - if ( resp.d.asBytes[3] & (1 << 1 ) ) - PrintAndLog(" 0x02 Free directory list access without PICC Master Key"); - else - PrintAndLog(" 0x02 Directory list access with PICC Master Key"); - - if ( resp.d.asBytes[3] & (1 << 0 ) ) - PrintAndLog(" 0x01 Allow changing the Master Key"); - else - PrintAndLog(" 0x01 Master Key is not changeable anymore"); - - // init len - UsbCommand c2 = {CMD_MIFARE_DESFIRE, { 0x03, 0x02 }}; - c2.d.asBytes[0] = GET_KEY_VERSION; - c2.d.asBytes[1] = 0x00; - SendCommand(&c2); - if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - return 0; - } - - 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("-------------------------------------------------------------"); - - - UsbCommand c3 = {CMD_MIFARE_DESFIRE, { 0x03, 0x01 }}; - c3.d.asBytes[0] = GET_FREE_MEMORY; - SendCommand(&c3); + // 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; } @@ -225,7 +189,7 @@ int CmdHF14ADesInfo(const char *Cmd){ uint8_t tmp[3]; memcpy(tmp, resp.d.asBytes+3,3); - PrintAndLog(" Free memory on card : %d bytes", le24toh( tmp )); + PrintAndLog(" Available free memory on card : %d bytes", le24toh( tmp )); PrintAndLog("-------------------------------------------------------------"); /* @@ -240,12 +204,7 @@ int CmdHF14ADesInfo(const char *Cmd){ keys 4,5,6,7 RW keys 8,9,10,11 W keys 12,13,14,15 R - - Session key: - 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte4-byte7) + RndB(byte4-byte7) - 8 : RndA(byte0-byte3) + RndB(byte0-byte3) - - AES 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte12-byte15) + RndB(byte12-byte15) + */ return 1; @@ -296,29 +255,202 @@ char * GetProtocolStr(uint8_t 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){ - uint32_t options = 0x00; - - options |= INIT; - options |= DISCONNECT; + 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; } - - uint8_t isOK = resp.arg[0] & 0xff; + isOK = resp.arg[0] & 0xff; if ( !isOK ){ PrintAndLog("Command unsuccessful"); return 0; } - - PrintAndLog("---Desfire Enum Applications --------------------------------"); + PrintAndLog(""); + PrintAndLog("-- Desfire Enumerate Applications ---------------------------"); PrintAndLog("-------------------------------------------------------------"); UsbCommand respAid; @@ -331,47 +463,73 @@ int CmdHF14ADesEnumApplications(const char *Cmd){ PrintAndLog(" Aid %d : %02X %02X %02X ",num ,resp.d.asBytes[i],resp.d.asBytes[i+1],resp.d.asBytes[i+2]); num++; - options = INIT; - - UsbCommand cAid = {CMD_MIFARE_DESFIRE, { options, 0x04 }}; - cAid.d.asBytes[0] = SELECT_APPLICATION; // 0x5a - cAid.d.asBytes[1] = resp.d.asBytes[i]; - cAid.d.asBytes[2] = resp.d.asBytes[i+1]; - cAid.d.asBytes[3] = resp.d.asBytes[i+2]; - SendCommand(&cAid); + 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; } - uint8_t isOK = respAid.arg[0] & 0xff; - if ( !isOK ){ + isOK = respAid.d.asBytes[2] & 0xff; + if ( isOK != 0x00 ){ PrintAndLog(" Can't select AID: %s",sprint_hex(resp.d.asBytes+i,3)); continue; } - options = DISCONNECT; - UsbCommand cFiles = {CMD_MIFARE_DESFIRE, { options, 0x01 }}; - cFiles.d.asBytes[0] = GET_FILE_IDS; // 0x6f - SendCommand(&cFiles); + // 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 { - - uint8_t isOK = respFiles.arg[0] & 0xff; + isOK = respFiles.d.asBytes[2] & 0xff; if ( !isOK ){ - PrintAndLog(" No files found"); - continue; - } - - int respfileLen = resp.arg[1]-3-2; - for (int j=0; j< respfileLen; ++j){ - PrintAndLog(" Fileid %d :", resp.d.asBytes[j+3]); + 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("-------------------------------------------------------------"); @@ -386,7 +544,7 @@ int CmdHF14ADesNonces(const char *Cmd){ // // MIAFRE DesFire Authentication // -#define BUFSIZE 64 +#define BUFSIZE 256 int CmdHF14ADesAuth(const char *Cmd){ // NR DESC KEYLENGHT @@ -395,22 +553,19 @@ int CmdHF14ADesAuth(const char *Cmd){ // 2 = 3DES 16 // 3 = 3K 3DES 24 // 4 = AES 16 - - // AUTHENTICTION MODES: - // 1 Normal - // 2 ISO - // 3 AES - + uint8_t keylength = 8; - //unsigned char testinput[] = { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00}; - unsigned char key[24]; // = { 0x75,0x28,0x78,0x39,0x74,0x93,0xCB,0x70}; + unsigned char key[24]; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf mfdes auth <1|2|3> <1|2|3|4> "); - PrintAndLog(" AUTH modes 1 = normal, 2 = iso, 3 = aes"); - PrintAndLog(" Crypto: 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES"); - PrintAndLog(" keynumber"); + 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); @@ -473,29 +628,27 @@ int CmdHF14ADesAuth(const char *Cmd){ c.d.asBytes[0] = keylength; memcpy(c.d.asBytes+1, key, keylength); - //memcpy(c.d.asBytes + 30, testinput, keylength); SendCommand(&c); UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,3000)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - - } else { - PrintAndLog("Command execute timeout"); + if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) { + PrintAndLog("Client command execute timeout"); return 0; } - uint8_t * data= resp.d.asBytes; + uint8_t isOK = resp.arg[0] & 0xff; + if ( isOK) { + uint8_t * data= resp.d.asBytes; - // PrintAndLog("-------------------------------------------------------------"); - PrintAndLog(" Key :%s",sprint_hex(key, keylength)); - // PrintAndLog(" Plain :%s",sprint_hex(testinput, keylength)); - PrintAndLog(" Encoded :%s",sprint_hex(data, keylength)); - PrintAndLog("-------------------------------------------------------------"); - //PrintAndLog(" Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56"); - + 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; } diff --git a/client/cmdhfmfdes.h b/client/cmdhfmfdes.h index 8ecf36d3..06f592ed 100644 --- a/client/cmdhfmfdes.h +++ b/client/cmdhfmfdes.h @@ -18,22 +18,23 @@ int CmdHF14ADesNonces(const char *Cmd); char * GetCardSizeStr( uint8_t fsize ); char * GetVendorStr( uint8_t id); char * GetProtocolStr(uint8_t id); +void GetKeySettings( uint8_t * aid); // Command options for Desfire behavior. enum { NONE = 0x00, INIT = 0x01, DISCONNECT = 0x02, - FOO = 0x04, + 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 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 @@ -48,6 +49,7 @@ enum { #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 @@ -65,9 +67,9 @@ enum { #define GET_KEY_VERSION 0x64 #define AUTHENTICATION_FRAME 0xAF - +#define MAX_NUM_KEYS 0x0F #define MAX_APPLICATION_COUNT 28 -#define MAX_FILE_COUNT 16 +#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/cmdlfem4x.c b/client/cmdlfem4x.c index 3c46d3b1..8380bcba 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -21,7 +21,7 @@ #include "cmdlfem4x.h" #include "util.h" #include "data.h" -#define LF_TRACE_BUFF_SIZE 16000 +#define LF_TRACE_BUFF_SIZE 12000 char *global_em410xId; @@ -526,29 +526,20 @@ int CmdReadWord(const char *Cmd) SendCommand(&c); WaitForResponse(CMD_ACK, NULL); - uint8_t data[LF_TRACE_BUFF_SIZE]; - memset(data, 0x00, LF_TRACE_BUFF_SIZE); + uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]) - 128; + GraphBuffer[j] = ((int)data[j]); } GraphTraceLen = LF_TRACE_BUFF_SIZE; - - // BiDirectional - //CmdDirectionalThreshold("70 -60"); - // Askdemod - //Cmdaskdemod("1"); - - uint8_t bits[1000]; + uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; - memset(bitstream, 0x00, sizeof(bits)); - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); - + RepaintGraphWindow(); return 0; } @@ -575,28 +566,21 @@ int CmdReadWordPWD(const char *Cmd) SendCommand(&c); WaitForResponse(CMD_ACK, NULL); - uint8_t data[LF_TRACE_BUFF_SIZE]; - memset(data, 0x00, LF_TRACE_BUFF_SIZE); + uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]) - 128; + GraphBuffer[j] = ((int)data[j]); } GraphTraceLen = LF_TRACE_BUFF_SIZE; - - // BiDirectional - //CmdDirectionalThreshold("70 -60"); - // Askdemod - //Cmdaskdemod("1"); - - uint8_t bits[1000]; + uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; - memset(bitstream, 0x00, sizeof(bits)); manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + RepaintGraphWindow(); return 0; } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index a002bf34..30f5e68e 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -21,7 +21,8 @@ #include "util.h" #include "data.h" -#define LF_TRACE_BUFF_SIZE 16000 + +#define LF_TRACE_BUFF_SIZE 12000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) static int CmdHelp(const char *Cmd); @@ -50,33 +51,25 @@ int CmdReadBlk(const char *Cmd) SendCommand(&c); WaitForResponse(CMD_ACK, NULL); - uint8_t data[LF_TRACE_BUFF_SIZE]; - memset(data, 0x00, LF_TRACE_BUFF_SIZE); + uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]) - 128; + GraphBuffer[j] = ((int)data[j]) ; } GraphTraceLen = LF_TRACE_BUFF_SIZE; - - // BiDirectional - //CmdDirectionalThreshold("70 60"); - // Askdemod - //Cmdaskdemod("1"); - - uint8_t bits[1000]; + uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; - memset(bitstream, 0x00, sizeof(bits)); manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + RepaintGraphWindow(); return 0; } - int CmdReadBlkPWD(const char *Cmd) { int Block = -1; //default to invalid block @@ -100,8 +93,7 @@ int CmdReadBlkPWD(const char *Cmd) SendCommand(&c); WaitForResponse(CMD_ACK, NULL); - uint8_t data[LF_TRACE_BUFF_SIZE]; - memset(data, 0x00, LF_TRACE_BUFF_SIZE); + uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); @@ -111,21 +103,14 @@ int CmdReadBlkPWD(const char *Cmd) } GraphTraceLen = LF_TRACE_BUFF_SIZE; - // BiDirectional - //CmdDirectionalThreshold("70 -60"); - - // Askdemod - //Cmdaskdemod("1"); - - uint8_t bits[1000]; + uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; - memset(bitstream, 0x00, sizeof(bits)); - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + RepaintGraphWindow(); return 0; } - int CmdWriteBlk(const char *Cmd) { int Block = 8; //default to invalid block @@ -177,39 +162,251 @@ int CmdWriteBlkPWD(const char *Cmd) int CmdReadTrace(const char *Cmd) { - PrintAndLog(" Reading page 1 - tracedata"); - - UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}}; - SendCommand(&c); + UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}}; + SendCommand(&c); WaitForResponse(CMD_ACK, NULL); - uint8_t data[LF_TRACE_BUFF_SIZE]; - memset(data, 0x00, LF_TRACE_BUFF_SIZE); + uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]) - 128; + GraphBuffer[j] = ((int)data[j]); + //GraphBuffer[j] = ((int)data[j]) - 128; } GraphTraceLen = LF_TRACE_BUFF_SIZE; - // BiDirectional - //CmdDirectionalThreshold("70 -60"); - - // Askdemod - //Cmdaskdemod("1"); - - - uint8_t bits[1000]; + uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; - memset(bitstream, 0x00, sizeof(bits)); manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); - + RepaintGraphWindow(); + + 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 num = 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 ); + PrintAndLog(" Manufactured"); + PrintAndLog(" Year/Quarter : %d/%d",2000+year, quarter ); + PrintAndLog(" Number : %d", num ); + PrintAndLog(" Wafer number : %d", wafer); + PrintAndLog(" Die Number : %d", dw); + PrintAndLog("-------------------------------------------------------------"); + PrintAndLog(" Raw Data"); + PrintAndLog(" Block 0 : %08X", bl0); + PrintAndLog(" Block 1 : %08X", bl1); + PrintAndLog("-------------------------------------------------------------"); + /* + TRACE - BLOCK O + Bits Definition HEX + 1-8 ACL Allocation class (ISO/IEC 15963-1) 0xE0 + 9-16 MFC Manufacturer ID (ISO/IEC 7816-6) 0x15 Atmel Corporation + 17-21 CID 0x1 = Atmel ATA5577M1 0x2 = Atmel ATA5577M2 + 22-24 ICR IC revision + 25-28 YEAR (BCD encoded) 9 (= 2009) + 29-30 QUARTER 1,2,3,4 + 31-32 Number + + TRACE - BLOCK 1 + 1-12 Number + 13-17 Wafer number + 18-32 DW, die number sequential + */ + return 0; } +int CmdInfo(const char *Cmd){ + /* + Page 0 Block 0 Configuration data. + Normal mode + Extended mode + */ + // läs block 0 - data finns i graphbuff + CmdReadBlk("0"); + + uint8_t bits[1000] = {0x00}; + uint8_t * bitstream = bits; + + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + + uint8_t si = 5; + uint32_t bl0 = PackBits(si, 32, bitstream); + + uint32_t safer = PackBits(si, 4, bitstream); si += 4; + uint32_t resv = PackBits(si, 7, bitstream); si += 7; + uint32_t dbr = PackBits(si, 3, bitstream); si += 3; + uint32_t extend = PackBits(si, 1, bitstream); si += 1; + uint32_t datamodulation = PackBits(si, 5, bitstream); si += 5; + uint32_t pskcf = PackBits(si, 2, bitstream); si += 2; + uint32_t aor = PackBits(si, 1, bitstream); si += 1; + uint32_t otp = PackBits(si, 1, bitstream); si += 1; + uint32_t maxblk = PackBits(si, 3, bitstream); si += 3; + uint32_t pwd = PackBits(si, 1, bitstream); si += 1; + uint32_t sst = PackBits(si, 1, bitstream); si += 1; + uint32_t fw = PackBits(si, 1, bitstream); si += 1; + uint32_t inv = PackBits(si, 1, bitstream); si += 1; + uint32_t por = PackBits(si, 1, bitstream); si += 1; + + PrintAndLog(""); + PrintAndLog("-- T55xx Configuration --------------------------------------"); + PrintAndLog("-------------------------------------------------------------"); + PrintAndLog(" Safer key : %s", GetSaferStr(safer)); + PrintAndLog(" reserved : %d", resv); + PrintAndLog(" Data bit rate : %s", GetBitRateStr(dbr)); + PrintAndLog(" eXtended mode : %s", (extend) ? "Yes - Warning":"No"); + PrintAndLog(" Modulation : %s", GetModulationStr(datamodulation) ); + PrintAndLog(" PSK clock freq : %d", pskcf); + PrintAndLog(" AOR - Answer on Request : %s", (aor) ? "Yes":"No"); + PrintAndLog(" OTP - One Time Pad : %s", (otp) ? "Yes - Warning":"No" ); + PrintAndLog(" Max block : %d", maxblk); + PrintAndLog(" Password mode : %s", (pwd) ? "Yes":"No"); + PrintAndLog(" Sequence Start Terminator : %s", (sst) ? "Yes":"No"); + PrintAndLog(" Fast Write : %s", (fw) ? "Yes":"No"); + PrintAndLog(" Inverse data : %s", (inv) ? "Yes":"No"); + PrintAndLog(" POR-Delay : %s", (por) ? "Yes":"No"); + PrintAndLog("-------------------------------------------------------------"); + PrintAndLog(" Raw Data"); + PrintAndLog(" Block 0 : 0x%08X", bl0); + PrintAndLog("-------------------------------------------------------------"); + + return 0; +} + +char * GetBitRateStr(uint32_t id){ + static char buf[40]; + char *retStr = buf; + switch (id){ + case 0: + sprintf(retStr,"%d - RF/8",id); + break; + case 1: + sprintf(retStr,"%d - RF/16",id); + break; + case 2: + sprintf(retStr,"%d - RF/32",id); + break; + case 3: + sprintf(retStr,"%d - RF/40",id); + break; + case 4: + sprintf(retStr,"%d - RF/50",id); + break; + case 5: + sprintf(retStr,"%d - RF/64",id); + break; + case 6: + sprintf(retStr,"%d - RF/100",id); + break; + case 7: + sprintf(retStr,"%d - RF/128",id); + break; + default: + sprintf(retStr,"%d - (Unknown)",id); + break; + } + + return buf; +} + + +char * GetSaferStr(uint32_t id){ + static char buf[40]; + char *retStr = buf; + + sprintf(retStr,"%d",id); + if (id == 6) { + sprintf(retStr,"%d - pasdwd",id); + } + if (id == 9 ){ + sprintf(retStr,"%d - testmode ",id); + } + + return buf; +} +char * GetModulationStr( uint32_t id){ + static char buf[40]; + char *retStr = buf; + + switch (id){ + case 0: + sprintf(retStr,"%d - direct",id); + break; + case 1: + sprintf(retStr,"%d - PSK 1 phase change when input changes",id); + break; + case 2: + sprintf(retStr,"%d - PSK 2 phase change on bitclk if input high",id); + break; + case 3: + sprintf(retStr,"%d - PSK 3 phase change on rising edge of input",id); + break; + case 4: + sprintf(retStr,"%d - FSK 1 RF/8 RF/5",id); + break; + case 5: + sprintf(retStr,"%d - FSK 2 RF/8 RF/10",id); + break; + case 6: + sprintf(retStr,"%d - FSK 1a RF/5 RF/8",id); + break; + case 7: + sprintf(retStr,"%d - FSK 2a RF/10 RF/8",id); + break; + case 8: + sprintf(retStr,"%d - Manschester",id); + break; + case 16: + sprintf(retStr,"%d - Biphase",id); + break; + case 17: + sprintf(retStr,"%d - Reserved",id); + break; + default: + sprintf(retStr,"0x%02X (Unknown)",id); + break; + } + return buf; +} + + +uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits){ + + int i = start; + int j = len-1; + uint32_t tmp = 0; + for (; j >= 0; --j, ++i){ + tmp |= bits[i] << j; + } + return tmp; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -218,6 +415,7 @@ static command_t CommandTable[] = {"wr", CmdWriteBlk, 0, " -- Write T55xx block data (page 0)"}, {"wrPWD", CmdWriteBlkPWD, 0, " -- Write T55xx block data in password mode(page 0)"}, {"trace", CmdReadTrace, 0, "Read T55xx traceability data (page 1)"}, + {"info", CmdInfo, 0, "Read T55xx configuration data (page 0 / block 0"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 25503e87..d7be8add 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -17,5 +17,9 @@ int CmdReadBlkPWD(const char *Cmd); int CmdWriteBlk(const char *Cmd); int CmdWriteBLkPWD(const char *Cmd); int CmdReadTrace(const char *Cmd); - +int CmdInfo(const char *Cmd); +char * GetBitRateStr(uint32_t id); +char * GetSaferStr(uint32_t id); +char * GetModulationStr( uint32_t id); +uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bitstream); #endif diff --git a/client/ui.c b/client/ui.c index 4f1b5d85..b4e85575 100644 --- a/client/ui.c +++ b/client/ui.c @@ -12,11 +12,12 @@ #include #include #include +#include #include #include #include - #include "ui.h" +#include "loclass/cipherutils.h" double CursorScaleFactor; int PlotGridX, PlotGridY, PlotGridXdefault= 64, PlotGridYdefault= 64; @@ -85,22 +86,20 @@ void PrintAndLog(char *fmt, ...) pthread_mutex_unlock(&print_lock); } - void SetLogFilename(char *fn) { logfilename = fn; } - -int manchester_decode(const int * data, const size_t len, uint8_t * dataout){ +int manchester_decode( int * data, const size_t len, uint8_t * dataout){ int bitlength = 0; int i, clock, high, low, startindex; low = startindex = 0; high = 1; uint8_t bitStream[len]; - - memset(bitStream, 0x00, len); + + memset(bitStream, 0x00, len); /* Detect high and lows */ for (i = 0; i < len; i++) { @@ -112,19 +111,18 @@ int manchester_decode(const int * data, const size_t len, uint8_t * dataout){ /* get clock */ clock = GetT55x7Clock( data, len, high ); - startindex = DetectFirstTransition(data, len, high, low); + startindex = DetectFirstTransition(data, len, high); - PrintAndLog(" Clock : %d", clock); - PrintAndLog(" startindex : %d", startindex); + PrintAndLog(" Clock : %d", clock); + PrintAndLog(" startindex : %d", startindex); if (high != 1) bitlength = ManchesterConvertFrom255(data, len, bitStream, high, low, clock, startindex); else bitlength= ManchesterConvertFrom1(data, len, bitStream, clock, startindex); - if ( bitlength > 0 ){ + if ( bitlength > 0 ) PrintPaddedManchester(bitStream, bitlength, clock); - } memcpy(dataout, bitStream, bitlength); @@ -171,80 +169,112 @@ int manchester_decode(const int * data, const size_t len, uint8_t * dataout){ break; default: break; } - return 32; + + PrintAndLog(" Found Clock : %d - trying to adjust", clock); + + // When detected clock is 31 or 33 then then return + int clockmod = clock%8; + if ( clockmod == 7 ) + clock += 1; + else if ( clockmod == 1 ) + clock -= 1; + + return clock; } - int DetectFirstTransition(const int * data, const size_t len, int high, int low){ + int DetectFirstTransition(const int * data, const size_t len, int threshold){ - int i, retval; - retval = 0; - /* - Detect first transition Lo-Hi (arbitrary) - skip to the first high - */ - for (i = 0; i < len; ++i) - if (data[i] == high) - break; - - /* now look for the first low */ - for (; i < len; ++i) { - if (data[i] == low) { - retval = i; + int i =0; + /* now look for the first threshold */ + for (; i < len; ++i) { + if (data[i] == threshold) { break; } - } - return retval; + } + return i; } int ManchesterConvertFrom255(const int * data, const size_t len, uint8_t * dataout, int high, int low, int clock, int startIndex){ - int i, j, hithigh, hitlow, first, bit, bitIndex; - i = 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; - /* - * We assume the 1st bit is zero, it may not be - * the case: this routine (I think) has an init problem. - * Ed. - */ - bit = 0; - + // i = clock frame of data for (; i < (int)(len / clock); i++) { hithigh = 0; hitlow = 0; - first = 1; - + 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[(i * clock) + j] == high) + { + if (data[z+j] == high){ hithigh = 1; - else if (data[(i * clock) + j] == low) + if ( startType == -1) + startType = 1; + } + + if (data[z+j] == low ){ hitlow = 1; - - /* it doesn't count if it's the first part of our read - because it's really just trailing from the last sequence */ - if (first && (hithigh || hitlow)) - hithigh = hitlow = 0; - else - first = 0; - + 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/2; j++) + { + if ( + (data[z+j] <= dampHi && data[z+j] >= dampLow) + ){ + isDamp = 1; + } + else + isDamp = 0; + } + } - /* If we didn't hit both high and low peaks, we had a bit transition */ - if (!hithigh || !hitlow) - bit ^= 1; - - dataout[bitIndex++] = bit; + /* 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 ) { + firstST++; + } + + if ( firstST == 4) + break; } return bitIndex; } int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout, int clock, int startIndex){ + PrintAndLog(" Path B"); + int i,j, bitindex, lc, tolerance, warnings; warnings = 0; int upperlimit = len*2/clock+8; @@ -253,7 +283,7 @@ int manchester_decode(const int * data, const size_t len, uint8_t * dataout){ tolerance = clock/4; uint8_t decodedArr[len]; - /* Then detect duration between 2 successive transitions */ + /* Detect duration between 2 successive transitions */ for (bitindex = 1; i < len; i++) { if (data[i-1] != data[i]) { @@ -350,19 +380,19 @@ int manchester_decode(const int * data, const size_t len, uint8_t * dataout){ PrintAndLog("%s", sprint_hex(decodedArr, j)); } - void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){ - PrintAndLog(" Manchester decoded bitstream : %d bits", len); + 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) { + 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) ); - } -} + } + + if ( mod > 0 ) + PrintAndLog(" %s", sprint_bin(bitStream+i, mod) ); +} \ No newline at end of file diff --git a/client/ui.h b/client/ui.h index f599ef3c..823dccc2 100644 --- a/client/ui.h +++ b/client/ui.h @@ -25,9 +25,9 @@ extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault; extern int offline; extern int flushAfterWrite; //buzzy -int manchester_decode(const int * data, const size_t len, uint8_t * dataout); +int manchester_decode( int * data, const size_t len, uint8_t * dataout); int GetT55x7Clock( const int * data, const size_t len, int high ); -int DetectFirstTransition(const int * data, const size_t len, int high, int low); +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 high, int low, int clock, int startIndex); diff --git a/common/Makefile.common b/common/Makefile.common index 2b2bb2fb..b30294a8 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -69,7 +69,7 @@ INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gp CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 $(APP_CFLAGS) -Os LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n -LIBS = -lgcc +LIBS = -lgcc THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(THUMBSRC)) ARMOBJ = $(ARMSRC:%.c=$(OBJDIR)/%.o) diff --git a/common/desfire.h b/common/desfire.h index 912ca9ff..c163c5c5 100644 --- a/common/desfire.h +++ b/common/desfire.h @@ -1,9 +1,10 @@ #ifndef __DESFIRE_H #define __DESFIRE_H +#include +#include + #include "aes.h" -#define DESFIRE(tag) ((struct desfire_tag *) tag) -#define DESFIRE_KEY(key) ((struct desfire_key *) key) #define MAX_CRYPTO_BLOCK_SIZE 16 /* Mifare DESFire EV1 Application crypto operations */ @@ -65,8 +66,9 @@ enum DESFIRE_CRYPTOALGO { T_AES = 0x03 }; -struct desfire_key { +#define DESFIRE_KEY(key) ((struct desfire_key *) key) +struct desfire_key { enum DESFIRE_CRYPTOALGO type; uint8_t data[24]; // DES_key_schedule ks1; @@ -77,9 +79,9 @@ struct desfire_key { 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; diff --git a/cp2tau b/cp2tau new file mode 100644 index 00000000..8b6ee4b4 --- /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 diff --git a/iceman.txt b/iceman.txt new file mode 100644 index 00000000..e69de29b From 773765774761e1463cadd979c1f74728b8b6fd31 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 7 Oct 2014 21:34:02 +0200 Subject: [PATCH 07/78] Fixed: the dampening field detection is enhanced. If half a frame (clock rate) of values is within 40% of the mean value then it is a dampening field. --- client/cmdlft55xx.c | 113 +++++++++++++++++++++++++++++--------------- client/ui.c | 21 ++++---- 2 files changed, 83 insertions(+), 51 deletions(-) diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 30f5e68e..027f528a 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -39,7 +39,7 @@ int CmdReadBlk(const char *Cmd) return 1; } - PrintAndLog(" Reading page 0 block : %d", Block); + //PrintAndLog(" Reading page 0 block : %d", Block); // this command fills up BigBuff // @@ -66,6 +66,9 @@ int CmdReadBlk(const char *Cmd) manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + uint32_t bl0 = PackBits(5, 32, bitstream); + PrintAndLog(" Block %d : 0x%08X %s", Block, bl0, sprint_bin(bitstream+5,32) ); + RepaintGraphWindow(); return 0; } @@ -107,6 +110,10 @@ int CmdReadBlkPWD(const char *Cmd) uint8_t * bitstream = bits; manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + + uint32_t bl0 = PackBits(5, 32, bitstream); + PrintAndLog(" Block %d : 0x%08X %s", Block, bl0, sprint_bin(bitstream+5,32) ); + RepaintGraphWindow(); return 0; } @@ -187,23 +194,15 @@ int CmdReadTrace(const char *Cmd) 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 num = PackBits(si, 12, bitstream); - si += 12; - uint32_t wafer = PackBits(si, 5, bitstream); - si += 5; - uint32_t dw = PackBits(si, 15, 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 ----------------------------------"); @@ -214,13 +213,13 @@ int CmdReadTrace(const char *Cmd) PrintAndLog(" ICR IC Revision : %d",icr ); PrintAndLog(" Manufactured"); PrintAndLog(" Year/Quarter : %d/%d",2000+year, quarter ); - PrintAndLog(" Number : %d", num ); + PrintAndLog(" Lot ID : %d", lotid ); PrintAndLog(" Wafer number : %d", wafer); PrintAndLog(" Die Number : %d", dw); PrintAndLog("-------------------------------------------------------------"); - PrintAndLog(" Raw Data"); - PrintAndLog(" Block 0 : %08X", bl0); - PrintAndLog(" Block 1 : %08X", bl1); + PrintAndLog(" Raw Data - Page 1"); + PrintAndLog(" Block 0 : 0x%08X %s", bl0, sprint_bin(bitstream+5,32) ); + PrintAndLog(" Block 0 : 0x%08X %s", bl1, sprint_bin(bitstream+37,32) ); PrintAndLog("-------------------------------------------------------------"); /* TRACE - BLOCK O @@ -231,10 +230,10 @@ int CmdReadTrace(const char *Cmd) 22-24 ICR IC revision 25-28 YEAR (BCD encoded) 9 (= 2009) 29-30 QUARTER 1,2,3,4 - 31-32 Number + 31-32 LOT ID TRACE - BLOCK 1 - 1-12 Number + 1-12 LOT ID 13-17 Wafer number 18-32 DW, die number sequential */ @@ -257,22 +256,22 @@ int CmdInfo(const char *Cmd){ manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); uint8_t si = 5; - uint32_t bl0 = PackBits(si, 32, bitstream); + uint32_t bl0 = PackBits(si, 32, bitstream); - uint32_t safer = PackBits(si, 4, bitstream); si += 4; - uint32_t resv = PackBits(si, 7, bitstream); si += 7; - uint32_t dbr = PackBits(si, 3, bitstream); si += 3; + uint32_t safer = PackBits(si, 4, bitstream); si += 4; + uint32_t resv = PackBits(si, 7, bitstream); si += 7; + uint32_t dbr = PackBits(si, 3, bitstream); si += 3; uint32_t extend = PackBits(si, 1, bitstream); si += 1; uint32_t datamodulation = PackBits(si, 5, bitstream); si += 5; - uint32_t pskcf = PackBits(si, 2, bitstream); si += 2; - uint32_t aor = PackBits(si, 1, bitstream); si += 1; - uint32_t otp = PackBits(si, 1, bitstream); si += 1; + uint32_t pskcf = PackBits(si, 2, bitstream); si += 2; + uint32_t aor = PackBits(si, 1, bitstream); si += 1; + uint32_t otp = PackBits(si, 1, bitstream); si += 1; uint32_t maxblk = PackBits(si, 3, bitstream); si += 3; - uint32_t pwd = PackBits(si, 1, bitstream); si += 1; - uint32_t sst = PackBits(si, 1, bitstream); si += 1; - uint32_t fw = PackBits(si, 1, bitstream); si += 1; - uint32_t inv = PackBits(si, 1, bitstream); si += 1; - uint32_t por = PackBits(si, 1, bitstream); si += 1; + uint32_t pwd = PackBits(si, 1, bitstream); si += 1; + uint32_t sst = PackBits(si, 1, bitstream); si += 1; + uint32_t fw = PackBits(si, 1, bitstream); si += 1; + uint32_t inv = PackBits(si, 1, bitstream); si += 1; + uint32_t por = PackBits(si, 1, bitstream); si += 1; PrintAndLog(""); PrintAndLog("-- T55xx Configuration --------------------------------------"); @@ -292,13 +291,49 @@ int CmdInfo(const char *Cmd){ PrintAndLog(" Inverse data : %s", (inv) ? "Yes":"No"); PrintAndLog(" POR-Delay : %s", (por) ? "Yes":"No"); PrintAndLog("-------------------------------------------------------------"); - PrintAndLog(" Raw Data"); - PrintAndLog(" Block 0 : 0x%08X", bl0); + PrintAndLog(" Raw Data - Page 0"); + PrintAndLog(" Block 0 : 0x%08X %s", bl0, sprint_bin(bitstream+5,32) ); PrintAndLog("-------------------------------------------------------------"); return 0; } +int CmdDump(const char *Cmd){ + + char cmdp = param_getchar(Cmd, 0); + char s[20]; + uint8_t pwd[4] = {0x00}; + + + if (strlen(Cmd)>1 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: lf t55xx dump "); + PrintAndLog(" sample: lf t55xx dump FFFFFFFF"); + return 0; + } + + bool hasPwd = ( strlen(Cmd) > 0); + + if ( hasPwd ){ + if (param_gethex(Cmd, 0, pwd, 4)) { + PrintAndLog("password must include 4 HEX symbols"); + return 0; + } + } + + + for ( int i = 0; i <8; ++i){ + *s = 0; + if ( hasPwd ) { + sprintf(s,"%d %d", i, pwd); + CmdReadBlkPWD(s); + } else { + sprintf(s,"%d", i); + CmdReadBlk(s); + } + } + return 0; +} + char * GetBitRateStr(uint32_t id){ static char buf[40]; char *retStr = buf; @@ -335,7 +370,6 @@ char * GetBitRateStr(uint32_t id){ return buf; } - char * GetSaferStr(uint32_t id){ static char buf[40]; char *retStr = buf; @@ -416,6 +450,7 @@ static command_t CommandTable[] = {"wrPWD", CmdWriteBlkPWD, 0, " -- Write T55xx block data in password mode(page 0)"}, {"trace", CmdReadTrace, 0, "Read T55xx traceability data (page 1)"}, {"info", CmdInfo, 0, "Read T55xx configuration data (page 0 / block 0"}, + {"dump", CmdDump, 0, "Dump T55xx card block 0-7 (is possible)"}, {NULL, NULL, 0, NULL} }; diff --git a/client/ui.c b/client/ui.c index b4e85575..c796d904 100644 --- a/client/ui.c +++ b/client/ui.c @@ -113,16 +113,16 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ clock = GetT55x7Clock( data, len, high ); startindex = DetectFirstTransition(data, len, high); - PrintAndLog(" Clock : %d", clock); - PrintAndLog(" startindex : %d", startindex); + //PrintAndLog(" Clock : %d", clock); + //PrintAndLog(" startindex : %d", startindex); if (high != 1) bitlength = ManchesterConvertFrom255(data, len, bitStream, high, low, clock, startindex); else bitlength= ManchesterConvertFrom1(data, len, bitStream, clock, startindex); - if ( bitlength > 0 ) - PrintPaddedManchester(bitStream, bitlength, clock); + //if ( bitlength > 0 ) + // PrintPaddedManchester(bitStream, bitlength, clock); memcpy(dataout, bitStream, bitlength); @@ -170,7 +170,7 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ default: break; } - PrintAndLog(" Found Clock : %d - trying to adjust", clock); + //PrintAndLog(" Found Clock : %d - trying to adjust", clock); // When detected clock is 31 or 33 then then return int clockmod = clock%8; @@ -214,8 +214,7 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ startType = -1; z = startIndex + (i*clock); isDamp = 0; - - + /* Find out if we hit both high and low peaks */ for (j = 0; j < clock; j++) { @@ -238,15 +237,13 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ // 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/2; j++) + for (j = 0; j < clock; j++) { if ( (data[z+j] <= dampHi && data[z+j] >= dampLow) ){ - isDamp = 1; + isDamp++; } - else - isDamp = 0; } } @@ -261,7 +258,7 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ else dataout[bitIndex++] = 2; - if ( isDamp ) { + if ( isDamp > clock/2 ) { firstST++; } From 7bd30f12ac6def96c82df20ed7d927160db289af Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 16 Oct 2014 15:05:27 +0200 Subject: [PATCH 08/78] Small fixes, Fix: removed a call to free, which I think made linux people unhappy during "lf t55xx rd 0"... Add: "lf t55xx fsk" now kind of outputs binary from "FSK2a R/40 R/50".. --- armsrc/iso15693.c | 18 ++-- armsrc/lfops.c | 146 ++++++----------------------- client/Makefile | 6 +- client/cmdhf15.c | 28 +++++- client/cmdhfmf.c | 10 +- client/cmdlf.c | 33 +++++-- client/cmdlfio.c | 16 +--- client/cmdlft55xx.c | 28 ++++-- client/cmdlft55xx.h | 1 + client/data.c | 16 ---- client/ui.c | 222 +++++++++++++++++++++++++++++++++++++++++++- client/ui.h | 5 + tools/mkversion.pl | 2 +- 13 files changed, 346 insertions(+), 185 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 39d9effb..d8bec898 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -64,6 +64,8 @@ #include "string.h" #include "../common/iso15693tools.h" #include "../common/cmd.h" +#include "crapto1.h" +#include "mifareutil.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) @@ -600,10 +602,10 @@ static void BuildIdentifyRequest(void); //----------------------------------------------------------------------------- void AcquireRawAdcSamplesIso15693(void) { - int c = 0; - uint8_t *dest = (uint8_t *)BigBuf; - int getNext = 0; + uint8_t *dest = mifare_get_bigbufptr(); + int c = 0; + int getNext = 0; int8_t prev = 0; FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -682,10 +684,10 @@ void AcquireRawAdcSamplesIso15693(void) void RecordRawAdcSamplesIso15693(void) { - int c = 0; - uint8_t *dest = (uint8_t *)BigBuf; - int getNext = 0; + uint8_t *dest = mifare_get_bigbufptr(); + int c = 0; + int getNext = 0; int8_t prev = 0; FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -693,8 +695,8 @@ void RecordRawAdcSamplesIso15693(void) FpgaSetupSsc(); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 0c0f0275..e086a717 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -54,11 +54,11 @@ void SnoopLFRawAdcSamples(int divisor, int trigger_threshold) // split into two routines so we can avoid timing issues after sending commands // void DoAcquisition125k(int trigger_threshold) { - uint8_t *dest = (uint8_t *)BigBuf; - int n = sizeof(BigBuf); + uint8_t *dest = mifare_get_bigbufptr(); + int n = 8000; int i; - memset(dest, 0, n); + memset(dest, 0x00, n); i = 0; for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { @@ -77,6 +77,7 @@ void DoAcquisition125k(int trigger_threshold) } Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + } void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) @@ -829,24 +830,12 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = (uint8_t *)BigBuf; + uint8_t *dest = mifare_get_bigbufptr(); int m=0, n=0, i=0, idx=0, lastval=0; int found=0; uint32_t code=0, code2=0; - //uint32_t hi2=0, hi=0, lo=0; - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); + LFSetupFPGAForADC(0, true); for(;;) { WDT_HIT(); @@ -860,7 +849,7 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) } i = 0; - m = sizeof(BigBuf); + m = 30000; memset(dest,128,m); for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { @@ -872,13 +861,12 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // we don't care about actual value, only if it's more or less than a // threshold essentially we capture zero crossings for later analysis - if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; - i++; + dest[i] = (dest[i] < 127) ? 0 : 1; + ++i; if (ledcontrol) LED_D_OFF(); - if(i >= m) { + if(i >= m) break; - } } } @@ -898,12 +886,7 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) for( i=0; idx tagtype lookups typedef struct { @@ -252,6 +253,17 @@ int CmdHF15Read(const char *Cmd) { UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693}; SendCommand(&c); + + uint8_t data[TRACE_BUFF_SIZE] = {0x00}; + + GetFromBigBuf(data,TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]) ; + } + GraphTraceLen = TRACE_BUFF_SIZE; + RepaintGraphWindow(); return 0; } @@ -260,6 +272,17 @@ int CmdHF15Record(const char *Cmd) { UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693}; SendCommand(&c); + + uint8_t data[TRACE_BUFF_SIZE] = {0x00}; + + GetFromBigBuf(data,TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]) ; + } + GraphTraceLen = TRACE_BUFF_SIZE; + RepaintGraphWindow(); return 0; } @@ -421,8 +444,9 @@ int CmdHF15CmdInquiry(const char *Cmd) int CmdHF15CmdDebug( const char *cmd) { int debug=atoi(cmd); if (strlen(cmd)<1) { - PrintAndLog("Usage: hf 15 cmd debug <0/1>"); - PrintAndLog(" 0..no debugging output 1..turn debugging on"); + PrintAndLog("Usage: hf 15 cmd debug <0|1>"); + PrintAndLog(" 0 no debugging"); + PrintAndLog(" 1 turn debugging on"); return 0; } diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 8448731e..0e212b2d 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -522,13 +522,13 @@ int CmdHF14AMfDump(const char *Cmd) int size = GetCardSize(); char cmdp = param_getchar(Cmd, 0); - PrintAndLog("Got %d",size); - - return 0; + if ( size > -1) - cmdp = (char)48+size; - + cmdp = (char)(48+size); + + PrintAndLog("Got %d",cmdp); + switch (cmdp) { case '0' : numSectors = 5; break; case '1' : diff --git a/client/cmdlf.c b/client/cmdlf.c index 71d87f16..2306121b 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -468,6 +468,18 @@ int CmdLFSnoop(const char *Cmd) } SendCommand(&c); WaitForResponse(CMD_ACK,NULL); + + size_t BUFF_SIZE = 8000; + uint8_t data[BUFF_SIZE]; + + GetFromBigBuf(data,BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]); + } + GraphTraceLen = BUFF_SIZE; + return 0; } @@ -551,22 +563,27 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"cmdread", CmdLFCommandRead, 0, " <'0' period> <'1' period> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)"}, - {"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"}, + {"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, 1, " ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"}, + {"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"}, + + {"read", CmdLFRead, 0, "['h' or ] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134, alternatively: f=12MHz/(divisor+1))"}, {"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"}, {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, {"simman", CmdLFSimManchester, 0, " [GAP] Simulate arbitrary Manchester LF tag"}, {"snoop", CmdLFSnoop, 0, "['l'|'h'|] [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...}"}, + + {"em4x", CmdLFEM4X, 1, "{ EM4X tags }"}, + {"hid", CmdLFHID, 1, "{ HID tags }"}, + {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders }"}, + {"io", CmdLFIO, 1, "{ ioProx tags }"}, + {"pcf7931", CmdLFPCF7931, 1, "{ PCF7931 tags }"}, + {"ti", CmdLFTI, 1, "{ TI tags }"}, + {"t55xx", CmdLFT55XX, 1, "{ T55xx tags }"}, + {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfio.c b/client/cmdlfio.c index d7d36bc1..919fa442 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -21,20 +21,14 @@ int CmdIODemodFSK(const char *Cmd) return 0; } - int CmdIOProxDemod(const char *Cmd){ if (GraphTraceLen < 4800) { PrintAndLog("too short; need at least 4800 samples"); return 0; } - GraphTraceLen = 4800; for (int i = 0; i < GraphTraceLen; ++i) { - if (GraphBuffer[i] < 0) { - GraphBuffer[i] = 0; - } else { - GraphBuffer[i] = 1; - } + GraphBuffer[i] = (GraphBuffer[i] < 0) ? 0 : 1; } RepaintGraphWindow(); return 0; @@ -68,10 +62,10 @@ int CmdIOClone(const char *Cmd) static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"demod", CmdIOProxDemod, 1, "Demodulate Stream"}, - {"fskdemod", CmdIODemodFSK, 1, "Demodulate ioProx Tag"}, - {"clone", CmdIOClone, 1, "Clone ioProx Tag"}, + {"help", CmdHelp, 1, "This help"}, + {"demod", CmdIOProxDemod, 1, "Demodulate Stream"}, + {"fskdemod", CmdIODemodFSK, 1, "Demodulate ioProx Tag"}, + {"clone", CmdIOClone, 1, "Clone ioProx Tag"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 027f528a..3820e590 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -303,7 +303,6 @@ int CmdDump(const char *Cmd){ char cmdp = param_getchar(Cmd, 0); char s[20]; uint8_t pwd[4] = {0x00}; - if (strlen(Cmd)>1 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: lf t55xx dump "); @@ -320,7 +319,6 @@ int CmdDump(const char *Cmd){ } } - for ( int i = 0; i <8; ++i){ *s = 0; if ( hasPwd ) { @@ -334,6 +332,15 @@ int CmdDump(const char *Cmd){ return 0; } +int CmdIceFsk(const char *Cmd){ + //uint8_t bits[1000] = {0x00}; + //uint8_t * bitstream = bits; + iceFsk3(GraphBuffer, LF_TRACE_BUFF_SIZE); + + RepaintGraphWindow(); + return 0; +} + char * GetBitRateStr(uint32_t id){ static char buf[40]; char *retStr = buf; @@ -390,7 +397,7 @@ char * GetModulationStr( uint32_t id){ switch (id){ case 0: - sprintf(retStr,"%d - direct",id); + sprintf(retStr,"%d - DIRECT (ASK/NRZ)",id); break; case 1: sprintf(retStr,"%d - PSK 1 phase change when input changes",id); @@ -444,13 +451,14 @@ uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"rd", CmdReadBlk, 0, " -- Read T55xx block data (page 0)"}, - {"rdPWD", CmdReadBlkPWD, 0, " -- Read T55xx block data in password mode(page 0)"}, - {"wr", CmdWriteBlk, 0, " -- Write T55xx block data (page 0)"}, - {"wrPWD", CmdWriteBlkPWD, 0, " -- Write T55xx block data in password mode(page 0)"}, - {"trace", CmdReadTrace, 0, "Read T55xx traceability data (page 1)"}, - {"info", CmdInfo, 0, "Read T55xx configuration data (page 0 / block 0"}, - {"dump", CmdDump, 0, "Dump T55xx card block 0-7 (is possible)"}, + {"rd", CmdReadBlk, 0, " -- Read T55xx block data (page 0)"}, + {"rdPWD", CmdReadBlkPWD, 0, " -- Read T55xx block data with password mode"}, + {"wr", CmdWriteBlk, 0, " -- Write T55xx block data (page 0)"}, + {"wrPWD", CmdWriteBlkPWD, 0, " -- Write T55xx block data with password"}, + {"trace", CmdReadTrace, 0, "Read T55xx traceability data (page 1 / blk 0-1)"}, + {"info", CmdInfo, 0, "Read T55xx configuration data (page0 /blk 0)"}, + {"dump", CmdDump, 0, "[password] Dump T55xx card block 0-7. optional with password"}, + {"fsk", CmdIceFsk, 0, "FSK demod"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index d7be8add..f4fc3640 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -18,6 +18,7 @@ int CmdWriteBlk(const char *Cmd); int CmdWriteBLkPWD(const char *Cmd); int CmdReadTrace(const char *Cmd); int CmdInfo(const char *Cmd); +int CmdIceFsk(const char *Cmd); char * GetBitRateStr(uint32_t id); char * GetSaferStr(uint32_t id); char * GetModulationStr( uint32_t id); diff --git a/client/data.c b/client/data.c index 72acf8a6..3f019326 100644 --- a/client/data.c +++ b/client/data.c @@ -22,22 +22,6 @@ void GetFromBigBuf(uint8_t *dest, int bytes, int start_index) { sample_buf_len = 0; sample_buf = dest; -// start_index = ((start_index/12)*12); -// int n = start_index + bytes; - /* - if (n % 48 != 0) { - PrintAndLog("bad len in GetFromBigBuf"); - return; - } - */ UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}}; SendCommand(&c); -/* - for (int i = start_index; i < n; i += 48) { - UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {i, 0, 0}}; - SendCommand(&c); -// WaitForResponse(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K); -// memcpy(dest+(i*4), sample_buf, 48); - } -*/ } diff --git a/client/ui.c b/client/ui.c index c796d904..1d85cc05 100644 --- a/client/ui.c +++ b/client/ui.c @@ -16,8 +16,11 @@ #include #include #include -#include "ui.h" #include "loclass/cipherutils.h" +#include "ui.h" + +//#include +#define M_PI 3.14159265358979323846264338327 double CursorScaleFactor; int PlotGridX, PlotGridY, PlotGridXdefault= 64, PlotGridYdefault= 64; @@ -125,8 +128,6 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ // PrintPaddedManchester(bitStream, bitlength, clock); memcpy(dataout, bitStream, bitlength); - - free(bitStream); return bitlength; } @@ -392,4 +393,217 @@ void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){ if ( mod > 0 ) PrintAndLog(" %s", sprint_bin(bitStream+i, mod) ); -} \ No newline at end of file +} + +void iceFsk(int * data, const size_t len){ + + //34359738 == 125khz (2^32 / 125) = + + // parameters + float phase_offset = 0.00f; // carrier phase offset + float frequency_offset = 0.30f; // carrier frequency offset + float wn = 0.01f; // pll bandwidth + float zeta = 0.707f; // pll damping factor + float K = 1000; // pll loop gain + size_t n = len; // number of samples + + // generate loop filter parameters (active PI design) + float t1 = K/(wn*wn); // tau_1 + float t2 = 2*zeta/wn; // tau_2 + + // feed-forward coefficients (numerator) + float b0 = (4*K/t1)*(1.+t2/2.0f); + float b1 = (8*K/t1); + float b2 = (4*K/t1)*(1.-t2/2.0f); + + // feed-back coefficients (denominator) + // a0 = 1.0 is implied + float a1 = -2.0f; + float a2 = 1.0f; + + // filter buffer + float v0=0.0f, v1=0.0f, v2=0.0f; + + // initialize states + float phi = phase_offset; // input signal's initial phase + float phi_hat = 0.0f; // PLL's initial phase + + unsigned int i; + float complex x,y; + float complex output[n]; + + for (i=0; i 60)? 100:0; + } + } + + for (j=0; j 0)? 10 : -10; + } + + // show data + for (j=0; j 0 ) + printf("1"); + else + printf("0"); + } + printf("\n"); + + printf("R/50 : "); + for (i =startPos ; i < len; i += 50){ + if ( data[i] > 0 ) + printf("1"); + else + printf("0"); + } + printf("\n"); + +} + +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; +} diff --git a/client/ui.h b/client/ui.h index 823dccc2..666d7002 100644 --- a/client/ui.h +++ b/client/ui.h @@ -11,6 +11,8 @@ #ifndef UI_H__ #define UI_H__ +#include +#include #include "util.h" void ShowGui(void); @@ -32,4 +34,7 @@ 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 high, int low, int clock, int startIndex); int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout, int clock, int startIndex); +void iceFsk(int * data, const size_t len); +void iceFsk2(int * data, const size_t len); +void iceFsk3(int * data, const size_t len); #endif diff --git a/tools/mkversion.pl b/tools/mkversion.pl index 19616441..e12dd447 100644 --- a/tools/mkversion.pl +++ b/tools/mkversion.pl @@ -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; From fbceacc5b80254eb4381102d44e78aad7490876f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 16 Oct 2014 22:25:38 +0200 Subject: [PATCH 09/78] add: "lf t55xx info" option to use data from Graphbuffer. add: "lf t55xx trace" option to use data from Graphbuffer. --- client/cmdlft55xx.c | 96 ++++++++++++++++++++++++++++----------------- client/cmdlft55xx.h | 1 + client/ui.c | 15 ++++--- 3 files changed, 71 insertions(+), 41 deletions(-) diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 3820e590..9206fd2a 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -60,15 +60,7 @@ int CmdReadBlk(const char *Cmd) GraphBuffer[j] = ((int)data[j]) ; } GraphTraceLen = LF_TRACE_BUFF_SIZE; - - uint8_t bits[1000] = {0x00}; - uint8_t * bitstream = bits; - - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); - - uint32_t bl0 = PackBits(5, 32, bitstream); - PrintAndLog(" Block %d : 0x%08X %s", Block, bl0, sprint_bin(bitstream+5,32) ); - + CmdIceManchester(Cmd); RepaintGraphWindow(); return 0; } @@ -106,13 +98,7 @@ int CmdReadBlkPWD(const char *Cmd) } GraphTraceLen = LF_TRACE_BUFF_SIZE; - uint8_t bits[1000] = {0x00}; - uint8_t * bitstream = bits; - - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); - - uint32_t bl0 = PackBits(5, 32, bitstream); - PrintAndLog(" Block %d : 0x%08X %s", Block, bl0, sprint_bin(bitstream+5,32) ); + CmdIceManchester(Cmd); RepaintGraphWindow(); return 0; @@ -169,20 +155,32 @@ int CmdWriteBlkPWD(const char *Cmd) int CmdReadTrace(const char *Cmd) { - UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}}; - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); + char cmdp = param_getchar(Cmd, 0); - uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); - - for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]); - //GraphBuffer[j] = ((int)data[j]) - 128; + if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: lf t55xx trace [use data from Graphbuffer]"); + PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); + PrintAndLog(""); + PrintAndLog(" sample: lf t55xx trace"); + PrintAndLog(" sample: lf t55xx trace 1"); + return 0; + } + + if ( strlen(Cmd)==0){ + UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}}; + SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + + uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; + + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); + + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = ((int)data[j]); + } + GraphTraceLen = LF_TRACE_BUFF_SIZE; } - GraphTraceLen = LF_TRACE_BUFF_SIZE; uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; @@ -247,9 +245,22 @@ int CmdInfo(const char *Cmd){ Normal mode Extended mode */ - // läs block 0 - data finns i graphbuff - CmdReadBlk("0"); + char cmdp = param_getchar(Cmd, 0); + + if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: lf t55xx info [use data from Graphbuffer]"); + PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); + PrintAndLog(""); + PrintAndLog(" sample: lf t55xx info"); + PrintAndLog(" sample: lf t55xx info 1"); + return 0; + } + + if ( strlen(Cmd)==0){ + CmdReadBlk("0"); + } + uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; @@ -333,13 +344,27 @@ int CmdDump(const char *Cmd){ } int CmdIceFsk(const char *Cmd){ - //uint8_t bits[1000] = {0x00}; - //uint8_t * bitstream = bits; iceFsk3(GraphBuffer, LF_TRACE_BUFF_SIZE); - RepaintGraphWindow(); return 0; } +int CmdIceManchester(const char *Cmd){ + + int blockNum = -1; + uint32_t blockData; + uint8_t bits[1000] = {0x00}; + uint8_t * bitstream = bits; + + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + blockData = PackBits(5, 32, bitstream); + sscanf(Cmd, "%d", &blockNum); + if ( blockNum > -1){ + PrintAndLog(" Block %d : 0x%08X %s", blockNum, blockData, sprint_bin(bitstream+5,32) ); + }else{ + PrintAndLog(" Decoded : 0x%08X %s", blockData, sprint_bin(bitstream+5,32) ); + } + return 0; +} char * GetBitRateStr(uint32_t id){ static char buf[40]; @@ -455,10 +480,11 @@ static command_t CommandTable[] = {"rdPWD", CmdReadBlkPWD, 0, " -- Read T55xx block data with password mode"}, {"wr", CmdWriteBlk, 0, " -- Write T55xx block data (page 0)"}, {"wrPWD", CmdWriteBlkPWD, 0, " -- Write T55xx block data with password"}, - {"trace", CmdReadTrace, 0, "Read T55xx traceability data (page 1 / blk 0-1)"}, - {"info", CmdInfo, 0, "Read T55xx configuration data (page0 /blk 0)"}, + {"trace", CmdReadTrace, 0, "[1] Read T55xx traceability data (page 1 / blk 0-1) "}, + {"info", CmdInfo, 0, "[1] Read T55xx configuration data (page0 /blk 0)"}, {"dump", CmdDump, 0, "[password] Dump T55xx card block 0-7. optional with password"}, {"fsk", CmdIceFsk, 0, "FSK demod"}, + {"man", CmdIceManchester, 0, "Manchester demod"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index f4fc3640..d5c55f11 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -19,6 +19,7 @@ int CmdWriteBLkPWD(const char *Cmd); int CmdReadTrace(const char *Cmd); int CmdInfo(const char *Cmd); int CmdIceFsk(const char *Cmd); +int CmdIceManchester(const char *Cmd); char * GetBitRateStr(uint32_t id); char * GetSaferStr(uint32_t id); char * GetModulationStr( uint32_t id); diff --git a/client/ui.c b/client/ui.c index 1d85cc05..094b8e56 100644 --- a/client/ui.c +++ b/client/ui.c @@ -116,17 +116,14 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ clock = GetT55x7Clock( data, len, high ); startindex = DetectFirstTransition(data, len, high); - //PrintAndLog(" Clock : %d", clock); - //PrintAndLog(" startindex : %d", startindex); + // PrintAndLog(" Clock : %d", clock); + // PrintAndLog(" startindex : %d", startindex); if (high != 1) bitlength = ManchesterConvertFrom255(data, len, bitStream, high, low, clock, startindex); else bitlength= ManchesterConvertFrom1(data, len, bitStream, clock, startindex); - //if ( bitlength > 0 ) - // PrintPaddedManchester(bitStream, bitlength, clock); - memcpy(dataout, bitStream, bitlength); return bitlength; } @@ -558,8 +555,14 @@ void iceFsk3(int * data, const size_t len){ int stopOne = j-1; int fieldlen = stopOne-startOne; - printf("FIELD Length: %d \n", fieldlen); + 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 len 40 or 50. Aborting..."); + return; + } // FSK sequence start == 000111 int startPos = 0; From 72e930ef3206224ae0ff0696a8a146a0b26268f7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 23 Oct 2014 18:36:44 +0200 Subject: [PATCH 10/78] FIXED: lf t55xx fsk now demods but only to binary. ADD: holimans lf io / hid fskdemod changes. --- armsrc/appmain.c | 38 +++- armsrc/apps.h | 5 +- armsrc/lfops.c | 496 ++++++++++++++++---------------------------- client/cmdhf15.c | 2 +- client/cmdhw.c | 2 +- client/cmdlft55xx.c | 24 +-- client/cmdlft55xx.h | 1 + client/cmdmain.c | 34 ++- client/proxmark3.c | 5 + client/ui.c | 20 +- 10 files changed, 272 insertions(+), 355 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index afed56b7..b9ad1abd 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -24,6 +24,7 @@ #include "legicrf.h" #include "../include/hitag2.h" + #ifdef WITH_LCD #include "LCD.h" #endif @@ -359,6 +360,7 @@ void SamyRun() int selected = 0; int playing = 0; + int cardRead = 0; // Turn on selected LED LED(selected + 1, 0); @@ -374,7 +376,7 @@ void SamyRun() SpinDelay(300); // Button was held for a second, begin recording - if (button_pressed > 0) + if (button_pressed > 0 && cardRead == 0) { LEDsoff(); LED(selected + 1, 0); @@ -400,6 +402,40 @@ void SamyRun() // If we were previously playing, set playing off // so next button push begins playing what we recorded playing = 0; + + cardRead = 1; + + } + + else if (button_pressed > 0 && cardRead == 1) + { + LEDsoff(); + LED(selected + 1, 0); + LED(LED_ORANGE, 0); + + // record + Dbprintf("Cloning %x %x %x", selected, high[selected], low[selected]); + + // wait for button to be released + while(BUTTON_PRESS()) + WDT_HIT(); + + /* need this delay to prevent catching some weird data */ + SpinDelay(500); + + CopyHIDtoT55x7(high[selected], low[selected], 0, 0); + Dbprintf("Cloned %x %x %x", selected, high[selected], low[selected]); + + LEDsoff(); + LED(selected + 1, 0); + // Finished recording + + // If we were previously playing, set playing off + // so next button push begins playing what we recorded + playing = 0; + + cardRead = 0; + } // Change where to record (or begin playing) diff --git a/armsrc/apps.h b/armsrc/apps.h index 6f96875b..a4dd3d08 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -72,7 +72,10 @@ void ToSendReset(void); void ListenReaderField(int limit); void AcquireRawAdcSamples125k(int at134khz); void SnoopLFRawAdcSamples(int divisor, int trigger_threshold); -void DoAcquisition125k(int trigger_threshold); +void DoAcquisition125k_internal(int trigger_threshold, bool silent); +void DoAcquisition125k_threshold(int trigger_threshold); +void DoAcquisition125k(); + extern int ToSendMax; extern uint8_t ToSend[]; extern uint32_t BigBuf[]; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index e086a717..136a1567 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -42,17 +42,17 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) void AcquireRawAdcSamples125k(int divisor) { LFSetupFPGAForADC(divisor, true); - DoAcquisition125k(-1); + DoAcquisition125k(); } void SnoopLFRawAdcSamples(int divisor, int trigger_threshold) { LFSetupFPGAForADC(divisor, false); - DoAcquisition125k(trigger_threshold); + DoAcquisition125k_threshold(trigger_threshold); } // split into two routines so we can avoid timing issues after sending commands // -void DoAcquisition125k(int trigger_threshold) +void DoAcquisition125k_internal(int trigger_threshold, bool silent) { uint8_t *dest = mifare_get_bigbufptr(); int n = 8000; @@ -75,11 +75,18 @@ void DoAcquisition125k(int trigger_threshold) if (++i >= n) break; } } - Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", + if (!silent){ + Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); - + } } - +void DoAcquisition125k_threshold(int trigger_threshold) { + DoAcquisition125k_internal(trigger_threshold, true); +} +void DoAcquisition125k() { + DoAcquisition125k_internal(-1, true); +} + void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) { int at134khz; @@ -138,7 +145,7 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); // now do the read - DoAcquisition125k(-1); + DoAcquisition125k(); } /* blank r/w tag data stream @@ -614,331 +621,206 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol) LED_A_OFF(); } +size_t fsk_demod(uint8_t * dest, size_t size) +{ + uint32_t last_transition = 0; + uint32_t idx = 1; + // we don't care about actual value, only if it's more or less than a + // threshold essentially we capture zero crossings for later analysis + uint8_t threshold_value = 127; + + // sync to first lo-hi transition, and threshold + + //Need to threshold first sample + dest[0] = (dest[0] < threshold_value) ? 0 : 1; + + size_t numBits = 0; + // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8) + // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere + // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10 + for(idx = 1; idx < size; idx++) { + // threshold current value + dest[idx] = (dest[idx] < threshold_value) ? 0 : 1; + + // Check for 0->1 transition + if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition + + dest[numBits] = (idx-last_transition < 9) ? 1 : 0; + last_transition = idx; + numBits++; + } + } + return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 +} + + +size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, uint8_t maxConsequtiveBits ) +{ + uint8_t lastval=dest[0]; + uint32_t idx=0; + size_t numBits=0; + uint32_t n=1; + + for( idx=1; idx < size; idx++) { + + if (dest[idx]==lastval) { + n++; + continue; + } + //if lastval was 1, we have a 1->0 crossing + if ( dest[idx-1] ) { + n=(n+1) / h2l_crossing_value; + } else {// 0->1 crossing + n=(n+1) / l2h_crossing_value; + } + if (n == 0) n = 1; + + if(n < maxConsequtiveBits) + { + memset(dest+numBits, dest[idx-1] , n); + numBits += n; + } + n=0; + lastval=dest[idx]; + }//end for + + return numBits; + +} // loop to capture raw HID waveform then FSK demodulate the TAG ID from it void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { uint8_t *dest = (uint8_t *)BigBuf; - int m=0, n=0, i=0, idx=0, found=0, lastval=0; + + size_t size=0,idx=0; //, found=0; uint32_t hi2=0, hi=0, lo=0; - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + while(!BUTTON_PRESS()) { - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(0,true); - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); - - for(;;) { WDT_HIT(); - if (ledcontrol) - LED_A_ON(); - if(BUTTON_PRESS()) { - DbpString("Stopped"); - if (ledcontrol) - LED_A_OFF(); - return; - } + if (ledcontrol) LED_A_ON(); - i = 0; - m = sizeof(BigBuf); - memset(dest,128,m); - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - if (ledcontrol) - LED_D_ON(); - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - // we don't care about actual value, only if it's more or less than a - // threshold essentially we capture zero crossings for later analysis - if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; - i++; - if (ledcontrol) - LED_D_OFF(); - if(i >= m) { - break; - } - } - } + DoAcquisition125k(); + size = sizeof(BigBuf); // FSK demodulator - - // sync to first lo-hi transition - for( idx=1; idx0 : fc/8 in sets of 6 + // 0->1 : fc/10 in sets of 5 + size = aggregate_bits(dest,size, 6,5,5); + WDT_HIT(); // final loop, go over previously decoded manchester data and decode into usable tag ID // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 - for( idx=0; idx>1) & 0xFFFF); - } - else { - Dbprintf("TAG ID: %x%08x (%d)", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - } - /* if we're only looking for one tag */ - if (findone) - { - *high = hi; - *low = lo; - return; - } - hi2=0; - hi=0; - lo=0; - found=0; - } - } - if (found) { - if (dest[idx] && (!dest[idx+1]) ) { + if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { // frame marker found + idx+=sizeof(frame_marker_mask); + + while(dest[idx] != dest[idx+1] && idx < size-2) + { // Keep going until next frame marker (or error) + // Shift in a bit. Start by shifting high registers hi2=(hi2<<1)|(hi>>31); hi=(hi<<1)|(lo>>31); + //Then, shift in a 0 or one into low + if (dest[idx] && !dest[idx+1]) // 1 0 lo=(lo<<1)|0; - } else if ( (!dest[idx]) && dest[idx+1]) { - hi2=(hi2<<1)|(hi>>31); - hi=(hi<<1)|(lo>>31); - lo=(lo<<1)|1; - } else { - found=0; - hi2=0; - hi=0; - lo=0; + else // 0 1 + lo=(lo<<1)| + 1; + numshifts ++; + idx += 2; } - idx++; - } - if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) ) - { - found=1; - idx+=6; - if (found && (hi|lo)) { - if (hi2 != 0){ - Dbprintf("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - } - else { - Dbprintf("TAG ID: %x%08x (%d)", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - } - /* if we're only looking for one tag */ - if (findone) - { - *high = hi; - *low = lo; - return; + //Dbprintf("Num shifts: %d ", numshifts); + // Hopefully, we read a tag and hit upon the next frame marker + if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { + if (hi2 != 0){ + Dbprintf("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + } + else { + Dbprintf("TAG ID: %x%08x (%d)", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); } - hi2=0; - hi=0; - lo=0; - found=0; } + + // reset + hi2 = hi = lo = 0; + numshifts = 0; + }else + { + idx++; } } WDT_HIT(); + } + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); } +uint32_t bytebits_to_byte(uint8_t* src, int numbits) +{ + uint32_t num = 0; + for(int i = 0 ; i < numbits ; i++) + { + num = (num << 1) | (*src); + src++; + } + return num; +} + + void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = mifare_get_bigbufptr(); - int m=0, n=0, i=0, idx=0, lastval=0; - int found=0; + uint8_t *dest = (uint8_t *)BigBuf; + + size_t size=0, idx=0; uint32_t code=0, code2=0; - LFSetupFPGAForADC(0, true); - for(;;) { + while(!BUTTON_PRESS()) { + + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(0,true); + WDT_HIT(); - if (ledcontrol) - LED_A_ON(); - if(BUTTON_PRESS()) { - DbpString("Stopped"); - if (ledcontrol) - LED_A_OFF(); - return; - } + if (ledcontrol) LED_A_ON(); - i = 0; - m = 30000; - memset(dest,128,m); - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - if (ledcontrol) - LED_D_ON(); - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - // we don't care about actual value, only if it's more or less than a - // threshold essentially we capture zero crossings for later analysis - dest[i] = (dest[i] < 127) ? 0 : 1; - ++i; - if (ledcontrol) - LED_D_OFF(); - if(i >= m) - break; - } - } + DoAcquisition125k(true); + size = sizeof(BigBuf); // FSK demodulator - - // sync to first lo-hi transition - for( idx=1; idx0 : fc/8 in sets of 7 + // 0->1 : fc/10 in sets of 6 + size = aggregate_bits(dest, size, 7,6,13); - // stuff appropriate bits in buffer - if ( n==0 ) - dest[i++]=dest[idx-1]^1; - else { - if ( n < 13){ - for(int j=0; j -- Drive LF antenna at 12Mhz/(divisor+1)"}, {"setmux", CmdSetMux, 0, " -- Set the ADC mux to a specific value"}, {"tune", CmdTune, 0, "Measure antenna tuning"}, - {"version", CmdVersion, 0, "Show version inforation about the connected Proxmark"}, + {"version", CmdVersion, 0, "Show version information about the connected Proxmark"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 9206fd2a..8420465b 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -28,9 +28,7 @@ static int CmdHelp(const char *Cmd); int CmdReadBlk(const char *Cmd) { - //default to invalid block int Block = -1; - UsbCommand c; sscanf(Cmd, "%d", &Block); @@ -39,10 +37,8 @@ int CmdReadBlk(const char *Cmd) return 1; } - //PrintAndLog(" Reading page 0 block : %d", Block); - // this command fills up BigBuff - // + UsbCommand c; c.cmd = CMD_T55XX_READ_BLOCK; c.d.asBytes[0] = 0x00; c.arg[0] = 0; @@ -57,10 +53,10 @@ int CmdReadBlk(const char *Cmd) WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]) ; + GraphBuffer[j] = (int)data[j]; } GraphTraceLen = LF_TRACE_BUFF_SIZE; - CmdIceManchester(Cmd); + CmdIceManchester(Block); RepaintGraphWindow(); return 0; } @@ -97,9 +93,7 @@ int CmdReadBlkPWD(const char *Cmd) GraphBuffer[j] = ((int)data[j]) - 128; } GraphTraceLen = LF_TRACE_BUFF_SIZE; - - CmdIceManchester(Cmd); - + CmdIceManchester(Block); RepaintGraphWindow(); return 0; } @@ -349,6 +343,10 @@ int CmdIceFsk(const char *Cmd){ return 0; } int CmdIceManchester(const char *Cmd){ + ManchesterDemod( -1); + return 0; +} +int ManchesterDemod(int block){ int blockNum = -1; uint32_t blockData; @@ -357,9 +355,9 @@ int CmdIceManchester(const char *Cmd){ manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); blockData = PackBits(5, 32, bitstream); - sscanf(Cmd, "%d", &blockNum); + if ( blockNum > -1){ - PrintAndLog(" Block %d : 0x%08X %s", blockNum, blockData, sprint_bin(bitstream+5,32) ); + PrintAndLog(" Block %d : 0x%08X %s", blockNum, blockData, sprint_bin(bitstream+5,32) ); }else{ PrintAndLog(" Decoded : 0x%08X %s", blockData, sprint_bin(bitstream+5,32) ); } @@ -484,7 +482,7 @@ static command_t CommandTable[] = {"info", CmdInfo, 0, "[1] Read T55xx configuration data (page0 /blk 0)"}, {"dump", CmdDump, 0, "[password] Dump T55xx card block 0-7. optional with password"}, {"fsk", CmdIceFsk, 0, "FSK demod"}, - {"man", CmdIceManchester, 0, "Manchester demod"}, + {"man", CmdIceManchester, 0, "Manchester demod (with SST)"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index d5c55f11..8c0cdf58 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -20,6 +20,7 @@ int CmdReadTrace(const char *Cmd); int CmdInfo(const char *Cmd); int CmdIceFsk(const char *Cmd); int CmdIceManchester(const char *Cmd); +int ManchesterDemod(int block); char * GetBitRateStr(uint32_t id); char * GetSaferStr(uint32_t id); char * GetModulationStr( uint32_t id); diff --git a/client/cmdmain.c b/client/cmdmain.c index c56aaa63..bf69c5ad 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -26,6 +26,10 @@ #include "util.h" #include "cmdscript.h" +int delta125[2]; +int delta134[2]; +int deltahf[2]; +int deltaReset = 0; unsigned int current_command = CMD_UNKNOWN; //unsigned int received_command = CMD_UNKNOWN; @@ -210,13 +214,30 @@ void UsbCommandReceived(UsbCommand *UC) int vLf125, vLf134, vHf; vLf125 = UC->arg[0] & 0xffff; vLf134 = UC->arg[0] >> 16; - vHf = UC->arg[1] & 0xffff;; - peakf = UC->arg[2] & 0xffff; - peakv = UC->arg[2] >> 16; + vHf = UC->arg[1] & 0xffff;; + peakf = UC->arg[2] & 0xffff; + peakv = UC->arg[2] >> 16; + + //Reset delta trigger every 3:d time + + if ( deltaReset == 4){ + delta125[0] = vLf125; + delta134[0] = vLf134; + deltahf[0] = vHf; + } else if ( deltaReset == 2){ + delta125[1] = vLf125; + delta134[1] = vLf134; + deltahf[1] = vHf; + } + + if ( deltaReset == 0){ + + } + PrintAndLog(""); PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0); PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0); - PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1)); + PrintAndLog("# LF optimal: %5.2f V @ %9.2f kHz", peakv/1000.0, 12000.0/(peakf+1)); PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0); if (peakv<2000) PrintAndLog("# Your LF antenna is unusable."); @@ -226,7 +247,10 @@ void UsbCommandReceived(UsbCommand *UC) PrintAndLog("# Your HF antenna is unusable."); else if (vHf<5000) PrintAndLog("# Your HF antenna is marginal."); - } break; + } + + deltaReset = (deltaReset == 0) ? 4 : deltaReset>>1; + break; case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: { // printf("received samples: "); diff --git a/client/proxmark3.c b/client/proxmark3.c index a9819b54..d2bb2011 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -48,6 +48,11 @@ void SendCommand(UsbCommand *c) { return; } + /** + The while-loop below causes hangups at times, when the pm3 unit is unresponsive + 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; diff --git a/client/ui.c b/client/ui.c index 094b8e56..59ca72dc 100644 --- a/client/ui.c +++ b/client/ui.c @@ -116,8 +116,8 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ clock = GetT55x7Clock( data, len, high ); startindex = DetectFirstTransition(data, len, high); - // PrintAndLog(" Clock : %d", clock); - // PrintAndLog(" startindex : %d", startindex); + PrintAndLog(" Clock : %d", clock); + PrintAndLog(" startindex : %d", startindex); if (high != 1) bitlength = ManchesterConvertFrom255(data, len, bitStream, high, low, clock, startindex); @@ -579,25 +579,21 @@ void iceFsk3(int * data, const size_t len){ printf("000111 position: %d \n", startPos); - startPos += 6*fieldlen+1; + startPos += 6*fieldlen+5; + int bit =0; printf("BINARY\n"); printf("R/40 : "); for (i =startPos ; i < len; i += 40){ - if ( data[i] > 0 ) - printf("1"); - else - printf("0"); + bit = data[i]>0 ? 1:0; + printf("%d", bit ); } printf("\n"); printf("R/50 : "); for (i =startPos ; i < len; i += 50){ - if ( data[i] > 0 ) - printf("1"); - else - printf("0"); - } + bit = data[i]>0 ? 1:0; + printf("%d", bit ); } printf("\n"); } From c2d25819d8c55b568814da61d116fda9b4ad53d1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 24 Oct 2014 00:04:56 +0200 Subject: [PATCH 11/78] BUG: the lf read now uses "getbigbuffer" which the offset from where the data starts in "data samples nnnnn" needed to be set. ADD: ioprox nxp identifikations --- client/cmddata.c | 4 ++-- client/cmdhf15.c | 6 +++-- client/cmdlf.c | 6 +++-- client/cmdlfem4x.c | 54 ++++++++++++++++++++------------------------- client/cmdlft55xx.c | 8 +++---- 5 files changed, 38 insertions(+), 40 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index e7be9884..f5b9fc9c 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -464,8 +464,8 @@ int CmdSamples(const char *Cmd) if (n == 0) n = 512; if (n > sizeof(got)) n = sizeof(got); - PrintAndLog("Reading %d samples\n", n); - GetFromBigBuf(got,n,0); + PrintAndLog("Reading %d samples from device memory\n", n); + GetFromBigBuf(got,n,3560); WaitForResponse(CMD_ACK,NULL); for (int j = 0; j < n; j++) { GraphBuffer[cnt++] = ((int)got[j]) - 128; diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 1ee04e1b..bdc08521 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -59,8 +59,10 @@ const productName uidmapping[] = { { 0xE001000000000000LL, 16, "Motorola" }, { 0xE002000000000000LL, 16, "ST Microelectronics" }, { 0xE003000000000000LL, 16, "Hitachi" }, - { 0xE004000000000000LL, 16, "Philips" }, - { 0xE004010000000000LL, 24, "Philips; IC SL2 ICS20" }, + { 0xE004000000000000LL, 16, "NXP(Philips)" }, + { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)" }, + { 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" }, + { 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" }, { 0xE005000000000000LL, 16, "Infineon" }, { 0xE005400000000000LL, 24, "Infineon; 56x32bit" }, { 0xE006000000000000LL, 16, "Cylinc" }, diff --git a/client/cmdlf.c b/client/cmdlf.c index 2306121b..a198e1e1 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -363,7 +363,9 @@ int CmdLFRead(const char *Cmd) } else if (*Cmd == '\0') { c.arg[0] = 0; } else if (sscanf(Cmd, "%"lli, &c.arg[0]) != 1) { - PrintAndLog("use 'read' or 'read h', or 'read '"); + PrintAndLog("Samples 1: 'lf read'"); + PrintAndLog(" 2: 'lf read h'"); + PrintAndLog(" 3: 'lf read '"); return 0; } SendCommand(&c); @@ -566,7 +568,7 @@ static command_t CommandTable[] = {"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, 1, " ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"}, + {"indalaclone", CmdIndalaClone, 1, " ['l']-- Clone Indala to T55x7 (UID in HEX)(option 'l' for 224 UID"}, {"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"}, diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 8380bcba..0449e34a 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -255,38 +255,32 @@ int CmdEM410xSim(const char *Cmd) return 0; } -/* Function is equivalent of loread + losamples + em410xread - * looped until an EM410x tag is detected */ +/* Function is equivalent of lf read + data samples + em410xread + * looped until an EM410x tag is detected + * + * Why is CmdSamples("16000")? + * TBD: Auto-grow sample size based on detected sample rate. IE: If the + * rate gets lower, then grow the number of samples + * Changed by martin, 4000 x 4 = 16000, + * see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235 + +*/ int CmdEM410xWatch(const char *Cmd) { - int read_h = (*Cmd == 'h'); - //char k; - do - { - CmdLFRead(read_h ? "h" : ""); - // 2000 samples is OK for clock=64, but not clock=32. Probably want - // 8000 for clock=16. Don't want to go too high since old HID driver - // is very slow - // TBD: Auto-grow sample size based on detected sample rate. IE: If the - // rate gets lower, then grow the number of samples - - // Changed by martin, 4000 x 4 = 16000, - // see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235 - CmdSamples("16000"); - } while ( + int read_h = (*Cmd == 'h'); + do + { + CmdLFRead(read_h ? "h" : ""); + CmdSamples("16000"); + } while ( !CmdEM410xRead("") ); - return 0; + return 0; } int CmdEM410xWatchnSpoof(const char *Cmd) { - int read_h = (*Cmd == 'h'); - do - { - CmdLFRead(read_h ? "h" : ""); - CmdSamples("16000"); - } while ( ! CmdEM410xRead("")); + CmdEM410xWatch(Cmd); PrintAndLog("# Replaying : %s",global_em410xId); CmdEM410xSim(global_em410xId); return 0; @@ -636,12 +630,12 @@ int CmdWriteWordPWD(const char *Cmd) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"410read", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, - {"410sim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, - {"410watch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, - {"410spoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, - {"410write", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, - {"4xread", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, + {"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, + {"410xsim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, + {"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, + {"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, + {"410xwrite", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, + {"4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, {"rd", CmdReadWord, 1, " -- Read EM4xxx word data"}, {"rdpwd", CmdReadWordPWD, 1, " -- Read EM4xxx word data in password mode "}, {"wr", CmdWriteWord, 1, " -- Write EM4xxx word data"}, diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 8420465b..63cc2ee4 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -56,7 +56,7 @@ int CmdReadBlk(const char *Cmd) GraphBuffer[j] = (int)data[j]; } GraphTraceLen = LF_TRACE_BUFF_SIZE; - CmdIceManchester(Block); + ManchesterDemod(Block); RepaintGraphWindow(); return 0; } @@ -93,7 +93,7 @@ int CmdReadBlkPWD(const char *Cmd) GraphBuffer[j] = ((int)data[j]) - 128; } GraphTraceLen = LF_TRACE_BUFF_SIZE; - CmdIceManchester(Block); + ManchesterDemod(Block); RepaintGraphWindow(); return 0; } @@ -475,9 +475,9 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"rd", CmdReadBlk, 0, " -- Read T55xx block data (page 0)"}, - {"rdPWD", CmdReadBlkPWD, 0, " -- Read T55xx block data with password mode"}, + {"rdpwd", CmdReadBlkPWD, 0, " -- Read T55xx block data with password mode"}, {"wr", CmdWriteBlk, 0, " -- Write T55xx block data (page 0)"}, - {"wrPWD", CmdWriteBlkPWD, 0, " -- Write T55xx block data with password"}, + {"wrpwd", CmdWriteBlkPWD, 0, " -- Write T55xx block data with password"}, {"trace", CmdReadTrace, 0, "[1] Read T55xx traceability data (page 1 / blk 0-1) "}, {"info", CmdInfo, 0, "[1] Read T55xx configuration data (page0 /blk 0)"}, {"dump", CmdDump, 0, "[password] Dump T55xx card block 0-7. optional with password"}, From 081151eabb3728d4db4e5cca0cab2b2e397e3851 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 24 Oct 2014 15:34:50 +0200 Subject: [PATCH 12/78] FIX: data mandemod read the wrong part of BigBuffer (no correct offset) --- client/cmddata.c | 36 +++++++------- client/cmdlfhitag.c | 6 +-- client/cmdlft55xx.c | 46 +++++++++--------- client/ui.c | 114 ++++++++------------------------------------ client/ui.h | 1 - 5 files changed, 62 insertions(+), 141 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index f5b9fc9c..c58f6f62 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -456,25 +456,23 @@ int CmdHpf(const char *Cmd) int CmdSamples(const char *Cmd) { - int cnt = 0; - int n; - uint8_t got[40000]; - - n = strtol(Cmd, NULL, 0); - if (n == 0) n = 512; - if (n > sizeof(got)) n = sizeof(got); + uint8_t got[36440] = {0x00}; + + int n = strtol(Cmd, NULL, 0); + if (n == 0) + n = 512; + if (n > sizeof(got)) + n = sizeof(got); - PrintAndLog("Reading %d samples from device memory\n", n); - GetFromBigBuf(got,n,3560); - WaitForResponse(CMD_ACK,NULL); - for (int j = 0; j < n; j++) { - GraphBuffer[cnt++] = ((int)got[j]) - 128; - } - - PrintAndLog("Done!\n"); - GraphTraceLen = n; - RepaintGraphWindow(); - return 0; + PrintAndLog("Reading %d samples from device memory\n", n); + GetFromBigBuf(got,n,3560); + WaitForResponse(CMD_ACK,NULL); + for (int j = 0; j < n; ++j) { + GraphBuffer[j] = ((int)got[j]) - 128; + } + GraphTraceLen = n; + RepaintGraphWindow(); + return 0; } int CmdLoad(const char *Cmd) @@ -684,7 +682,7 @@ int CmdManchesterDemod(const char *Cmd) // We cannot end up in this state, this means we are unsynchronized, // move up 1 bit: i++; - warnings++; + warnings++; PrintAndLog("Unsynchronized, resync..."); PrintAndLog("(too many of those messages mean the stream is not Manchester encoded)"); diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 038ec887..331f2c87 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -230,7 +230,7 @@ int CmdLFHitagReader(const char *Cmd) { return 0; } -static command_t CommandTableHitag[] = +static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"list", CmdLFHitagList, 1, "List Hitag trace history"}, @@ -242,12 +242,12 @@ static command_t CommandTableHitag[] = int CmdLFHitag(const char *Cmd) { - CmdsParse(CommandTableHitag, Cmd); + CmdsParse(CommandTable, Cmd); return 0; } int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTableHitag); + CmdsHelp(CommandTable); return 0; } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 63cc2ee4..5804fbc7 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -29,7 +29,6 @@ static int CmdHelp(const char *Cmd); int CmdReadBlk(const char *Cmd) { int Block = -1; - sscanf(Cmd, "%d", &Block); if ((Block > 7) | (Block < 0)) { @@ -37,7 +36,6 @@ int CmdReadBlk(const char *Cmd) return 1; } - // this command fills up BigBuff UsbCommand c; c.cmd = CMD_T55XX_READ_BLOCK; c.d.asBytes[0] = 0x00; @@ -47,17 +45,18 @@ int CmdReadBlk(const char *Cmd) SendCommand(&c); WaitForResponse(CMD_ACK, NULL); - uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; +// uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); + // GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + // WaitForResponseTimeout(CMD_ACK,NULL, 1500); - for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = (int)data[j]; - } - GraphTraceLen = LF_TRACE_BUFF_SIZE; + // for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + // GraphBuffer[j] = (int)data[j]; + // } + // GraphTraceLen = LF_TRACE_BUFF_SIZE; + CmdSamples("12000"); ManchesterDemod(Block); - RepaintGraphWindow(); + // RepaintGraphWindow(); return 0; } @@ -90,7 +89,7 @@ int CmdReadBlkPWD(const char *Cmd) WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]) - 128; + GraphBuffer[j] = ((int)data[j]); } GraphTraceLen = LF_TRACE_BUFF_SIZE; ManchesterDemod(Block); @@ -155,8 +154,8 @@ int CmdReadTrace(const char *Cmd) PrintAndLog("Usage: lf t55xx trace [use data from Graphbuffer]"); PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); PrintAndLog(""); - PrintAndLog(" sample: lf t55xx trace"); - PrintAndLog(" sample: lf t55xx trace 1"); + PrintAndLog(" sample: lf t55xx trace"); + PrintAndLog(" sample: lf t55xx trace 1"); return 0; } @@ -245,15 +244,14 @@ int CmdInfo(const char *Cmd){ PrintAndLog("Usage: lf t55xx info [use data from Graphbuffer]"); PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); PrintAndLog(""); - PrintAndLog(" sample: lf t55xx info"); - PrintAndLog(" sample: lf t55xx info 1"); + PrintAndLog(" sample: lf t55xx info"); + PrintAndLog(" sample: lf t55xx info 1"); return 0; } if ( strlen(Cmd)==0){ CmdReadBlk("0"); - } - + } uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; @@ -349,18 +347,20 @@ int CmdIceManchester(const char *Cmd){ int ManchesterDemod(int block){ int blockNum = -1; + uint8_t sizebyte = 32; + uint8_t offset = 5; uint32_t blockData; uint8_t bits[1000] = {0x00}; uint8_t * bitstream = bits; manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); - blockData = PackBits(5, 32, bitstream); + blockData = PackBits(offset, sizebyte, bitstream); - if ( blockNum > -1){ - PrintAndLog(" Block %d : 0x%08X %s", blockNum, blockData, sprint_bin(bitstream+5,32) ); - }else{ - PrintAndLog(" Decoded : 0x%08X %s", blockData, sprint_bin(bitstream+5,32) ); - } + if ( blockNum < 0) + PrintAndLog(" Decoded : 0x%08X %s", blockData, sprint_bin(bitstream+offset,sizebyte) ); + else + PrintAndLog(" Block %d : 0x%08X %s", blockNum, blockData, sprint_bin(bitstream+offset,sizebyte) ); + return 0; } diff --git a/client/ui.c b/client/ui.c index 59ca72dc..5d05da96 100644 --- a/client/ui.c +++ b/client/ui.c @@ -18,7 +18,8 @@ #include #include "loclass/cipherutils.h" #include "ui.h" - +#include "cmdmain.h" +#include "cmddata.h" //#include #define M_PI 3.14159265358979323846264338327 @@ -117,7 +118,7 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ startindex = DetectFirstTransition(data, len, high); PrintAndLog(" Clock : %d", clock); - PrintAndLog(" startindex : %d", startindex); + //PrintAndLog(" startindex : %d", startindex); if (high != 1) bitlength = ManchesterConvertFrom255(data, len, bitStream, high, low, clock, startindex); @@ -235,8 +236,7 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ // 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++) - { + for (j = 0; j < clock; j++) { if ( (data[z+j] <= dampHi && data[z+j] >= dampLow) ){ @@ -392,83 +392,6 @@ void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){ PrintAndLog(" %s", sprint_bin(bitStream+i, mod) ); } -void iceFsk(int * data, const size_t len){ - - //34359738 == 125khz (2^32 / 125) = - - // parameters - float phase_offset = 0.00f; // carrier phase offset - float frequency_offset = 0.30f; // carrier frequency offset - float wn = 0.01f; // pll bandwidth - float zeta = 0.707f; // pll damping factor - float K = 1000; // pll loop gain - size_t n = len; // number of samples - - // generate loop filter parameters (active PI design) - float t1 = K/(wn*wn); // tau_1 - float t2 = 2*zeta/wn; // tau_2 - - // feed-forward coefficients (numerator) - float b0 = (4*K/t1)*(1.+t2/2.0f); - float b1 = (8*K/t1); - float b2 = (4*K/t1)*(1.-t2/2.0f); - - // feed-back coefficients (denominator) - // a0 = 1.0 is implied - float a1 = -2.0f; - float a2 = 1.0f; - - // filter buffer - float v0=0.0f, v1=0.0f, v2=0.0f; - - // initialize states - float phi = phase_offset; // input signal's initial phase - float phi_hat = 0.0f; // PLL's initial phase - - unsigned int i; - float complex x,y; - float complex output[n]; - - for (i=0; i0 ? 1:0; printf("%d", bit ); } printf("\n"); printf("R/50 : "); - for (i =startPos ; i < len; i += 50){ + for (i =startPos ; i < adjustedLen; i += 50){ bit = data[i]>0 ? 1:0; printf("%d", bit ); } printf("\n"); diff --git a/client/ui.h b/client/ui.h index 666d7002..8d16e059 100644 --- a/client/ui.h +++ b/client/ui.h @@ -34,7 +34,6 @@ 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 high, int low, int clock, int startIndex); int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout, int clock, int startIndex); -void iceFsk(int * data, const size_t len); void iceFsk2(int * data, const size_t len); void iceFsk3(int * data, const size_t len); #endif From 149aeadaa609b01db86ba3b4ee23b317f16bede5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 26 Oct 2014 21:25:06 +0100 Subject: [PATCH 13/78] Minor bug fixes with help from Holiman. FIX: sprint_hex, sprint_bin has better length detection. FIX: ui.c has removed all c99 array declarations, with malloc FIX: hfmfmfu.c wrong length in one array caused crashes in CmdHF14AMfURdCard FIX: cmdlft55xx.c CmdDump has now a correct pwd string. --- client/cmdhfmfu.c | 69 +++++++++++++++++++++------------------------ client/cmdlft55xx.c | 11 ++++---- client/ui.c | 21 ++++++++------ client/util.c | 8 ++++-- 4 files changed, 56 insertions(+), 53 deletions(-) diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 3b9f2e6d..72eb8895 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -24,9 +24,9 @@ static int CmdHelp(const char *Cmd); // Mifare Ultralight Write Single Block // int CmdHF14AMfUWrBl(const char *Cmd){ - uint8_t blockNo = 0; - bool chinese_card=0; - uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t blockNo = 0; + bool chinese_card = 0; + uint8_t bldata[16] = {0x00}; UsbCommand resp; if (strlen(Cmd)<3) { @@ -173,10 +173,10 @@ int CmdHF14AMfURdCard(const char *Cmd){ uint8_t BlockNo = 0; int Pages=16; uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0,0}; - bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t lockbytes[2]={0x00}; + bool bit[16]={0x00}; bool dump=false; - uint8_t datatemp[5]={0,0,0,0,0}; + uint8_t datatemp[7]= {0x00}; uint8_t isOK = 0; uint8_t * data = NULL; @@ -327,19 +327,17 @@ int CmdHF14AMfURdCard(const char *Cmd){ int CmdHF14AMfUDump(const char *Cmd){ int i; - uint8_t BlockNo = 0; - int Pages=16; - uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0,0}; - bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - bool dump=false; - uint8_t datatemp[5]={0,0,0,0,0}; - - uint8_t isOK = 0; - uint8_t * data = NULL; + uint8_t BlockNo = 0; + int Pages = 16; + uint8_t *lockbytes_t = NULL; + uint8_t lockbytes[2] = {0x00}; + bool bit[16] = {0x00}; + uint8_t datatemp[5] = {0x00}; + bool dump = true; + uint8_t isOK = 0; + uint8_t * data = NULL; FILE *fout; - dump=true; if ((fout = fopen("dump_ultralight_data.bin","wb")) == NULL) { PrintAndLog("Could not create file name dumpdata.bin"); return 1; @@ -468,12 +466,12 @@ void rol (uint8_t *data, const size_t len){ int CmdHF14AMfucAuth(const char *Cmd){ uint8_t blockNo = 0, keyNo=0; - uint8_t e_RndB[8]; + uint8_t e_RndB[8] = {0x00}; uint32_t cuid=0; - unsigned char RndARndB[16]; - uint8_t key[16]; + unsigned char RndARndB[16] = {0x00}; + uint8_t key[16] = {0x00}; DES_cblock RndA, RndB; - DES_cblock iv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + DES_cblock iv[8] = {0x00}; DES_key_schedule ks1,ks2; DES_cblock key1,key2; @@ -566,7 +564,6 @@ int CmdHF14AMfucAuth(const char *Cmd){ // int CmdHF14AMfUCRdBl(const char *Cmd) { - uint8_t blockNo = 0; if (strlen(Cmd)<1) { @@ -607,14 +604,13 @@ int CmdHF14AMfUCRdCard(const char *Cmd){ uint8_t BlockNo = 0; int Pages=44; uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0,0}; + uint8_t lockbytes[2]={0x00}; uint8_t *lockbytes_t2=NULL; - uint8_t lockbytes2[2]={0,0}; - bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - bool bit2[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t lockbytes2[2]={0x00}; + bool bit[16]={0x00}; + bool bit2[16]={0x00}; bool dump=false; - uint8_t datatemp[5]={0,0,0,0,0}; - + uint8_t datatemp[5]={0x00}; uint8_t isOK = 0; uint8_t * data = NULL; FILE *fout = NULL; @@ -817,19 +813,18 @@ int CmdHF14AMfUCDump(const char *Cmd){ uint8_t BlockNo = 0; int Pages=44; uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0,0}; + uint8_t lockbytes[2]={0x00}; uint8_t *lockbytes_t2=NULL; - uint8_t lockbytes2[2]={0,0}; - bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - bool bit2[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - bool dump=false; - uint8_t datatemp[5]={0,0,0,0,0}; + uint8_t lockbytes2[2]={0x00}; + bool bit[16]={0x00}; + bool bit2[16]={0x00}; + bool dump=true; + uint8_t datatemp[5]={0x00}; uint8_t isOK = 0; uint8_t * data = NULL; FILE *fout; - dump=true; if ((fout = fopen("dump_ultralightc_data.bin","wb")) == NULL) { PrintAndLog("Could not create file name dumpdata.bin"); return 1; @@ -1024,8 +1019,8 @@ int CmdHF14AMfUCDump(const char *Cmd){ int CmdHF14AMfUCWrBl(const char *Cmd){ uint8_t blockNo = 0; - bool chinese_card=0; - uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + bool chinese_card = 0; + uint8_t bldata[16] = {0x00}; UsbCommand resp; if (strlen(Cmd)<3) { diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 5804fbc7..31261a4f 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -306,14 +306,13 @@ int CmdDump(const char *Cmd){ char cmdp = param_getchar(Cmd, 0); char s[20]; uint8_t pwd[4] = {0x00}; - - if (strlen(Cmd)>1 || cmdp == 'h' || cmdp == 'H') { + bool hasPwd = ( strlen(Cmd) > 0); + + if ( cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: lf t55xx dump "); PrintAndLog(" sample: lf t55xx dump FFFFFFFF"); return 0; } - - bool hasPwd = ( strlen(Cmd) > 0); if ( hasPwd ){ if (param_gethex(Cmd, 0, pwd, 4)) { @@ -323,9 +322,9 @@ int CmdDump(const char *Cmd){ } for ( int i = 0; i <8; ++i){ - *s = 0; + memset(s,0,sizeof(s)); if ( hasPwd ) { - sprintf(s,"%d %d", i, pwd); + sprintf(s,"%d %s", i, sprint_hex(pwd,4)); CmdReadBlkPWD(s); } else { sprintf(s,"%d", i); diff --git a/client/ui.c b/client/ui.c index 5d05da96..966ab2ca 100644 --- a/client/ui.c +++ b/client/ui.c @@ -101,8 +101,7 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ int i, clock, high, low, startindex; low = startindex = 0; high = 1; - uint8_t bitStream[len]; - + uint8_t * bitStream = (uint8_t* ) malloc(sizeof(uint8_t) * len); memset(bitStream, 0x00, len); /* Detect high and lows */ @@ -118,14 +117,14 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ startindex = DetectFirstTransition(data, len, high); PrintAndLog(" Clock : %d", clock); - //PrintAndLog(" startindex : %d", startindex); - + if (high != 1) bitlength = ManchesterConvertFrom255(data, len, bitStream, high, low, clock, startindex); else bitlength= ManchesterConvertFrom1(data, len, bitStream, clock, startindex); memcpy(dataout, bitStream, bitlength); + free(bitStream); return bitlength; } @@ -398,8 +397,9 @@ void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){ void iceFsk2(int * data, const size_t len){ int i, j; - int output[len]; - + int * output = (int* ) malloc(sizeof(int) * len); + memset(output, 0x00, len); + // for (i=0; i 1024/3) ? 1024/3 : len; static char buf[1024]; char * tmp = buf; size_t i; - for (i=0; i < len && i < 1024/3; i++, tmp += 3) + for (i=0; i < maxLen; ++i, tmp += 3) sprintf(tmp, "%02x ", data[i]); return buf; } char * sprint_bin(const uint8_t * data, const size_t len) { + + int maxLen = ( len > 1024) ? 1024 : len; static char buf[1024]; char * tmp = buf; size_t i; - for (i=0; i < len && i < 1024; i++, tmp++) + for (i=0; i < maxLen; ++i, ++tmp) sprintf(tmp, "%u", data[i]); return buf; From db297e69e116369d7f5cdadcff69a0425b4e61de Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 26 Oct 2014 21:30:29 +0100 Subject: [PATCH 14/78] BUG: fixed a bug with the initialization of IV in cmdhfmfu.c CmdHF14AMfucAuth --- client/cmdhfmfu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 72eb8895..afe54bb4 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -471,10 +471,13 @@ int CmdHF14AMfucAuth(const char *Cmd){ unsigned char RndARndB[16] = {0x00}; uint8_t key[16] = {0x00}; DES_cblock RndA, RndB; - DES_cblock iv[8] = {0x00}; + DES_cblock iv; DES_key_schedule ks1,ks2; DES_cblock key1,key2; + // + memset(iv, 0, 8); + if (strlen(Cmd)<1) { PrintAndLog("Usage: hf mfu auth k "); PrintAndLog(" sample: hf mfu auth k 0"); From c6be64da095246620420500857f1f34994b769a8 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 26 Oct 2014 23:16:25 +0100 Subject: [PATCH 15/78] Some more nasty bugs fixed in the lf t55xx manchester_decode method. ADD: a little function to see if GraphBuffer is not used. --- client/cmdlfem4x.c | 12 ++++++------ client/cmdlft55xx.c | 31 ++++++++++++++++++------------- client/cmdmain.c | 4 ++-- client/graph.c | 13 +++++++++++++ client/graph.h | 2 +- client/ui.c | 20 +++++++++++--------- client/ui.h | 6 +++--- 7 files changed, 54 insertions(+), 34 deletions(-) diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 0449e34a..1ce937d9 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -22,6 +22,7 @@ #include "util.h" #include "data.h" #define LF_TRACE_BUFF_SIZE 12000 +#define LF_BITSSTREAM_LEN 1000 char *global_em410xId; @@ -530,9 +531,9 @@ int CmdReadWord(const char *Cmd) } GraphTraceLen = LF_TRACE_BUFF_SIZE; - uint8_t bits[1000] = {0x00}; + uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; uint8_t * bitstream = bits; - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream,LF_BITSSTREAM_LEN); RepaintGraphWindow(); return 0; } @@ -570,10 +571,9 @@ int CmdReadWordPWD(const char *Cmd) } GraphTraceLen = LF_TRACE_BUFF_SIZE; - uint8_t bits[1000] = {0x00}; - uint8_t * bitstream = bits; - - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; + uint8_t * bitstream = bits; + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); RepaintGraphWindow(); return 0; } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 31261a4f..09ba1ee7 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -23,15 +23,16 @@ #define LF_TRACE_BUFF_SIZE 12000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) +#define LF_BITSSTREAM_LEN 1000 // more then 1000 bits shouldn't happend.. 8block * 4 bytes * 8bits = static int CmdHelp(const char *Cmd); int CmdReadBlk(const char *Cmd) { - int Block = -1; - sscanf(Cmd, "%d", &Block); + int block = -1; + sscanf(Cmd, "%d", &block); - if ((Block > 7) | (Block < 0)) { + if ((block > 7) | (block < 0)) { PrintAndLog("Block must be between 0 and 7"); return 1; } @@ -55,7 +56,7 @@ int CmdReadBlk(const char *Cmd) // } // GraphTraceLen = LF_TRACE_BUFF_SIZE; CmdSamples("12000"); - ManchesterDemod(Block); + ManchesterDemod(block); // RepaintGraphWindow(); return 0; } @@ -175,10 +176,10 @@ int CmdReadTrace(const char *Cmd) GraphTraceLen = LF_TRACE_BUFF_SIZE; } - uint8_t bits[1000] = {0x00}; + uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; uint8_t * bitstream = bits; - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); RepaintGraphWindow(); uint8_t si = 5; @@ -253,10 +254,10 @@ int CmdInfo(const char *Cmd){ CmdReadBlk("0"); } - uint8_t bits[1000] = {0x00}; + uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; uint8_t * bitstream = bits; - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); uint8_t si = 5; uint32_t bl0 = PackBits(si, 32, bitstream); @@ -324,7 +325,7 @@ int CmdDump(const char *Cmd){ for ( int i = 0; i <8; ++i){ memset(s,0,sizeof(s)); if ( hasPwd ) { - sprintf(s,"%d %s", i, sprint_hex(pwd,4)); + sprintf(s,"%d %02x%02x%02x%02x", i, pwd[0],pwd[1],pwd[2],pwd[3]); CmdReadBlkPWD(s); } else { sprintf(s,"%d", i); @@ -335,6 +336,9 @@ int CmdDump(const char *Cmd){ } int CmdIceFsk(const char *Cmd){ + + if (!HasGraphData()) return 0; + iceFsk3(GraphBuffer, LF_TRACE_BUFF_SIZE); RepaintGraphWindow(); return 0; @@ -343,16 +347,17 @@ int CmdIceManchester(const char *Cmd){ ManchesterDemod( -1); return 0; } -int ManchesterDemod(int block){ +int ManchesterDemod(int blockNum){ - int blockNum = -1; + if (!HasGraphData()) return 0; + uint8_t sizebyte = 32; uint8_t offset = 5; uint32_t blockData; - uint8_t bits[1000] = {0x00}; + uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; uint8_t * bitstream = bits; - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream); + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); blockData = PackBits(offset, sizebyte, bitstream); if ( blockNum < 0) diff --git a/client/cmdmain.c b/client/cmdmain.c index bf69c5ad..b35ba63c 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -51,9 +51,9 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help. Use ' help' for details of a particular command."}, {"data", CmdData, 1, "{ Plot window / data buffer manipulation... }"}, - {"hf", CmdHF, 1, "{ HF commands... }"}, + {"hf", CmdHF, 1, "{ High Frequency commands... }"}, {"hw", CmdHW, 1, "{ Hardware commands... }"}, - {"lf", CmdLF, 1, "{ LF commands... }"}, + {"lf", CmdLF, 1, "{ Low Frequency commands... }"}, {"script", CmdScript, 1,"{ Scripting commands }"}, {"quit", CmdQuit, 1, "Exit program"}, {"exit", CmdQuit, 1, "Exit program"}, diff --git a/client/graph.c b/client/graph.c index 541e68f3..8974f4c3 100644 --- a/client/graph.c +++ b/client/graph.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include +#include #include #include "ui.h" #include "graph.h" @@ -93,3 +94,15 @@ int GetClock(const char *str, int peak, int verbose) return clock; } + + +/* A simple test to see if there is any data inside Graphbuffer. +*/ +bool HasGraphData(){ + + if ( GraphTraceLen <= 0) { + PrintAndLog("No data available, try reading something first"); + return false; + } + return true; +} \ No newline at end of file diff --git a/client/graph.h b/client/graph.h index cbe81161..ce803c82 100644 --- a/client/graph.h +++ b/client/graph.h @@ -15,9 +15,9 @@ void AppendGraph(int redraw, int clock, int bit); int ClearGraph(int redraw); int DetectClock(int peak); int GetClock(const char *str, int peak, int verbose); +bool HasGraphData(); #define MAX_GRAPH_TRACE_LEN (1024*128) extern int GraphBuffer[MAX_GRAPH_TRACE_LEN]; extern int GraphTraceLen; - #endif diff --git a/client/ui.c b/client/ui.c index 966ab2ca..816bff44 100644 --- a/client/ui.c +++ b/client/ui.c @@ -95,14 +95,14 @@ void SetLogFilename(char *fn) logfilename = fn; } -int manchester_decode( int * data, const size_t len, uint8_t * dataout){ +int manchester_decode( int * data, const size_t len, uint8_t * dataout, size_t dataoutlen){ int bitlength = 0; int i, clock, high, low, startindex; low = startindex = 0; high = 1; - uint8_t * bitStream = (uint8_t* ) malloc(sizeof(uint8_t) * len); - memset(bitStream, 0x00, len); + uint8_t * bitStream = (uint8_t* ) malloc(sizeof(uint8_t) * dataoutlen); + memset(bitStream, 0x00, dataoutlen); /* Detect high and lows */ for (i = 0; i < len; i++) { @@ -116,12 +116,12 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ clock = GetT55x7Clock( data, len, high ); startindex = DetectFirstTransition(data, len, high); - PrintAndLog(" Clock : %d", clock); + //PrintAndLog(" Clock : %d", clock); if (high != 1) - bitlength = ManchesterConvertFrom255(data, len, bitStream, high, low, clock, startindex); + bitlength = ManchesterConvertFrom255(data, len, bitStream, dataoutlen, high, low, clock, startindex); else - bitlength= ManchesterConvertFrom1(data, len, bitStream, clock, startindex); + bitlength= ManchesterConvertFrom1(data, len, bitStream, dataoutlen, clock, startindex); memcpy(dataout, bitStream, bitlength); free(bitStream); @@ -192,7 +192,7 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ return i; } - int ManchesterConvertFrom255(const int * data, const size_t len, uint8_t * dataout, int high, int low, int clock, int startIndex){ + 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; @@ -205,7 +205,7 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ int firstST = 0; // i = clock frame of data - for (; i < (int)(len / clock); i++) + for (; i < (int)(len/clock); i++) { hithigh = 0; hitlow = 0; @@ -261,11 +261,13 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout){ if ( firstST == 4) break; + if ( bitIndex >= dataoutlen-1 ) + break; } return bitIndex; } - int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout, int clock, int startIndex){ + int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout,int dataoutlen, int clock, int startIndex){ PrintAndLog(" Path B"); diff --git a/client/ui.h b/client/ui.h index 8d16e059..6a45fcfd 100644 --- a/client/ui.h +++ b/client/ui.h @@ -27,13 +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); +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 high, int low, int clock, int startIndex); -int ManchesterConvertFrom1(const int * data, const size_t len, uint8_t * dataout, int clock, int startIndex); +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 From 1010aacca01ea823e5265babefa0d325863a2ba3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 27 Oct 2014 09:56:18 +0100 Subject: [PATCH 16/78] Minor corrections in fskdemod i lfops.c , see Holimans branch. BUG: fixed a variablename, that didn't get changed. --- armsrc/lfops.c | 52 +++++++++++++++++++-------------------------- client/cmdlft55xx.c | 2 +- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 136a1567..bf743c24 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -55,7 +55,7 @@ void SnoopLFRawAdcSamples(int divisor, int trigger_threshold) void DoAcquisition125k_internal(int trigger_threshold, bool silent) { uint8_t *dest = mifare_get_bigbufptr(); - int n = 8000; + int n = 24000; int i; memset(dest, 0x00, n); @@ -89,28 +89,24 @@ void DoAcquisition125k() { void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) { - int at134khz; /* Make sure the tag is reset */ FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(2500); + int divisor_used = 95; // 125 KHz // see if 'h' was specified + if (command[strlen((char *) command) - 1] == 'h') - at134khz = TRUE; - else - at134khz = FALSE; - - if (at134khz) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + divisor_used = 88; // 134.8 KHz + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Give it a bit of time for the resonant antenna to settle. SpinDelay(50); + + // And a little more time for the tag to fully power up SpinDelay(2000); @@ -122,10 +118,7 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelayUs(delay_off); - if (at134khz) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); LED_D_ON(); @@ -137,15 +130,12 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelayUs(delay_off); - if (at134khz) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); // now do the read - DoAcquisition125k(); + DoAcquisition125k(-1); } /* blank r/w tag data stream @@ -696,21 +686,19 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) size_t size=0,idx=0; //, found=0; uint32_t hi2=0, hi=0, lo=0; + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(0, true); while(!BUTTON_PRESS()) { - // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(0,true); - WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition125k(); + DoAcquisition125k_internal(-1,true); size = sizeof(BigBuf); // FSK demodulator size = fsk_demod(dest, size); - WDT_HIT(); // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns // 1->0 : fc/8 in sets of 6 @@ -731,7 +719,8 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) idx+=sizeof(frame_marker_mask); while(dest[idx] != dest[idx+1] && idx < size-2) - { // Keep going until next frame marker (or error) + { + // Keep going until next frame marker (or error) // Shift in a bit. Start by shifting high registers hi2=(hi2<<1)|(hi>>31); hi=(hi<<1)|(lo>>31); @@ -746,6 +735,8 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) } //Dbprintf("Num shifts: %d ", numshifts); // Hopefully, we read a tag and hit upon the next frame marker + if(idx + sizeof(frame_marker_mask) < size) + { if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) { if (hi2 != 0){ @@ -758,6 +749,8 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) } } + } + // reset hi2 = hi = lo = 0; numshifts = 0; @@ -792,21 +785,20 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) size_t size=0, idx=0; uint32_t code=0, code2=0; + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(0, true); while(!BUTTON_PRESS()) { - // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(0,true); WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition125k(true); + DoAcquisition125k_internal(-1,true); size = sizeof(BigBuf); // FSK demodulator size = fsk_demod(dest, size); - WDT_HIT(); // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns // 1->0 : fc/8 in sets of 7 diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 09ba1ee7..b4f884fe 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -41,7 +41,7 @@ int CmdReadBlk(const char *Cmd) c.cmd = CMD_T55XX_READ_BLOCK; c.d.asBytes[0] = 0x00; c.arg[0] = 0; - c.arg[1] = Block; + c.arg[1] = block; c.arg[2] = 0; SendCommand(&c); WaitForResponse(CMD_ACK, NULL); From 2ae8a312e058f71d0f02be4f2f9cc6f284ebbf34 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 27 Oct 2014 19:46:21 +0100 Subject: [PATCH 17/78] Inital test for the "lf em4x 410xsim / lf em4x 410xwatch" which I try to verify that the sim works. Something about speed, the clock detection is not so good. should be 64, usually 67.. --- armsrc/appmain.c | 1 - armsrc/lfops.c | 14 +++++++---- client/cmdlfem4x.c | 34 +++++++++++++++++++++---- client/cmdlft55xx.c | 4 +-- client/graph.c | 4 ++- client/loclass/cipher.c | 20 +++++++++++++-- client/loclass/cipher.h | 20 +++++++++++++-- client/loclass/cipherutils.c | 19 ++++++++++++-- client/loclass/cipherutils.h | 20 +++++++++++++-- client/loclass/elite_crack.c | 46 ++++++++++++++++++++++++++++----- client/loclass/elite_crack.h | 39 ++++++++++++++++++++++++++++ client/loclass/fileutils.c | 49 ++++++++++++++++++++++++++++++++++++ client/loclass/fileutils.h | 49 +++++++++++++++++++++++++++++++++++- client/loclass/ikeys.c | 26 +++++++++++++------ client/loclass/ikeys.h | 38 ++++++++++++++++++++++++++++ client/loclass/main.c | 35 +++++++++++++++++++++++--- 16 files changed, 379 insertions(+), 39 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index b9ad1abd..d239ceb0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -949,7 +949,6 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_DOWNLOADED_SIM_SAMPLES_125K: { uint8_t *b = (uint8_t *)BigBuf; memcpy(b+c->arg[0], c->d.asBytes, 48); - //Dbprintf("copied 48 bytes to %i",b+c->arg[0]); cmd_send(CMD_ACK,0,0,0,0,0); break; } diff --git a/armsrc/lfops.c b/armsrc/lfops.c index bf743c24..025314a0 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -450,13 +450,17 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) void SimulateTagLowFrequency(int period, int gap, int ledcontrol) { int i; - uint8_t *tab = (uint8_t *)BigBuf; + uint8_t *buff = (uint8_t *)BigBuf; FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; - + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(150); + + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; @@ -476,7 +480,7 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) if (ledcontrol) LED_D_ON(); - if(tab[i]) + if(buff[i]) OPEN_COIL(); else SHORT_COIL(); diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 1ce937d9..aa87132e 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -1,4 +1,4 @@ -//----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh // // This code is licensed to you under the terms of the GNU GPL, version 2 or, @@ -195,9 +195,27 @@ retest: * 0 <-- stop bit, end of tag */ int CmdEM410xSim(const char *Cmd) -{ - int i, n, j, h, binary[4], parity[4]; +{ + int i, n, j, h, binary[4], parity[4]; + char cmdp = param_getchar(Cmd, 0); + uint8_t uid[5] = {0x00}; + + if (cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: lf em4x sim "); + PrintAndLog(""); + PrintAndLog(" sample: lf em4x sim 0F0368568B"); + return 0; + } + + if (param_gethex(Cmd, 0, uid, 10)) { + PrintAndLog("UID must include 10 HEX symbols"); + return 0; + } + + PrintAndLog("Starting simulating with UID %02X %02X %02X %02X %02X", uid[0],uid[1],uid[2],uid[3],uid[4]); + + /* clock is 64 in EM410x tags */ int clock = 64; @@ -271,10 +289,16 @@ int CmdEM410xWatch(const char *Cmd) int read_h = (*Cmd == 'h'); do { + if (ukbhit()) { + printf("\naborted via keyboard!\n"); + break; + } + CmdLFRead(read_h ? "h" : ""); - CmdSamples("16000"); + CmdSamples("16000"); + } while ( - !CmdEM410xRead("") + !CmdEM410xRead("64") ); return 0; } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index b4f884fe..9eaa6463 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -316,8 +316,8 @@ int CmdDump(const char *Cmd){ } if ( hasPwd ){ - if (param_gethex(Cmd, 0, pwd, 4)) { - PrintAndLog("password must include 4 HEX symbols"); + if (param_gethex(Cmd, 0, pwd, 8)) { + PrintAndLog("password must include 8 HEX symbols"); return 0; } } diff --git a/client/graph.c b/client/graph.c index 8974f4c3..98dc8043 100644 --- a/client/graph.c +++ b/client/graph.c @@ -36,8 +36,10 @@ void AppendGraph(int redraw, int clock, int bit) int ClearGraph(int redraw) { int gtl = GraphTraceLen; - GraphTraceLen = 0; + memset(GraphBuffer, 0x00, GraphTraceLen); + GraphTraceLen = 0; + if (redraw) RepaintGraphWindow(); diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 8b1a523d..9c1c2cfd 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #include "cipher.h" #include "cipherutils.h" #include diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h index 4bfbe0b7..176a2976 100644 --- a/client/loclass/cipher.h +++ b/client/loclass/cipher.h @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #ifndef CIPHER_H #define CIPHER_H #include diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index 1e08cf10..8c6a278a 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,7 +30,10 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ #include diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h index acf96115..cb090f69 100644 --- a/client/loclass/cipherutils.h +++ b/client/loclass/cipherutils.h @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #ifndef CIPHERUTILS_H #define CIPHERUTILS_H #include diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index 1a464b6c..cba31808 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #include #include #include @@ -526,13 +564,9 @@ int bruteforceFile(const char *filename, uint16_t keytable[]) fseek(f, 0, SEEK_SET); uint8_t *dump = malloc(fsize); - size_t bytes_read = fread(dump, fsize, 1, f); - + fread(dump, fsize, 1, f); fclose(f); - if (bytes_read < fsize) - { - prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize ); - } + return bruteforceDump(dump,fsize,keytable); } /** diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h index 21004e59..fb27355f 100644 --- a/client/loclass/elite_crack.h +++ b/client/loclass/elite_crack.h @@ -1,3 +1,42 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + + #ifndef ELITE_CRACK_H #define ELITE_CRACK_H void permutekey(uint8_t key[8], uint8_t dest[8]); diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index 08e1c1a7..6d990171 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #include #include #include @@ -45,6 +83,17 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si return 0; } +int loadFile(const char *fileName, void* data, size_t datalen) +{ + FILE *filehandle = fopen(fileName, "rb"); + if(!filehandle) { + prnlog("Failed to read from file '%s'", fileName); + return 1; + } + fread(data,datalen,1,filehandle); + fclose(filehandle); + return 0; +} /** * Utility function to print to console. This is used consistently within the library instead * of printf, but it actually only calls printf (and adds a linebreak). diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h index a0f5a799..02cfcef9 100644 --- a/client/loclass/fileutils.h +++ b/client/loclass/fileutils.h @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #ifndef FILEUTILS_H #define FILEUTILS_H /** @@ -11,13 +49,22 @@ * @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 loadFile(const char *fileName, void* data, size_t datalen); /** * Utility function to print to console. This is used consistently within the library instead * of printf, but it actually only calls printf. The reason to have this method is to *make it simple to plug this library into proxmark, which has this function already to - * write also to a logfile. When doing so, just point this function to use PrintAndLog + * write also to a logfile. When doing so, just delete this function. * @param fmt */ void prnlog(char *fmt, ...); diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index cd2b72ee..b0528b5c 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -1,15 +1,23 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and * Milosch Meriac in the paper "Dismantling IClass". * - * This is a reference implementation of iclass key diversification. I'm sure it can be - * optimized heavily. It is written for ease of understanding and correctness, please take it - * and tweak it and make a super fast version instead, using this for testing and verification. - * Copyright (C) 2014 Martin Holst Swende * * This is free software: you can redistribute it and/or modify @@ -22,8 +30,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + /** @@ -391,7 +403,7 @@ void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]) //Calculate HASH0(DES)) uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8); - //uint64_t crypted_csn_swapped = swapZvalues(crypt_csn); + uint64_t crypted_csn_swapped = swapZvalues(crypt_csn); hash0(crypt_csn,div_key); } diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h index 1de46b62..13096194 100644 --- a/client/loclass/ikeys.h +++ b/client/loclass/ikeys.h @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #ifndef IKEYS_H #define IKEYS_H diff --git a/client/loclass/main.c b/client/loclass/main.c index 42019072..b7ea53e5 100644 --- a/client/loclass/main.c +++ b/client/loclass/main.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #include #include #include @@ -62,9 +78,22 @@ int showHelp() int main (int argc, char **argv) { + + prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n"); prnlog("Comes with ABSOLUTELY NO WARRANTY"); - prnlog("This is free software, and you are welcome to use, abuse and repackage, please keep the credits\n"); + prnlog("Released as GPLv2\n"); + prnlog("WARNING"); + prnlog(""); + prnlog("THIS TOOL IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. "); + prnlog(""); + prnlog("USAGE OF THIS TOOL IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL "); + prnlog("PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, "); + prnlog("AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. "); + prnlog(""); + prnlog("THIS TOOL SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. "); + + char *fileName = NULL; int c; while ((c = getopt (argc, argv, "thf:")) != -1) From 7c756d68925891ec3d3aa0bec89ec215fd449bd1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 27 Oct 2014 21:42:41 +0100 Subject: [PATCH 18/78] FIX: Another try to see if the "lf em4x 410xsim" becomes better, added the clock in the calls since the auto detection of the clock seems to be wrong. I get 67, instead of 64... FIX: changes the transfersize from sim -> pm3, was 48, now USB_CMD_DATA_SIZE (512) Much faster! --- armsrc/appmain.c | 2 +- client/.history | 3 +++ client/cmdlf.c | 9 +++++---- client/cmdlfem4x.c | 7 ++++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index d239ceb0..6d18561a 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -948,7 +948,7 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_DOWNLOADED_SIM_SAMPLES_125K: { uint8_t *b = (uint8_t *)BigBuf; - memcpy(b+c->arg[0], c->d.asBytes, 48); + memcpy(b+c->arg[0], c->d.asBytes, USB_CMD_DATA_SIZE); cmd_send(CMD_ACK,0,0,0,0,0); break; } diff --git a/client/.history b/client/.history index 176dec98..e20a63e0 100644 --- a/client/.history +++ b/client/.history @@ -6,3 +6,6 @@ lf t55xx rd 0 lf t55xx trac lf t55xx rd 1 lf t55xx rd 2 +lf em4x 410xsim 124s +lf em4x 410xsim 0F0368568B +da pl diff --git a/client/cmdlf.c b/client/cmdlf.c index a198e1e1..1ce0ac81 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -398,17 +398,18 @@ int CmdLFSim(const char *Cmd) /* convert to bitstream if necessary */ ChkBitstream(Cmd); - PrintAndLog("Sending data, please wait..."); - for (i = 0; i < GraphTraceLen; i += 48) { + PrintAndLog("Sending [%d bytes]", GraphTraceLen); + for (i = 0; i < GraphTraceLen; i += USB_CMD_DATA_SIZE) { UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}}; int j; - for (j = 0; j < 48; j++) { + 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 simulator..."); UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}}; SendCommand(&c); diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index aa87132e..45a95f02 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -221,7 +221,8 @@ int CmdEM410xSim(const char *Cmd) /* clear our graph */ ClearGraph(0); - + GraphTraceLen = 0; + /* write it out a few times */ for (h = 0; h < 4; h++) { @@ -270,7 +271,7 @@ int CmdEM410xSim(const char *Cmd) /* booyah! */ RepaintGraphWindow(); - CmdLFSim(""); + CmdLFSim("64"); return 0; } @@ -295,7 +296,7 @@ int CmdEM410xWatch(const char *Cmd) } CmdLFRead(read_h ? "h" : ""); - CmdSamples("16000"); + CmdSamples("12000"); } while ( !CmdEM410xRead("64") From a61b4976bd2085bf0495855b48fcad0d9ed4572e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 30 Oct 2014 00:09:01 +0100 Subject: [PATCH 19/78] FIXED: Merged all Holimans code-review issues which should fix a lot of memoryleaks. --- armsrc/appmain.c | 2 +- armsrc/epa.c | 2 +- armsrc/iso14443a.c | 11 +++++- armsrc/lfops.c | 80 +++++++++++++++++++------------------- armsrc/util.c | 2 +- client/cmddata.c | 22 +++++------ client/cmdhf15.c | 5 ++- client/cmdhficlass.c | 7 ++-- client/cmdhfmf.c | 18 +++++---- client/cmdlf.c | 2 +- client/cmdlfem4x.c | 22 +++++------ client/cmdlft55xx.c | 4 +- client/cmdmain.c | 6 ++- client/graph.c | 27 ++++++++++--- client/loclass/ikeys.c | 6 +-- client/mifarehost.c | 31 ++++++--------- client/nonce2key/crapto1.c | 7 +++- client/ui.c | 25 ++---------- 18 files changed, 142 insertions(+), 137 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 6d18561a..581335de 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -674,7 +674,7 @@ void UsbPacketReceived(uint8_t *packet, int len) break; case CMD_SIMULATE_TAG_125K: LED_A_ON(); - SimulateTagLowFrequency(c->arg[0], c->arg[1], 1); + SimulateTagLowFrequency(c->arg[0], c->arg[1], 0); LED_A_OFF(); break; case CMD_LF_SIMULATE_BIDIR: diff --git a/armsrc/epa.c b/armsrc/epa.c index 565019ce..69599dc9 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -419,7 +419,7 @@ int EPA_Setup() // return code int return_code = 0; // card UID - uint8_t uid[8]; + uint8_t uid[10]; // card select information iso14a_card_select_t card_select_info; // power up the field diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 3b17bd4b..6fe83c6e 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1717,7 +1717,13 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: // http://www.nxp.com/documents/application_note/AN10927.pdf - memcpy(uid_resp, uid_resp + 1, 3); + // This was earlier: + //memcpy(uid_resp, uid_resp + 1, 3); + // But memcpy should not be used for overlapping arrays, + // and memmove appears to not be available in the arm build. + // So this has been replaced with a for-loop: + for(int xx = 0; xx < 3; xx++) + uid_resp[xx] = uid_resp[xx+1]; uid_resp_len = 3; } @@ -1928,7 +1934,8 @@ void ReaderMifare(bool first_try) uint8_t uid[10]; uint32_t cuid; - uint32_t nt, previous_nt; + uint32_t nt = 0; + uint32_t previous_nt = 0; static uint32_t nt_attacked = 0; byte_t par_list[8] = {0,0,0,0,0,0,0,0}; byte_t ks_list[8] = {0,0,0,0,0,0,0,0}; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 025314a0..c80caf77 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -17,6 +17,9 @@ #include "crapto1.h" #include "mifareutil.h" +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) + void LFSetupFPGAForADC(int divisor, bool lf_field) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); @@ -56,10 +59,9 @@ void DoAcquisition125k_internal(int trigger_threshold, bool silent) { uint8_t *dest = mifare_get_bigbufptr(); int n = 24000; - int i; - + int i = 0; memset(dest, 0x00, n); - i = 0; + for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { AT91C_BASE_SSC->SSC_THR = 0x43; @@ -289,17 +291,17 @@ void WriteTIbyte(uint8_t b) { if (b&(1<PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; - -#define SHORT_COIL() LOW(GPIO_SSC_DOUT) -#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) - - i = 0; - for(;;) { + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(30); + + for(;;) { + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - if(BUTTON_PRESS()) { - DbpString("Stopped"); - return; - } - WDT_HIT(); + if(BUTTON_PRESS()) { + DbpString("Stopped at 0"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + return; + } + WDT_HIT(); } - if (ledcontrol) - LED_D_ON(); - - if(buff[i]) + if ( buff[i] ) OPEN_COIL(); else SHORT_COIL(); - - if (ledcontrol) - LED_D_OFF(); - - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - if(BUTTON_PRESS()) { - DbpString("Stopped"); + + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + if(BUTTON_PRESS()) { + DbpString("Stopped at 1"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off return; } WDT_HIT(); - } + } - i++; + ++i; if(i == period) { i = 0; if (gap) { + // turn of modulation SHORT_COIL(); - SpinDelayUs(gap); - } + // wait + SpinDelay(gap); + } } } } @@ -609,6 +608,7 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol) if (ledcontrol) LED_A_ON(); + SimulateTagLowFrequency(n, 0, ledcontrol); if (ledcontrol) @@ -793,8 +793,6 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) LFSetupFPGAForADC(0, true); while(!BUTTON_PRESS()) { - - WDT_HIT(); if (ledcontrol) LED_A_ON(); diff --git a/armsrc/util.c b/armsrc/util.c index 8ff5b68d..0558fb94 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -265,7 +265,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers { struct version_information *v = (struct version_information*)version_information; dst[0] = 0; - strncat(dst, prefix, len); + strncat(dst, prefix, len-1); if(v->magic != VERSION_INFORMATION_MAGIC) { strncat(dst, "Missing/Invalid version information", len - strlen(dst) - 1); return; diff --git a/client/cmddata.c b/client/cmddata.c index c58f6f62..b01b45ba 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -552,7 +552,7 @@ int CmdManchesterDemod(const char *Cmd) /* But it does not work if compiling on WIndows: therefore we just allocate a */ /* large array */ - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN] = {0x00}; /* Detect high and lows */ for (i = 0; i < GraphTraceLen; i++) @@ -564,8 +564,7 @@ int CmdManchesterDemod(const char *Cmd) } /* Get our clock */ - clock = GetClock(Cmd, high, 1); - + clock = GetClock(Cmd, high, 1); int tolerance = clock/4; /* Detect first transition */ @@ -583,8 +582,6 @@ int CmdManchesterDemod(const char *Cmd) break; } } - - PrintAndLog("Clock: %d", clock); /* If we're not working with 1/0s, demod based off clock */ if (high != 1) @@ -723,21 +720,22 @@ int CmdManchesterDemod(const char *Cmd) int CmdManchesterMod(const char *Cmd) { int i, j; - int clock; int bit, lastbit, wave; - - /* Get our clock */ - clock = GetClock(Cmd, 0, 1); - + int clock = GetClock(Cmd, 0, 1); + int clock1 = GetT55x7Clock( GraphBuffer, GraphTraceLen, 0 ); + PrintAndLog("MAN MOD CLOCKS: %d ice %d", clock,clock1); + + int half = (int)(clock/2); + wave = 0; lastbit = 1; for (i = 0; i < (int)(GraphTraceLen / clock); i++) { bit = GraphBuffer[i * clock] ^ 1; - for (j = 0; j < (int)(clock/2); j++) + for (j = 0; j < half; ++j) GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave; - for (j = (int)(clock/2); j < clock; j++) + for (j = half; j < clock; ++j) GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1; /* Keep track of how we start our wave and if we changed or not this time */ diff --git a/client/cmdhf15.c b/client/cmdhf15.c index bdc08521..556d3f56 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -561,8 +561,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, uid[8]; - uint32_t reqlen=0; + uint8_t *req = c->d.asBytes; + uint8_t uid[8] = {0x00}; + uint32_t reqlen = 0; // strip while (**cmd==' ' || **cmd=='\t') (*cmd)++; diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index bd215a61..47ff2db0 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -501,7 +501,9 @@ int CmdHFiClassReader_Dump(const char *Cmd) SendCommand(&c); UsbCommand resp; - + uint8_t key_sel[8] = {0x00}; + uint8_t key_sel_p[8] = {0x00}; + if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { uint8_t isOK = resp.arg[0] & 0xff; uint8_t * data = resp.d.asBytes; @@ -519,8 +521,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { if(elite) { - uint8_t key_sel[8] = {0}; - uint8_t key_sel_p[8] = { 0 }; + //Get the key index (hash1) uint8_t key_index[8] = {0}; diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 0e212b2d..1d2de683 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -521,8 +521,6 @@ int CmdHF14AMfDump(const char *Cmd) int size = GetCardSize(); char cmdp = param_getchar(Cmd, 0); - - if ( size > -1) cmdp = (char)(48+size); @@ -548,7 +546,7 @@ int CmdHF14AMfDump(const char *Cmd) } if ((fin = fopen("dumpkeys.bin","rb")) == NULL) { - PrintAndLog("Could not find file dumpkeys.bin"); + PrintAndLog("Could not find file dumpkeys.bin"); return 1; } @@ -556,6 +554,7 @@ int CmdHF14AMfDump(const char *Cmd) for (sectorNo=0; sectorNo low) && (i(MAX_GRAPH_TRACE_LEN/64)) { + if (j>=(MAX_GRAPH_TRACE_LEN/64)) { break; } tmpbuff[j++]= i - start; @@ -616,7 +616,7 @@ int CmdWriteWord(const char *Cmd) return 1; } - PrintAndLog("Writting word %d with data %08X", Word, Data); + PrintAndLog("Writing word %d with data %08X", Word, Data); c.cmd = CMD_EM4X_WRITE_WORD; c.d.asBytes[0] = 0x0; //Normal mode @@ -629,7 +629,7 @@ int CmdWriteWord(const char *Cmd) int CmdWriteWordPWD(const char *Cmd) { - int Word = 8; //default to invalid word + int Word = 16; //default to invalid word int Data = 0xFFFFFFFF; //default to blank data int Password = 0xFFFFFFFF; //default to blank password UsbCommand c; @@ -641,7 +641,7 @@ int CmdWriteWordPWD(const char *Cmd) return 1; } - PrintAndLog("Writting word %d with data %08X and password %08X", Word, Data, Password); + PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password); c.cmd = CMD_EM4X_WRITE_WORD; c.d.asBytes[0] = 0x1; //Password mode diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 9eaa6463..513eb0ef 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -482,8 +482,8 @@ static command_t CommandTable[] = {"rdpwd", CmdReadBlkPWD, 0, " -- Read T55xx block data with password mode"}, {"wr", CmdWriteBlk, 0, " -- Write T55xx block data (page 0)"}, {"wrpwd", CmdWriteBlkPWD, 0, " -- Write T55xx block data with password"}, - {"trace", CmdReadTrace, 0, "[1] Read T55xx traceability data (page 1 / blk 0-1) "}, - {"info", CmdInfo, 0, "[1] Read T55xx configuration data (page0 /blk 0)"}, + {"trace", CmdReadTrace, 0, "[1] Read T55xx traceability data (page 1/ blk 0-1)"}, + {"info", CmdInfo, 0, "[1] Read T55xx configuration data (page 0/ blk 0)"}, {"dump", CmdDump, 0, "[password] Dump T55xx card block 0-7. optional with password"}, {"fsk", CmdIceFsk, 0, "FSK demod"}, {"man", CmdIceManchester, 0, "Manchester demod (with SST)"}, diff --git a/client/cmdmain.c b/client/cmdmain.c index b35ba63c..d84d96ef 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -137,9 +137,11 @@ int getCommand(UsbCommand* response) * @return true if command was returned, otherwise false */ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) { - + + UsbCommand resp; + if (response == NULL) { - UsbCommand resp; + response = &resp; } diff --git a/client/graph.c b/client/graph.c index 98dc8043..4e8cb89c 100644 --- a/client/graph.c +++ b/client/graph.c @@ -21,11 +21,13 @@ int GraphTraceLen; void AppendGraph(int redraw, int clock, int bit) { int i; - - for (i = 0; i < (int)(clock / 2); ++i) - GraphBuffer[GraphTraceLen++] = bit ^ 1; + int half = (int)(clock/2); + int firstbit = bit ^ 1; + + for (i = 0; i < half; ++i) + GraphBuffer[GraphTraceLen++] = firstbit; - for (i = (int)(clock / 2); i < clock; ++i) + for (i = 0; i <= half; ++i) GraphBuffer[GraphTraceLen++] = bit; if (redraw) @@ -72,8 +74,23 @@ int DetectClock(int peak) lastpeak = i; } } + + int clockmod = clock%8; + if ( clockmod == 0) + return clock; + + // When detected clock is 31 or 33 then return 32 - return clock; + printf("Found clock at %d ", clock); + switch( clockmod ) + { + case 7: clock++; break; + case 6: clock += 2 ; break; + case 1: clock--; break; + case 2: clock -= 2; break; + } + printf("- adjusted it to %d \n", clock); + return clock; } /* Get or auto-detect clock rate */ diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index b0528b5c..a55227ef 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -737,16 +737,14 @@ int doTestsWithKnownInputs() int readKeyFile(uint8_t key[8]) { - FILE *f; - + int retval = 1; f = fopen("iclass_key.bin", "rb"); if (f) { if(fread(key, sizeof(key), 1, f) == 1) return 0; } - return 1; - + return retval; } diff --git a/client/mifarehost.c b/client/mifarehost.c index fe8b8b26..ed62bcee 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -296,7 +296,7 @@ static uint8_t trailerAccessBytes[4] = {0x08, 0x77, 0x8F, 0x00}; // variables char logHexFileName[200] = {0x00}; static uint8_t traceCard[4096] = {0x00}; -static char traceFileName[20]; +static char traceFileName[200] = {0x00}; static int traceState = TRACE_IDLE; static uint8_t traceCurBlock = 0; static uint8_t traceCurKey = 0; @@ -449,7 +449,7 @@ int mfTraceDecode(uint8_t *data_src, int len, uint32_t parity, bool wantSaveToEm } // AUTHENTICATION - if ((len ==4) && ((data[0] == 0x60) || (data[0] == 0x61))) { + if ((len == 4) && ((data[0] == 0x60) || (data[0] == 0x61))) { traceState = TRACE_AUTH1; traceCurBlock = data[1]; traceCurKey = data[0] == 60 ? 1:0; @@ -497,7 +497,7 @@ int mfTraceDecode(uint8_t *data_src, int len, uint32_t parity, bool wantSaveToEm break; case TRACE_WRITE_OK: - if ((len == 1) && (data[0] = 0x0a)) { + if ((len == 1) && (data[0] == 0x0a)) { traceState = TRACE_WRITE_DATA; return 0; @@ -555,23 +555,14 @@ int mfTraceDecode(uint8_t *data_src, int len, uint32_t parity, bool wantSaveToEm at_par = parity; // decode key here) - if (!traceCrypto1) { - 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); - }else{ - 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); - } + 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, &lfsr); printf("key> %x%x\n", (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF)); AddLogUint64(logHexFileName, "key> ", lfsr); diff --git a/client/nonce2key/crapto1.c b/client/nonce2key/crapto1.c index 90f55ab4..c2dd7a54 100644 --- a/client/nonce2key/crapto1.c +++ b/client/nonce2key/crapto1.c @@ -544,7 +544,12 @@ 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? if(!statelist || !odd || !even) - return 0; + { + free(statelist); + free(odd); + free(even); + return 0; + } s = statelist; for(o = odd; *o != -1; ++o) diff --git a/client/ui.c b/client/ui.c index 816bff44..5111e295 100644 --- a/client/ui.c +++ b/client/ui.c @@ -152,30 +152,13 @@ int manchester_decode( int * data, const size_t len, uint8_t * dataout, size_t lastpeak = i; } } - //return clock; - //defaults clock to precise values. - switch(clock){ - case 8: - case 16: - case 32: - case 40: - case 50: - case 64: - case 100: - case 128: - return clock; - break; - default: break; - } - - //PrintAndLog(" Found Clock : %d - trying to adjust", clock); // When detected clock is 31 or 33 then then return int clockmod = clock%8; - if ( clockmod == 7 ) - clock += 1; - else if ( clockmod == 1 ) - clock -= 1; + if ( clockmod == 0) return clock; + + if ( clockmod == 7 ) clock += 1; + else if ( clockmod == 1 ) clock -= 1; return clock; } From 3649b640e6a7f70e460791db18ed7cb96d9cfff6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 30 Oct 2014 14:11:37 +0100 Subject: [PATCH 20/78] CHG: added possiblity to send into the "HF 15 SIM" --- armsrc/appmain.c | 2 +- armsrc/apps.h | 2 +- armsrc/iso15693.c | 183 ++++++++++++++++----------------------------- client/cmdhf15.c | 21 +++++- client/cmdlfem4x.c | 11 ++- 5 files changed, 91 insertions(+), 128 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 581335de..be904b4f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -743,7 +743,7 @@ void UsbPacketReceived(uint8_t *packet, int len) ReaderIso15693(c->arg[0]); break; case CMD_SIMTAG_ISO_15693: - SimTagIso15693(c->arg[0]); + SimTagIso15693(c->arg[0], c->d.asBytes); break; #endif diff --git a/armsrc/apps.h b/armsrc/apps.h index a4dd3d08..0db2a19d 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -236,7 +236,7 @@ void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg -void SimTagIso15693(uint32_t parameter); // simulate an ISO15693 tag - greg +void SimTagIso15693(uint32_t parameter, uint8_t *uid); // simulate an ISO15693 tag - greg void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); // send arbitrary commands from CLI - atrox void SetDebugIso15693(uint32_t flag); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index d8bec898..884ed976 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -265,13 +265,10 @@ static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *w //----------------------------------------------------------------------------- static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *wait) { - int c; - -// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR); // No requirement to energise my coils + int c = 0; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K); if(*wait < 10) { *wait = 10; } - c = 0; for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = cmd[c]; @@ -456,7 +453,7 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int int8_t prev = 0; -// NOW READ RESPONSE + // NOW READ RESPONSE FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads c = 0; @@ -838,7 +835,7 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) } // Now the VICC>VCD responses when we are simulating a tag - static void BuildInventoryResponse(void) + static void BuildInventoryResponse( uint8_t *uid) { uint8_t cmd[12]; @@ -848,14 +845,14 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1); cmd[1] = 0; // 64-bit UID - cmd[2] = 0x32; - cmd[3]= 0x4b; - cmd[4] = 0x03; - cmd[5] = 0x01; - cmd[6] = 0x00; - cmd[7] = 0x10; - cmd[8] = 0x05; - cmd[9]= 0xe0; + cmd[2] = uid[7]; //0x32; + cmd[3] = uid[6]; //0x4b; + cmd[4] = uid[5]; //0x03; + cmd[5] = uid[4]; //0x01; + cmd[6] = uid[3]; //0x00; + cmd[7] = uid[2]; //0x10; + cmd[8] = uid[1]; //0x05; + cmd[9] = uid[0]; //0xe0; //Now the CRC crc = Crc(cmd, 10); cmd[10] = crc & 0xff; @@ -997,40 +994,41 @@ void SetDebugIso15693(uint32_t debug) { // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector // all demodulation performed in arm rather than host. - greg //----------------------------------------------------------------------------- -void ReaderIso15693(uint32_t parameter) +void ReaderIso15693(uint32_t parameter ) { LED_A_ON(); LED_B_ON(); LED_C_OFF(); LED_D_OFF(); -//DbpString(parameter); - - //uint8_t *answer0 = (((uint8_t *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much) uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); // uint8_t *answer2 = (((uint8_t *)BigBuf) + 3760); uint8_t *answer3 = (((uint8_t *)BigBuf) + 3860); - //uint8_t *TagUID= (((uint8_t *)BigBuf) + 3960); // where we hold the uid for hi15reader -// int answerLen0 = 0; + int answerLen1 = 0; int answerLen2 = 0; int answerLen3 = 0; - int i=0; // counter + int i = 0; + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; + uint8_t TagUID[8] = {0x00}; + // Blank arrays - memset(BigBuf + 3660, 0, 300); + memset(BigBuf + 3660, 0x00, 300); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup SSC FpgaSetupSsc(); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + // Give the tags time to energize FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(200); @@ -1040,44 +1038,19 @@ void ReaderIso15693(uint32_t parameter) LED_C_OFF(); LED_D_OFF(); - int samples = 0; - int tsamples = 0; - int wait = 0; - int elapsed = 0; - // FIRST WE RUN AN INVENTORY TO GET THE TAG UID // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - uint8_t TagUID[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // where we hold the uid for hi15reader - -// BuildIdentifyRequest(); -// //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); -// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 -// // Now wait for a response -// responseLen0 = GetIso15693AnswerFromTag(receivedAnswer0, 100, &samples, &elapsed) ; -// if (responseLen0 >=12) // we should do a better check than this -// { -// // really we should check it is a valid mesg -// // but for now just grab what we think is the uid -// TagUID[0] = receivedAnswer0[2]; -// TagUID[1] = receivedAnswer0[3]; -// TagUID[2] = receivedAnswer0[4]; -// TagUID[3] = receivedAnswer0[5]; -// TagUID[4] = receivedAnswer0[6]; -// TagUID[5] = receivedAnswer0[7]; -// TagUID[6] = receivedAnswer0[8]; // IC Manufacturer code -// DbpIntegers(TagUID[6],TagUID[5],TagUID[4]); -//} // Now send the IDENTIFY command BuildIdentifyRequest(); - //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 + + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + // Now wait for a response answerLen1 = GetIso15693AnswerFromTag(answer1, 100, &samples, &elapsed) ; if (answerLen1 >=12) // we should do a better check than this { - TagUID[0] = answer1[2]; TagUID[1] = answer1[3]; TagUID[2] = answer1[4]; @@ -1087,23 +1060,6 @@ void ReaderIso15693(uint32_t parameter) TagUID[6] = answer1[8]; // IC Manufacturer code TagUID[7] = answer1[9]; // always E0 - // Now send the SELECT command - // since the SELECT command is optional, we should not rely on it. -//// BuildSelectRequest(TagUID); -// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 - // Now wait for a response -/// answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); - - // Now send the MULTI READ command -// BuildArbitraryRequest(*TagUID,parameter); -/// BuildArbitraryCustomRequest(TagUID,parameter); -// BuildReadBlockRequest(*TagUID,parameter); -// BuildSysInfoRequest(*TagUID); - //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); -/// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 - // Now wait for a response -/// answerLen3 = GetIso15693AnswerFromTag(answer3, 100, &samples, &elapsed) ; - } Dbprintf("%d octets read from IDENTIFY request:", answerLen1); @@ -1111,10 +1067,10 @@ void ReaderIso15693(uint32_t parameter) Dbhexdump(answerLen1,answer1,true); // UID is reverse - if (answerLen1>=12) - //Dbprintf("UID = %*D",8,TagUID," "); - Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX",TagUID[7],TagUID[6],TagUID[5], - TagUID[4],TagUID[3],TagUID[2],TagUID[1],TagUID[0]); + if (answerLen1 >= 12) + Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX", + TagUID[7],TagUID[6],TagUID[5],TagUID[4], + TagUID[3],TagUID[2],TagUID[1],TagUID[0]); Dbprintf("%d octets read from SELECT request:", answerLen2); @@ -1125,15 +1081,14 @@ void ReaderIso15693(uint32_t parameter) DbdecodeIso15693Answer(answerLen3,answer3); Dbhexdump(answerLen3,answer3,true); - - // read all pages - if (answerLen1>=12 && DEBUG) { + // read all pages + if (answerLen1 >= 12 && DEBUG) { i=0; - while (i<32) { // sanity check, assume max 32 pages + while (i < 32) { // sanity check, assume max 32 pages BuildReadBlockRequest(TagUID,i); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); - answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); - if (answerLen2>0) { + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); + if (answerLen2 > 0) { Dbprintf("READ SINGLE BLOCK %d returned %d octets:",i,answerLen2); DbdecodeIso15693Answer(answerLen2,answer2); Dbhexdump(answerLen2,answer2,true); @@ -1143,13 +1098,6 @@ void ReaderIso15693(uint32_t parameter) } } -// str2[0]=0; -// for(i = 0; i < responseLen3; i++) { -// itoa(str1,receivedAnswer3[i]); -// strncat(str2,str1,8); -// } -// DbpString(str2); - LED_A_OFF(); LED_B_OFF(); LED_C_OFF(); @@ -1158,57 +1106,54 @@ void ReaderIso15693(uint32_t parameter) // Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands // all demodulation performed in arm rather than host. - greg -void SimTagIso15693(uint32_t parameter) +void SimTagIso15693(uint32_t parameter, uint8_t *uid) { LED_A_ON(); LED_B_ON(); LED_C_OFF(); LED_D_OFF(); - uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); // + uint8_t *buf = (((uint8_t *)BigBuf) + 3660); // + int answerLen1 = 0; - - // Blank arrays - memset(answer1, 0, 100); - + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; + + memset(buf, 0x00, 100); + + // Inventory response + BuildInventoryResponse(uid); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Setup SSC + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - // Give the tags time to energize -// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); // NO GOOD FOR SIM TAG!!!! - SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); LED_A_OFF(); LED_B_OFF(); LED_C_ON(); LED_D_OFF(); - int samples = 0; - int tsamples = 0; - int wait = 0; - int elapsed = 0; - - answerLen1 = GetIso15693AnswerFromSniff(answer1, 100, &samples, &elapsed) ; + // Listen to reader + answerLen1 = GetIso15693AnswerFromSniff(buf, 100, &samples, &elapsed) ; if (answerLen1 >=1) // we should do a better check than this { // Build a suitable reponse to the reader INVENTORY cocmmand - BuildInventoryResponse(); - TransmitTo15693Reader(ToSend,ToSendMax, &tsamples, &wait); + // not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. + TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait); } Dbprintf("%d octets read from reader command: %x %x %x %x %x %x %x %x %x", answerLen1, - answer1[0], answer1[1], answer1[2], - answer1[3], answer1[4], answer1[5], - answer1[6], answer1[7], answer1[8]); + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7], buf[8]); LED_A_OFF(); LED_B_OFF(); diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 556d3f56..8ee8be92 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -298,7 +298,26 @@ int CmdHF15Reader(const char *Cmd) // Simulation is still not working very good int CmdHF15Sim(const char *Cmd) { - UsbCommand c = {CMD_SIMTAG_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}}; + char cmdp = param_getchar(Cmd, 0); + uint8_t uid[8] = {0x00}; + + //E0 16 24 00 00 00 00 00 + if (cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf 15 sim "); + PrintAndLog(""); + PrintAndLog(" sample: hf 15 sim E016240000000000"); + return 0; + } + + if (param_gethex(Cmd, 0, uid, 16)) { + PrintAndLog("UID must include 16 HEX symbols"); + return 0; + } + + PrintAndLog("Starting simulating UID %02X %02X %02X %02X %02X %02X %02X %02X", + uid[0],uid[1],uid[2],uid[3],uid[4], uid[5], uid[6], uid[7]); + + UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}}; SendCommand(&c); return 0; } diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index d371bf27..67013b2e 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -57,8 +57,7 @@ int CmdEM410xRead(const char *Cmd) /* get clock */ clock = GetClock(Cmd, high, 0); - - + /* parity for our 4 columns */ parity[0] = parity[1] = parity[2] = parity[3] = 0; header = rows = 0; @@ -99,7 +98,7 @@ int CmdEM410xRead(const char *Cmd) retest: /* We go till 5 before the graph ends because we'll get that far below */ - for (i = 1; i < bit2idx - 5; i++) + for (i = 0; i < bit2idx - 5; i++) { /* Step 2: We have our header but need our tag ID */ if (header == 9 && rows < 10) @@ -128,7 +127,7 @@ retest: PrintAndLog("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i); /* Start back rows * 5 + 9 header bits, -1 to not start at same place */ - i -= 9 + (5 * rows) - 5; + i -= 9 + (5 * rows) -2; rows = header = 0; } @@ -214,8 +213,8 @@ int CmdEM410xSim(const char *Cmd) return 0; } - PrintAndLog("Starting simulating with UID %02X %02X %02X %02X %02X", uid[0],uid[1],uid[2],uid[3],uid[4]); - + PrintAndLog("Starting simulating UID %02X%02X%02X%02X%02X", uid[0],uid[1],uid[2],uid[3],uid[4]); + PrintAndLog("Press pm3-button to about simulation"); /* clock is 64 in EM410x tags */ int clock = 64; From 5ea2c8851520ed67b42b62a25f08eb493c1ed41a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 30 Oct 2014 14:29:31 +0100 Subject: [PATCH 21/78] FIX: maybe I should actually send the uid bytes with the command request.... --- client/cmdhf15.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 8ee8be92..76e1ea9c 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -318,6 +318,8 @@ int CmdHF15Sim(const char *Cmd) uid[0],uid[1],uid[2],uid[3],uid[4], uid[5], uid[6], uid[7]); UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}}; + memcpy(c.d.asBytes,uid,8); + SendCommand(&c); return 0; } From 0222acfcf37e5cf989534852fa7fba4e764fe30a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 30 Oct 2014 15:28:45 +0100 Subject: [PATCH 22/78] ADD: Implemented a "hf 14b write" function using the CmdHF14BCmdRaw method. The function can write to SRI512 and SRIX4K tags only. Be extremly cautious when writing to Block 0xFF --- client/cmdhf14b.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ client/cmdhf14b.h | 1 + 2 files changed, 62 insertions(+) diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 25a452e6..f580e6d5 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -386,6 +386,66 @@ int CmdHF14BCmdRaw (const char *cmd) { return 0; } +int CmdHF14BWrite( const char *Cmd){ + +/* + * For SRIX4K blocks 00 - 7F + * hf 14b raw -c -p 09 $srix4kwblock $srix4kwdata + * + * For SR512 blocks 00 - 0F + * hf 14b raw -c -p 09 $sr512wblock $sr512wdata + * + * Special block FF = otp_lock_reg block. + * Data len 4 bytes- + */ + char cmdp = param_getchar(Cmd, 0); + uint8_t blockno = -1; + uint8_t data[4] = {0x00}; + bool isSrix4k = true; + char str[20]; + + if (cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf 14b write <1|2> "); + PrintAndLog(""); + PrintAndLog(" sample: hf 14b write 1 127 11223344"); + PrintAndLog(" sample: hf 14b write 1 255 11223344"); + PrintAndLog(" sample: hf 14b write 2 15 11223344"); + PrintAndLog(" sample: hf 14b write 2 255 11223344"); + return 0; + } + + if ( param_getchar(Cmd, 0) == '2' ) + isSrix4k = false; + + blockno = param_get8(Cmd, 1); + + if ( isSrix4k ){ + if ( blockno > 0x7f && blockno != 0xff ){ + PrintAndLog("Block number out of range"); + return 0; + } + } else { + if ( blockno > 0x0f && blockno != 0xff ){ + PrintAndLog("Block number out of range"); + return 0; + } + } + + if (param_gethex(Cmd, 2, data, 8)) { + PrintAndLog("Data must include 8 HEX symbols"); + return 0; + } + + if ( blockno == 0xff) + PrintAndLog("Writing to special block %02X [ %s]", blockno, sprint_hex(data,4) ); + else + PrintAndLog("Writing to block %02X [ %s]", blockno, sprint_hex(data,4) ); + + sprintf(str, "-c -p 09 %02x %02x%02x%02x%02x", blockno, data[0], data[1], data[2], data[3]); + CmdHF14BCmdRaw(str); + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -398,6 +458,7 @@ static command_t CommandTable[] = {"sri512read", CmdSri512Read, 0, "Read contents of a SRI512 tag"}, {"srix4kread", CmdSrix4kRead, 0, "Read contents of a SRIX4K tag"}, {"raw", CmdHF14BCmdRaw, 0, "Send raw hex data to tag"}, + {"write", CmdHF14BWrite, 0, "Write data to a SRI512 | SRIX4K tag"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf14b.h b/client/cmdhf14b.h index 50d64762..cc8b9dbd 100644 --- a/client/cmdhf14b.h +++ b/client/cmdhf14b.h @@ -21,5 +21,6 @@ int CmdHFSimlisten(const char *Cmd); int CmdHF14BSnoop(const char *Cmd); int CmdSri512Read(const char *Cmd); int CmdSrix4kRead(const char *Cmd); +int CmdHF14BWrite( const char *cmd); #endif From a25d5c1cdebbd9a0840620e9307ecc8a254c2315 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 31 Oct 2014 09:26:35 +0100 Subject: [PATCH 23/78] test: hf 15 sim.. --- armsrc/iso15693.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 884ed976..42cb0ab8 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -837,26 +837,27 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) // Now the VICC>VCD responses when we are simulating a tag static void BuildInventoryResponse( uint8_t *uid) { - uint8_t cmd[12]; + uint8_t cmd[13]; uint16_t crc; // one sub-carrier, inventory, 1 slot, fast rate // AFI is at bit 5 (1<<4) when doing an INVENTORY - cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1); - cmd[1] = 0; + cmd[0] = 0x0d; // COM LEN? Data 8 + 4 //(1 << 2) | (1 << 5) | (1 << 1); + cmd[1] = 0; // com_Adr + cmd[2] = 0; // status 00 = success // 64-bit UID - cmd[2] = uid[7]; //0x32; - cmd[3] = uid[6]; //0x4b; - cmd[4] = uid[5]; //0x03; - cmd[5] = uid[4]; //0x01; - cmd[6] = uid[3]; //0x00; - cmd[7] = uid[2]; //0x10; - cmd[8] = uid[1]; //0x05; - cmd[9] = uid[0]; //0xe0; + cmd[3] = uid[7]; //0x32; + cmd[4] = uid[6]; //0x4b; + cmd[5] = uid[5]; //0x03; + cmd[6] = uid[4]; //0x01; + cmd[7] = uid[3]; //0x00; + cmd[8] = uid[2]; //0x10; + cmd[9] = uid[1]; //0x05; + cmd[10] = uid[0]; //0xe0; //Now the CRC crc = Crc(cmd, 10); - cmd[10] = crc & 0xff; - cmd[11] = crc >> 8; + cmd[11] = crc & 0xff; + cmd[12] = crc >> 8; CodeIso15693AsReader(cmd, sizeof(cmd)); } From c15d2bdc9b25da89931c767902639fa7e8c9b764 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 3 Nov 2014 13:49:19 +0100 Subject: [PATCH 24/78] ADD: added identification for Mifare TNP3xxx tags. ADD: MD5-lua functionality ADD: AES 128 decrypt lua functionality ADD: test luc script for reading TNP3xxx tags CHG: testing some changes for "hf 14b sim" / "lf em4x 410xsim" --- armsrc/iso15693.c | 57 ++--- armsrc/lfops.c | 59 +++-- client/cmddata.c | 9 +- client/cmdhf14a.c | 1 + client/cmdlfem4x.c | 275 ++++++++++++++++++++- client/cmdlfem4x.h | 1 + client/graph.c | 3 + client/lualibs/htmlskel.lua | 1 + client/lualibs/md5.lua | 384 +++++++++++++++++++++++++++++ client/lualibs/mf_default_keys.lua | 8 +- client/lualibs/read14a.lua | 1 + client/scripting.c | 44 +++- client/scripts/mifare_autopwn.lua | 2 + client/scripts/tnp3.lua | 189 ++++++++++++++ include/at91sam7s512.h | 2 +- 15 files changed, 971 insertions(+), 65 deletions(-) create mode 100644 client/lualibs/md5.lua create mode 100644 client/scripts/tnp3.lua diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 42cb0ab8..11a49902 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -463,28 +463,15 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int 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; + int8_t b = (int8_t)AT91C_BASE_SSC->SSC_RHR; // The samples are correlations against I and Q versions of the // tone that the tag AM-modulates, so every other sample is I, // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. - if(getNext) { - int8_t r; + if (getNext) { - if(b < 0) { - r = -b; - } else { - r = b; - } - if(prev < 0) { - r -= prev; - } else { - r += prev; - } - - dest[c++] = (uint8_t)r; + dest[c++] = abs(b) + abs(prev); if(c >= 20000) { break; @@ -837,27 +824,27 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) // Now the VICC>VCD responses when we are simulating a tag static void BuildInventoryResponse( uint8_t *uid) { - uint8_t cmd[13]; + uint8_t cmd[12]; uint16_t crc; // one sub-carrier, inventory, 1 slot, fast rate // AFI is at bit 5 (1<<4) when doing an INVENTORY - cmd[0] = 0x0d; // COM LEN? Data 8 + 4 //(1 << 2) | (1 << 5) | (1 << 1); - cmd[1] = 0; // com_Adr - cmd[2] = 0; // status 00 = success + //(1 << 2) | (1 << 5) | (1 << 1); + cmd[0] = 0; // + cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported // 64-bit UID - cmd[3] = uid[7]; //0x32; - cmd[4] = uid[6]; //0x4b; - cmd[5] = uid[5]; //0x03; - cmd[6] = uid[4]; //0x01; - cmd[7] = uid[3]; //0x00; - cmd[8] = uid[2]; //0x10; - cmd[9] = uid[1]; //0x05; - cmd[10] = uid[0]; //0xe0; + cmd[2] = uid[7]; //0x32; + cmd[3] = uid[6]; //0x4b; + cmd[4] = uid[5]; //0x03; + cmd[5] = uid[4]; //0x01; + cmd[6] = uid[3]; //0x00; + cmd[7] = uid[2]; //0x10; + cmd[8] = uid[1]; //0x05; + cmd[9] = uid[0]; //0xe0; //Now the CRC crc = Crc(cmd, 10); - cmd[11] = crc & 0xff; - cmd[12] = crc >> 8; + cmd[10] = crc & 0xff; + cmd[11] = crc >> 8; CodeIso15693AsReader(cmd, sizeof(cmd)); } @@ -1124,9 +1111,6 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) memset(buf, 0x00, 100); - // Inventory response - BuildInventoryResponse(uid); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -1149,6 +1133,9 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) { // Build a suitable reponse to the reader INVENTORY cocmmand // not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. + + BuildInventoryResponse(uid); + TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait); } @@ -1156,6 +1143,10 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]); + Dbprintf("Simulationg uid: %x %x %x %x %x %x %x %x", + uid[0], uid[1], uid[2], uid[3], + uid[4], uid[5], uid[6], uid[7]); + LED_A_OFF(); LED_B_OFF(); LED_C_OFF(); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c80caf77..dc5efe68 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -456,21 +456,30 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + + // Connect the A/D to the peak-detected low-frequency path. + //SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + // Configure output and enable pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - - AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; // (PIO_PER) PIO Enable Register , + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; // (PIO_OER) Output Enable Register + AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; // (PIO_ODR) Output Disable Register // Give it a bit of time for the resonant antenna to settle. - SpinDelay(30); + SpinDelay(150); + + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low + + while(!BUTTON_PRESS()) { + WDT_HIT(); - for(;;) { - - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + // PIO_PDSR = Pin Data Status Register + // GPIO_SSC_CLK = SSC Transmit Clock + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { // wait for ssp_clk to go high if(BUTTON_PRESS()) { DbpString("Stopped at 0"); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off @@ -479,12 +488,21 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) WDT_HIT(); } - if ( buff[i] ) - OPEN_COIL(); - else - SHORT_COIL(); - - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + // PIO_CODR = Clear Output Data Register + // PIO_SODR = Set Output Data Register + //#define LOW(x) AT91C_BASE_PIOA->PIO_CODR = (x) + //#define HIGH(x) AT91C_BASE_PIOA->PIO_SODR = (x) + + if ( buff[i] > 0 ){ + HIGH(GPIO_SSC_DOUT); + //FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + } else { + LOW(GPIO_SSC_DOUT); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + } + + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { // wait for ssp_clk to go low if(BUTTON_PRESS()) { DbpString("Stopped at 1"); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off @@ -492,18 +510,23 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) } WDT_HIT(); } - + + //SpinDelayUs(512); + ++i; if(i == period) { i = 0; if (gap) { // turn of modulation - SHORT_COIL(); + LOW(GPIO_SSC_DOUT); // wait SpinDelay(gap); } } } + DbpString("Stopped"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + return; } #define DEBUG_FRAME_CONTENTS 1 diff --git a/client/cmddata.c b/client/cmddata.c index b01b45ba..1df3486d 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -21,6 +21,7 @@ #include "cmdmain.h" #include "cmddata.h" + static int CmdHelp(const char *Cmd); int CmdAmp(const char *Cmd) @@ -670,7 +671,9 @@ int CmdManchesterDemod(const char *Cmd) // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful // to stop output at the final bitidx2 value, not bitidx - for (i = 0; i < bitidx; i += 2) { + + //http://www.proxmark.org/forum/viewtopic.php?id=403 + for (i = 1; i < bitidx; i += 2) { if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) { BitStream[bit2idx++] = 1 ^ invert; } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) { @@ -713,7 +716,7 @@ int CmdManchesterDemod(const char *Cmd) BitStream[i+14], BitStream[i+15]); } - return 0; + return bit2idx; } /* Modulate our data into manchester */ @@ -884,7 +887,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"amp", CmdAmp, 1, "Amplify peaks"}, - {"askdemod", Cmdaskdemod, 1, "<0 or 1> -- Attempt to demodulate simple ASK tags"}, + {"askdemod", Cmdaskdemod, 1, "<0|1> -- Attempt to demodulate simple ASK tags"}, {"autocorr", CmdAutoCorr, 1, " -- Autocorrelation over window"}, {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"}, {"bitstream", CmdBitstream, 1, "[clock rate] -- Convert waveform into a bitstream"}, diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index bd19cee4..0f2b5222 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -202,6 +202,7 @@ int CmdHF14AReader(const char *Cmd) switch (card->sak) { case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break; + case 0x01: PrintAndLog("TYPE : NXP TNP3xxx Activision Game Appliance"); break; case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break; case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break; case 0x09: PrintAndLog("TYPE : NXP MIFARE Mini 0.3k"); break; diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 67013b2e..07f909ac 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -127,7 +127,7 @@ retest: PrintAndLog("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i); /* Start back rows * 5 + 9 header bits, -1 to not start at same place */ - i -= 9 + (5 * rows) -2; + i -= 9 + (5 * rows) -5; rows = header = 0; } @@ -220,11 +220,11 @@ int CmdEM410xSim(const char *Cmd) int clock = 64; /* clear our graph */ - ClearGraph(1); + ClearGraph(0); /* write it out a few times */ - for (h = 0; h < 4; h++) - { + //for (h = 0; h < 4; h++) + //{ /* write 9 start bits */ for (i = 0; i < 9; i++) AppendGraph(0, clock, 1); @@ -262,10 +262,10 @@ int CmdEM410xSim(const char *Cmd) /* stop bit */ AppendGraph(0, clock, 0); - } + //} /* modulate that biatch */ - CmdManchesterMod("64"); + //CmdManchesterMod("64"); /* booyah! */ RepaintGraphWindow(); @@ -295,7 +295,7 @@ int CmdEM410xWatch(const char *Cmd) } CmdLFRead(read_h ? "h" : ""); - CmdSamples("16000"); + CmdSamples("6000"); } while ( !CmdEM410xRead("") @@ -654,8 +654,10 @@ int CmdWriteWordPWD(const char *Cmd) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, + {"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, {"410xsim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, + {"replay", MWRem4xReplay, 0, "Watches for tag and simulates manchester encoded em4x tag"}, {"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, {"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, {"410xwrite", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, @@ -667,6 +669,265 @@ static command_t CommandTable[] = {NULL, NULL, 0, NULL} }; + +//Confirms the parity of a bitstream as well as obtaining the data (TagID) from within the appropriate memory space. +//Arguments: +// Pointer to a string containing the desired bitsream +// Pointer to a string that will receive the decoded tag ID +// Length of the bitsream pointed at in the first argument, char* _strBitStream +//Retuns: +//1 Parity confirmed +//0 Parity not confirmed +int ConfirmEm410xTagParity( char* _strBitStream, char* pID, int LengthOfBitstream ) +{ + int i = 0; + int rows = 0; + int Parity[4] = {0x00}; + char ID[11] = {0x00}; + int k = 0; + int BitStream[70] = {0x00}; + int counter = 0; + //prepare variables + for ( i = 0; i <= LengthOfBitstream; i++) + { + if (_strBitStream[i] == '1') + { + k =1; + memcpy(&BitStream[i], &k,4); + } + else if (_strBitStream[i] == '0') + { + k = 0; + memcpy(&BitStream[i], &k,4); + } + } + while ( counter < 2 ) + { + //set/reset variables and counters + memset(ID,0x00,sizeof(ID)); + memset(Parity,0x00,sizeof(Parity)); + rows = 0; + for ( i = 9; i <= LengthOfBitstream; i++) + { + if ( rows < 10 ) + { + if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4]) + { + sprintf(ID+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3])); + rows++; + /* Keep parity info and move four bits ahead*/ + Parity[0] ^= BitStream[i]; + Parity[1] ^= BitStream[i+1]; + Parity[2] ^= BitStream[i+2]; + Parity[3] ^= BitStream[i+3]; + i += 4; + } + } + if ( rows == 10 ) + { + if ( BitStream[i] == Parity[0] && BitStream[i+1] == Parity[1] && + BitStream[i+2] == Parity[2] && BitStream[i+3] == Parity[3] && + BitStream[i+4] == 0) + { + memcpy(pID,ID,strlen(ID)); + return 1; + } + } + } + printf("[PARITY ->]Failed. Flipping Bits, and rechecking parity for bitstream:\n[PARITY ->]"); + for (k = 0; k < LengthOfBitstream; k++) + { + BitStream[k] ^= 1; + printf("%i", BitStream[k]); + } + puts(" "); + counter++; + } + return 0; +} +//Reads and demodulates an em410x RFID tag. It further allows slight modification to the decoded bitstream +//Once a suitable bitstream has been identified, and if needed, modified, it is replayed. Allowing emulation of the +//"stolen" rfid tag. +//No meaningful returns or arguments. +int MWRem4xReplay(const char* Cmd) +{ + // //header traces + // static char ArrayTraceZero[] = { '0','0','0','0','0','0','0','0','0' }; + // static char ArrayTraceOne[] = { '1','1','1','1','1','1','1','1','1' }; + // //local string variables + // char strClockRate[10] = {0x00}; + // char strAnswer[4] = {0x00}; + // char strTempBufferMini[2] = {0x00}; + // //our outbound bit-stream + // char strSimulateBitStream[65] = {0x00}; + // //integers + // int iClockRate = 0; + // int needle = 0; + // int j = 0; + // int iFirstHeaderOffset = 0x00000000; + // int numManchesterDemodBits=0; + // //boolean values + // bool bInverted = false; + // //pointers to strings. memory will be allocated. + // char* pstrInvertBitStream = 0x00000000; + // char* pTempBuffer = 0x00000000; + // char* pID = 0x00000000; + // char* strBitStreamBuffer = 0x00000000; + + + // puts("###################################"); + // puts("#### Em4x Replay ##"); + // puts("#### R.A.M. June 2013 ##"); + // puts("###################################"); + // //initialize + // CmdLFRead(""); + // //Collect ourselves 10,000 samples + // CmdSamples("10000"); + // puts("[->]preforming ASK demodulation\n"); + // //demodulate ask + // Cmdaskdemod("0"); + // iClockRate = DetectClock(0); + // sprintf(strClockRate, "%i\n",iClockRate); + // printf("[->]Detected ClockRate: %s\n", strClockRate); + + // //If detected clock rate is something completely unreasonable, dont go ahead + // if ( iClockRate < 0xFFFE ) + // { + // pTempBuffer = (char*)malloc(MAX_GRAPH_TRACE_LEN); + // if (pTempBuffer == 0x00000000) + // return 0; + // memset(pTempBuffer,0x00,MAX_GRAPH_TRACE_LEN); + // //Preform manchester de-modulation and display in a single line. + // numManchesterDemodBits = CmdManchesterDemod( strClockRate ); + // //note: numManchesterDemodBits is set above in CmdManchesterDemod() + // if ( numManchesterDemodBits == 0 ) + // return 0; + // strBitStreamBuffer = malloc(numManchesterDemodBits+1); + // if ( strBitStreamBuffer == 0x00000000 ) + // return 0; + // memset(strBitStreamBuffer, 0x00, (numManchesterDemodBits+1)); + // //fill strBitStreamBuffer with demodulated, string formatted bits. + // for ( j = 0; j <= numManchesterDemodBits; j++ ) + // { + // sprintf(strTempBufferMini, "%i",BitStream[j]); + // strcat(strBitStreamBuffer,strTempBufferMini); + // } + // printf("[->]Demodulated Bitstream: \n%s\n", strBitStreamBuffer); + // //Reset counter and select most probable bit stream + // j = 0; + // while ( j < numManchesterDemodBits ) + // { + // memset(strSimulateBitStream,0x00,64); + // //search for header of nine (9) 0's : 000000000 or nine (9) 1's : 1111 1111 1 + // if ( ( strncmp(strBitStreamBuffer+j, ArrayTraceZero, sizeof(ArrayTraceZero)) == 0 ) || + // ( strncmp(strBitStreamBuffer+j, ArrayTraceOne, sizeof(ArrayTraceOne)) == 0 ) ) + // { + // iFirstHeaderOffset = j; + // memcpy(strSimulateBitStream, strBitStreamBuffer+j,64); + // printf("[->]Offset of Header"); + // if ( strncmp(strBitStreamBuffer+iFirstHeaderOffset, "0", 1) == 0 ) + // printf("'%s'", ArrayTraceZero ); + // else + // printf("'%s'", ArrayTraceOne ); + // printf(": %i\nHighlighted string : %s\n",iFirstHeaderOffset,strSimulateBitStream); + // //allow us to escape loop or choose another frame + // puts("[<-]Are we happy with this sample? [Y]es/[N]o"); + // gets(strAnswer); + // if ( ( strncmp(strAnswer,"y",1) == 0 ) || ( strncmp(strAnswer,"Y",1) == 0 ) ) + // { + // j = numManchesterDemodBits+1; + // break; + // } + // } + // j++; + // } + // } + // else return 0; + + // //Do we want the buffer inverted? + // memset(strAnswer, 0x00, sizeof(strAnswer)); + // printf("[<-]Do you wish to invert the highlighted bitstream? [Y]es/[N]o\n"); + // gets(strAnswer); + // if ( ( strncmp("y", strAnswer,1) == 0 ) || ( strncmp("Y", strAnswer, 1 ) == 0 ) ) + // { + // //allocate heap memory + // pstrInvertBitStream = (char*)malloc(numManchesterDemodBits); + // if ( pstrInvertBitStream != 0x00000000 ) + // { + // memset(pstrInvertBitStream,0x00,numManchesterDemodBits); + // bInverted = true; + // //Invert Bitstream + // for ( needle = 0; needle <= numManchesterDemodBits; needle++ ) + // { + // if (strSimulateBitStream[needle] == '0') + // strcat(pstrInvertBitStream,"1"); + // else if (strSimulateBitStream[needle] == '1') + // strcat(pstrInvertBitStream,"0"); + // } + // printf("[->]Inverted bitstream: %s\n", pstrInvertBitStream); + // } + // } + // //Confirm parity of selected string + // pID = (char*)malloc(11); + // if (pID != 0x00000000) + // { + // memset(pID, 0x00, 11); + // if (ConfirmEm410xTagParity(strSimulateBitStream,pID, 64) == 1) + // { + // printf("[->]Parity confirmed for selected bitstream!\n"); + // printf("[->]Tag ID was detected as: [hex]:%s\n",pID ); + // } + // else + // printf("[->]Parity check failed for the selected bitstream!\n"); + // } + + // //Spoof + // memset(strAnswer, 0x00, sizeof(strAnswer)); + // printf("[<-]Do you wish to continue with the EM4x simulation? [Y]es/[N]o\n"); + // gets(strAnswer); + // if ( ( strncmp(strAnswer,"y",1) == 0 ) || ( strncmp(strAnswer,"Y",1) == 0 ) ) + // { + // strcat(pTempBuffer, strClockRate); + // strcat(pTempBuffer, " "); + // if (bInverted == true) + // strcat(pTempBuffer,pstrInvertBitStream); + // if (bInverted == false) + // strcat(pTempBuffer,strSimulateBitStream); + // //inform the user + // puts("[->]Starting simulation now: \n"); + // //Simulate tag with prepared buffer. + // CmdLFSimManchester(pTempBuffer); + // } + // else if ( ( strcmp("n", strAnswer) == 0 ) || ( strcmp("N", strAnswer ) == 0 ) ) + // printf("[->]Exiting procedure now...\n"); + // else + // printf("[->]Erroneous selection\nExiting procedure now....\n"); + + // //Clean up -- Exit function + // //clear memory, then release pointer. + // if ( pstrInvertBitStream != 0x00000000 ) + // { + // memset(pstrInvertBitStream,0x00,numManchesterDemodBits); + // free(pstrInvertBitStream); + // } + // if ( pTempBuffer != 0x00000000 ) + // { + // memset(pTempBuffer,0x00,MAX_GRAPH_TRACE_LEN); + // free(pTempBuffer); + // } + // if ( pID != 0x00000000 ) + // { + // memset(pID,0x00,11); + // free(pID); + // } + // if ( strBitStreamBuffer != 0x00000000 ) + // { + // memset(strBitStreamBuffer,0x00,numManchesterDemodBits); + // free(strBitStreamBuffer); + // } + return 0; +} + int CmdLFEM4X(const char *Cmd) { CmdsParse(CommandTable, Cmd); diff --git a/client/cmdlfem4x.h b/client/cmdlfem4x.h index a209e8f9..587dbf7f 100644 --- a/client/cmdlfem4x.h +++ b/client/cmdlfem4x.h @@ -22,5 +22,6 @@ int CmdReadWord(const char *Cmd); int CmdReadWordPWD(const char *Cmd); int CmdWriteWord(const char *Cmd); int CmdWriteWordPWD(const char *Cmd); +int MWRem4xReplay(const char* Cmd); #endif diff --git a/client/graph.c b/client/graph.c index 4e8cb89c..7b45f3f2 100644 --- a/client/graph.c +++ b/client/graph.c @@ -89,6 +89,9 @@ int DetectClock(int peak) case 1: clock--; break; case 2: clock -= 2; break; } + if ( clock < 32) + clock = 32; + printf("- adjusted it to %d \n", clock); return clock; } diff --git a/client/lualibs/htmlskel.lua b/client/lualibs/htmlskel.lua index a52abdef..b468eb2d 100644 --- a/client/lualibs/htmlskel.lua +++ b/client/lualibs/htmlskel.lua @@ -55,6 +55,7 @@ local skel_1 = [[ return "UNKNOWN" } + add("04,,,Mifare TNP3xxx Activision 1K,0f01,01"); add("04,,,Mifare Mini,0004,09"); add("04,,,Mifare Classic 1k/Mifare Plus(4 byte UID) 2K SL1,0004,08"); add("04,,,Mifare Plus (4 byte UID) 2K SL2,0004,10"); diff --git a/client/lualibs/md5.lua b/client/lualibs/md5.lua new file mode 100644 index 00000000..2390f957 --- /dev/null +++ b/client/lualibs/md5.lua @@ -0,0 +1,384 @@ +local md5 = { + _VERSION = "md5.lua 0.5.0", + _DESCRIPTION = "MD5 computation in Lua (5.1)", + _URL = "https://github.com/kikito/md5.lua", + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +-- bit lib implementions + +local floor, abs, max = math.floor, math.abs, math.max +local char, byte, format, rep, sub = + string.char, string.byte, string.format, string.rep, string.sub + +local function check_int(n) + -- checking not float + if(n - floor(n) > 0) then + error("trying to use bitwise operation on non-integer!") + end +end + +local function tbl2number(tbl) + local n = #tbl + + local rslt = 0 + local power = 1 + for i = 1, n do + rslt = rslt + tbl[i]*power + power = power*2 + end + + return rslt +end + +local function expand(tbl_m, tbl_n) + local big = {} + local small = {} + if(#tbl_m > #tbl_n) then + big = tbl_m + small = tbl_n + else + big = tbl_n + small = tbl_m + end + -- expand small + for i = #small + 1, #big do + small[i] = 0 + end + +end + +local to_bits -- needs to be declared before bit_not + +local function bit_not(n) + local tbl = to_bits(n) + local size = max(#tbl, 32) + for i = 1, size do + if(tbl[i] == 1) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + return tbl2number(tbl) +end + +-- defined as local above +to_bits = function (n) + check_int(n) + if(n < 0) then + -- negative + return to_bits(bit_not(abs(n)) + 1) + end + -- to bits table + local tbl = {} + local cnt = 1 + while (n > 0) do + local last = math.fmod(n,2) + if(last == 1) then + tbl[cnt] = 1 + else + tbl[cnt] = 0 + end + n = (n-last)/2 + cnt = cnt + 1 + end + + return tbl +end + +local function bit_or(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + local rslt = max(#tbl_m, #tbl_n) + for i = 1, rslt do + if(tbl_m[i]== 0 and tbl_n[i] == 0) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + + return tbl2number(tbl) +end + +local function bit_and(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + local rslt = max(#tbl_m, #tbl_n) + for i = 1, rslt do + if(tbl_m[i]== 0 or tbl_n[i] == 0) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + + return tbl2number(tbl) +end + +local function bit_xor(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + local rslt = max(#tbl_m, #tbl_n) + for i = 1, rslt do + if(tbl_m[i] ~= tbl_n[i]) then + tbl[i] = 1 + else + tbl[i] = 0 + end + end + + return tbl2number(tbl) +end + +local function bit_rshift(n, bits) + check_int(n) + + local high_bit = 0 + if(n < 0) then + -- negative + n = bit_not(abs(n)) + 1 + high_bit = 2147483648 -- 0x80000000 + end + + for i=1, bits do + n = n/2 + n = bit_or(floor(n), high_bit) + end + return floor(n) +end + +local function bit_lshift(n, bits) + check_int(n) + + if(n < 0) then + -- negative + n = bit_not(abs(n)) + 1 + end + + for i=1, bits do + n = n*2 + end + return bit_and(n, 4294967295) -- 0xFFFFFFFF +end + +-- convert little-endian 32-bit int to a 4-char string +local function lei2str(i) + local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end + return f(0)..f(8)..f(16)..f(24) +end + +-- convert raw string to big-endian int +local function str2bei(s) + local v=0 + for i=1, #s do + v = v * 256 + byte(s, i) + end + return v +end + +-- convert raw string to little-endian int +local function str2lei(s) + local v=0 + for i = #s,1,-1 do + v = v*256 + byte(s, i) + end + return v +end + +-- cut up a string in little-endian ints of given size +local function cut_le_str(s,...) + local o, r = 1, {} + local args = {...} + for i=1, #args do + table.insert(r, str2lei(sub(s, o, o + args[i] - 1))) + o = o + args[i] + end + return r +end + +local swap = function (w) return str2bei(lei2str(w)) end + +local function hex2binaryaux(hexval) + return char(tonumber(hexval, 16)) +end + +local function hex2binary(hex) + local result, _ = hex:gsub('..', hex2binaryaux) + return result +end + +-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) +-- 10/02/2001 jcw@equi4.com + +local FF = 0xffffffff +local CONSTS = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 +} + +local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end +local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end +local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end +local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end +local z=function (f,a,b,c,d,x,s,ac) + a=bit_and(a+f(b,c,d)+x+ac,FF) + -- be *very* careful that left shift does not cause rounding! + return bit_or(bit_lshift(bit_and(a,bit_rshift(FF,s)),s),bit_rshift(a,32-s))+b +end + +local function transform(A,B,C,D,X) + local a,b,c,d=A,B,C,D + local t=CONSTS + + a=z(f,a,b,c,d,X[ 0], 7,t[ 1]) + d=z(f,d,a,b,c,X[ 1],12,t[ 2]) + c=z(f,c,d,a,b,X[ 2],17,t[ 3]) + b=z(f,b,c,d,a,X[ 3],22,t[ 4]) + a=z(f,a,b,c,d,X[ 4], 7,t[ 5]) + d=z(f,d,a,b,c,X[ 5],12,t[ 6]) + c=z(f,c,d,a,b,X[ 6],17,t[ 7]) + b=z(f,b,c,d,a,X[ 7],22,t[ 8]) + a=z(f,a,b,c,d,X[ 8], 7,t[ 9]) + d=z(f,d,a,b,c,X[ 9],12,t[10]) + c=z(f,c,d,a,b,X[10],17,t[11]) + b=z(f,b,c,d,a,X[11],22,t[12]) + a=z(f,a,b,c,d,X[12], 7,t[13]) + d=z(f,d,a,b,c,X[13],12,t[14]) + c=z(f,c,d,a,b,X[14],17,t[15]) + b=z(f,b,c,d,a,X[15],22,t[16]) + + a=z(g,a,b,c,d,X[ 1], 5,t[17]) + d=z(g,d,a,b,c,X[ 6], 9,t[18]) + c=z(g,c,d,a,b,X[11],14,t[19]) + b=z(g,b,c,d,a,X[ 0],20,t[20]) + a=z(g,a,b,c,d,X[ 5], 5,t[21]) + d=z(g,d,a,b,c,X[10], 9,t[22]) + c=z(g,c,d,a,b,X[15],14,t[23]) + b=z(g,b,c,d,a,X[ 4],20,t[24]) + a=z(g,a,b,c,d,X[ 9], 5,t[25]) + d=z(g,d,a,b,c,X[14], 9,t[26]) + c=z(g,c,d,a,b,X[ 3],14,t[27]) + b=z(g,b,c,d,a,X[ 8],20,t[28]) + a=z(g,a,b,c,d,X[13], 5,t[29]) + d=z(g,d,a,b,c,X[ 2], 9,t[30]) + c=z(g,c,d,a,b,X[ 7],14,t[31]) + b=z(g,b,c,d,a,X[12],20,t[32]) + + a=z(h,a,b,c,d,X[ 5], 4,t[33]) + d=z(h,d,a,b,c,X[ 8],11,t[34]) + c=z(h,c,d,a,b,X[11],16,t[35]) + b=z(h,b,c,d,a,X[14],23,t[36]) + a=z(h,a,b,c,d,X[ 1], 4,t[37]) + d=z(h,d,a,b,c,X[ 4],11,t[38]) + c=z(h,c,d,a,b,X[ 7],16,t[39]) + b=z(h,b,c,d,a,X[10],23,t[40]) + a=z(h,a,b,c,d,X[13], 4,t[41]) + d=z(h,d,a,b,c,X[ 0],11,t[42]) + c=z(h,c,d,a,b,X[ 3],16,t[43]) + b=z(h,b,c,d,a,X[ 6],23,t[44]) + a=z(h,a,b,c,d,X[ 9], 4,t[45]) + d=z(h,d,a,b,c,X[12],11,t[46]) + c=z(h,c,d,a,b,X[15],16,t[47]) + b=z(h,b,c,d,a,X[ 2],23,t[48]) + + a=z(i,a,b,c,d,X[ 0], 6,t[49]) + d=z(i,d,a,b,c,X[ 7],10,t[50]) + c=z(i,c,d,a,b,X[14],15,t[51]) + b=z(i,b,c,d,a,X[ 5],21,t[52]) + a=z(i,a,b,c,d,X[12], 6,t[53]) + d=z(i,d,a,b,c,X[ 3],10,t[54]) + c=z(i,c,d,a,b,X[10],15,t[55]) + b=z(i,b,c,d,a,X[ 1],21,t[56]) + a=z(i,a,b,c,d,X[ 8], 6,t[57]) + d=z(i,d,a,b,c,X[15],10,t[58]) + c=z(i,c,d,a,b,X[ 6],15,t[59]) + b=z(i,b,c,d,a,X[13],21,t[60]) + a=z(i,a,b,c,d,X[ 4], 6,t[61]) + d=z(i,d,a,b,c,X[11],10,t[62]) + c=z(i,c,d,a,b,X[ 2],15,t[63]) + b=z(i,b,c,d,a,X[ 9],21,t[64]) + + return A+a,B+b,C+c,D+d +end + +---------------------------------------------------------------- + +function md5.sumhexa(s) + local msgLen = #s + local padLen = 56 - msgLen % 64 + + if msgLen % 64 > 56 then padLen = padLen + 64 end + + if padLen == 0 then padLen = 64 end + + s = s .. char(128) .. rep(char(0),padLen-1) .. lei2str(8*msgLen) .. lei2str(0) + + assert(#s % 64 == 0) + + local t = CONSTS + local a,b,c,d = t[65],t[66],t[67],t[68] + + for i=1,#s,64 do + local X = cut_le_str(sub(s,i,i+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) + assert(#X == 16) + X[0] = table.remove(X,1) -- zero based! + a,b,c,d = transform(a,b,c,d,X) + end + + return format("%08x%08x%08x%08x",swap(a),swap(b),swap(c),swap(d)) +end + +function md5.sum(s) + return hex2binary(md5.sumhexa(s)) +end + +return md5 diff --git a/client/lualibs/mf_default_keys.lua b/client/lualibs/mf_default_keys.lua index 4859ff0c..b9b414d8 100644 --- a/client/lualibs/mf_default_keys.lua +++ b/client/lualibs/mf_default_keys.lua @@ -141,7 +141,13 @@ local _keys = { '200000000000', 'a00000000000', 'b00000000000', - } + + --[[ + Should be for Mifare TNP3xxx tags A KEY. + --]] + '4b0b20107ccb', + +} --- -- The keys above have just been pasted in, for completeness sake. They contain duplicates. diff --git a/client/lualibs/read14a.lua b/client/lualibs/read14a.lua index 24021a1d..10e7c2d4 100644 --- a/client/lualibs/read14a.lua +++ b/client/lualibs/read14a.lua @@ -25,6 +25,7 @@ local ISO14A_COMMAND = { local ISO14443a_TYPES = {} ISO14443a_TYPES[0x00] = "NXP MIFARE Ultralight | Ultralight C" +ISO14443a_TYPES[0x01] = "NXP MIFARE TNP3xxx Activision Game Appliance" ISO14443a_TYPES[0x04] = "NXP MIFARE (various !DESFire !DESFire EV1)" ISO14443a_TYPES[0x08] = "NXP MIFARE CLASSIC 1k | Plus 2k" ISO14443a_TYPES[0x09] = "NXP MIFARE Mini 0.3k" diff --git a/client/scripting.c b/client/scripting.c index 963bb64c..fd065a04 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -18,6 +18,7 @@ #include "util.h" #include "nonce2key/nonce2key.h" #include "../common/iso15693tools.h" +#include /** * The following params expected: * UsbCommand c @@ -224,6 +225,44 @@ static int l_iso15693_crc(lua_State *L) return 1; } +/* + Simple AES 128 cbc hook up to OpenSSL. + params: key, input +*/ +static int l_aes(lua_State *L) +{ + //Check number of arguments + int i; + size_t size; + const char *p_key = luaL_checklstring(L, 1, &size); + if(size != 32) return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size); + + const char *p_encTxt = luaL_checklstring(L, 2, &size); + + unsigned char indata[AES_BLOCK_SIZE] = {0x00}; + unsigned char outdata[AES_BLOCK_SIZE] = {0x00}; + unsigned char aes_key[AES_BLOCK_SIZE] = {0x00}; + unsigned char iv[AES_BLOCK_SIZE] = {0x00}; + + // convert key to bytearray + for (i = 0; i < 32; i += 2) { + sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]); + } + + // convert input to bytearray + for (i = 0; i < 32; i += 2) { + sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]); + } + + AES_KEY key; + AES_set_decrypt_key(aes_key, 128, &key); + AES_cbc_encrypt(indata, outdata, sizeof(indata), &key, iv, AES_DECRYPT); + + //Push decrypted array as a string + lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); + return 1;// return 1 to signal one return value +} + /** * @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be * able to do "require('foobar')" if foobar.lua is within lualibs folder. @@ -259,8 +298,9 @@ int set_pm3_libraries(lua_State *L) {"foobar", l_foobar}, {"ukbhit", l_ukbhit}, {"clearCommandBuffer", l_clearCommandBuffer}, - {"console", l_CmdConsole}, - {"iso15693_crc", l_iso15693_crc}, + {"console", l_CmdConsole}, + {"iso15693_crc", l_iso15693_crc}, + {"aes", l_aes}, {NULL, NULL} }; diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index 8d0d358f..eb98ffbf 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -133,6 +133,8 @@ function nested(key,sak) typ = 0 elseif 0x10 == sak then-- "NXP MIFARE Plus 2k" typ = 2 + elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K" + typ = 1 else print("I don't know how many sectors there are on this type of card, defaulting to 16") end diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua new file mode 100644 index 00000000..3eb5af1c --- /dev/null +++ b/client/scripts/tnp3.lua @@ -0,0 +1,189 @@ +local cmds = require('commands') +local getopt = require('getopt') +local bin = require('bin') +local lib14a = require('read14a') +local utils = require('utils') +local md5 = require('md5') + +example =[[ + 1. script run tnp3 + 2. script run tnp3 -k aabbccddeeff +]] +author = "Iceman" +usage = "script run tnp3 -k " +desc =[[ +This script will try to dump the contents of a Mifare TNP3xxx card. +It will need a valid KeyA in order to find the other keys and decode the card. +Arguments: + -h - this help + -k - Sector 0 Key A. +]] + +local hashconstant = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' + +local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds +local DEBUG = true -- the debug flag +local numBlocks = 64 +local numSectors = 16 +--- +-- A debug printout-function +function dbg(args) + if not DEBUG then + return + end + + if type(args) == "table" then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print("###", args) + end +end +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) +end +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end +-- +-- Exit message +function ExitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + +local function show(data) + if DEBUG then + local formatString = ("H%d"):format(string.len(data)) + local _,hexdata = bin.unpack(formatString, data) + dbg("Hexdata" , hexdata) + end +end + +function waitCmd() + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) + if response then + local count,cmd,arg0 = bin.unpack('LL',response) + if(arg0==1) then + local count,arg1,arg2,data = bin.unpack('LLH511',response,count) + return data:sub(1,32) + else + return nil, "Couldn't read block.." + end + end + return nil, "No response from device" +end + +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + local keyA + local cmd + local err + local cmdReadBlockString = 'hf mf rdbl %d A %s' + + -- Arguments for the script + for o, a in getopt.getopt(args, 'hk:') do + if o == "h" then return help() end + if o == "k" then keyA = a end + end + + -- validate input args. + keyA = keyA or '4b0b20107ccb' + if #(keyA) ~= 12 then + return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA)) + end + + result, err = lib14a.read1443a(false) + if not result then + print(err) + return + end + print((" Found tag : %s"):format(result.name)) + + core.clearCommandBuffer() + + if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx + print("This is not a TNP3xxx tag. aborting.") + return + end + + -- Show info + print(('Using keyA : %s'):format(keyA)) + print( string.rep('--',20) ) + + local cmdNestedString = 'hf mf nested 1 0 A %s d' + local cmdDumpString = 'hf mf dump' + --core.console(cmdNestedString.format(keyA) ) + --core.console(cmdDumpString) + + print('Reading data need to dump data') + + -- Read block 0 + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA} + err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local block0, err = waitCmd() + if err then return oops(err) end + + -- Read block 1 + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1,arg2 = 0,arg3 = 0, data = keyA} + local err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local block1, err = waitCmd() + if err then return oops(err) end + + + -- Read block 9 + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 9,arg2 = 0,arg3 = 0, data = '56f6313550f9'} + local err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local block9, err = waitCmd() + if err then return oops(err) end + + -- main loop + print('BLOCK MD5 DECRYPTED ASCII' ) + + for block=0,numBlocks-1,1 do + + if math.fmod(block,4) then + + end + + local base = ('%s%s%02d%s'):format(block0, block1, block, hashconstant) + local md5hash = md5.sumhexa(base) + local aestest = core.aes(md5hash, block9 ) + + local _,hex = bin.unpack(("H%d"):format(16),aestest) + + + local hexascii = string.gsub(hex, '(%x%x)', + function(value) + return string.char(tonumber(value, 16)) + end + ) + + print( block .. ' :: ' .. md5hash .. ' :: ' .. hex .. ' :: ' .. hexascii ) + + -- if core.ukbhit() then + -- print("aborted by user") + -- break + -- end + end +end + +main(args) \ No newline at end of file diff --git a/include/at91sam7s512.h b/include/at91sam7s512.h index 5be13622..2cdcbce3 100644 --- a/include/at91sam7s512.h +++ b/include/at91sam7s512.h @@ -428,7 +428,7 @@ typedef struct _AT91S_PIO { #define PIO_PDR (AT91_CAST(AT91_REG *) 0x00000004) // (PIO_PDR) PIO Disable Register #define PIO_PSR (AT91_CAST(AT91_REG *) 0x00000008) // (PIO_PSR) PIO Status Register #define PIO_OER (AT91_CAST(AT91_REG *) 0x00000010) // (PIO_OER) Output Enable Register -#define PIO_ODR (AT91_CAST(AT91_REG *) 0x00000014) // (PIO_ODR) Output Disable Registerr +#define PIO_ODR (AT91_CAST(AT91_REG *) 0x00000014) // (PIO_ODR) Output Disable Register #define PIO_OSR (AT91_CAST(AT91_REG *) 0x00000018) // (PIO_OSR) Output Status Register #define PIO_IFER (AT91_CAST(AT91_REG *) 0x00000020) // (PIO_IFER) Input Filter Enable Register #define PIO_IFDR (AT91_CAST(AT91_REG *) 0x00000024) // (PIO_IFDR) Input Filter Disable Register From c70cef9734647bed49c76a78f5a10c086e0f2ffc Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 3 Nov 2014 15:25:54 +0100 Subject: [PATCH 25/78] fixing scripts/tnp3.lua --- client/scripts/tnp3.lua | 80 +++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index 3eb5af1c..ea7c3a23 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -71,7 +71,15 @@ local function show(data) end end -function waitCmd() +local function readdumpkeys(infile) + t = infile:read("*all") + len = string.len(t) + local len,hex = bin.unpack(("H%d"):format(len),t) + --print(len,hex) + return hex +end + +local function waitCmd() local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) if response then local count,cmd,arg0 = bin.unpack('LL',response) @@ -95,6 +103,7 @@ local function main(args) local cmd local err local cmdReadBlockString = 'hf mf rdbl %d A %s' + local input = "dumpkeys.bin" -- Arguments for the script for o, a in getopt.getopt(args, 'hk:') do @@ -113,12 +122,12 @@ local function main(args) print(err) return end - print((" Found tag : %s"):format(result.name)) + print((' Found tag : %s'):format(result.name)) core.clearCommandBuffer() if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx - print("This is not a TNP3xxx tag. aborting.") + print('This is not a TNP3xxx tag. aborting.') return end @@ -126,11 +135,18 @@ local function main(args) print(('Using keyA : %s'):format(keyA)) print( string.rep('--',20) ) - local cmdNestedString = 'hf mf nested 1 0 A %s d' - local cmdDumpString = 'hf mf dump' - --core.console(cmdNestedString.format(keyA) ) - --core.console(cmdDumpString) + print('Trying to find other keys. ') + --core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) + + -- Reading found keys file + local infile = io.open(input, "rb") + if infile == nil then + return oops('Could not read file ', input) + end + local akeys = readdumpkeys(infile):sub(0,12*16) + --print( ('KEYS: %s'):format(akeys)) + print('Reading data need to dump data') -- Read block 0 @@ -147,42 +163,46 @@ local function main(args) local block1, err = waitCmd() if err then return oops(err) end + print('Dumping data') - -- Read block 9 - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 9,arg2 = 0,arg3 = 0, data = '56f6313550f9'} - local err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local block9, err = waitCmd() - if err then return oops(err) end - -- main loop print('BLOCK MD5 DECRYPTED ASCII' ) + + local key + local keyPosStart = 0 + local block + for block = 0, numBlocks-1, 1 do + local b = (block+1)%4 + if b ~= 0 then + keyPosStart = (math.floor( block / 4 ) * 12)+1 + key = akeys:sub(keyPosStart, keyPosStart + 12 ) + --print( ('%02d %s'):format(block, key)) - for block=0,numBlocks-1,1 do + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = block ,arg2 = 0,arg3 = 0, data = key} + local err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local blockdata, err = waitCmd() + if err then return oops(err) end - if math.fmod(block,4) then - - end + local base = ('%s%s%02d%s'):format(block0, block1, block, hashconstant) + local md5hash = md5.sumhexa(base) + local aestest = core.aes(md5hash, blockdata) - local base = ('%s%s%02d%s'):format(block0, block1, block, hashconstant) - local md5hash = md5.sumhexa(base) - local aestest = core.aes(md5hash, block9 ) + local _,hex = bin.unpack(("H%d"):format(16),aestest) - local _,hex = bin.unpack(("H%d"):format(16),aestest) - - - local hexascii = string.gsub(hex, '(%x%x)', + local hexascii = string.gsub(hex, '(%x%x)', function(value) return string.char(tonumber(value, 16)) end ) - print( block .. ' :: ' .. md5hash .. ' :: ' .. hex .. ' :: ' .. hexascii ) + print( ('%02d :: %s :: %s :: %s :: %s'):format(block,key,md5hash,hex,hexascii) ) - -- if core.ukbhit() then - -- print("aborted by user") - -- break - -- end + if core.ukbhit() then + print("aborted by user") + break + end + end end end From 8aa79dee20c4df50734897c979b17bcf387c77f6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 3 Nov 2014 21:59:31 +0100 Subject: [PATCH 26/78] FIX: added some tnp3xxx identification i formatMifare.lua FIX: tnp3.lua is more or less finished. Needs testing. --- armsrc/lfops.c | 4 +- client/scripts/formatMifare.lua | 10 ++-- client/scripts/tnp3.lua | 97 +++++++++++++++++---------------- 3 files changed, 58 insertions(+), 53 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index dc5efe68..1a7c3224 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -452,7 +452,7 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) void SimulateTagLowFrequency(int period, int gap, int ledcontrol) { int i = 0; - uint8_t *buff = (uint8_t *)BigBuf; + uint8_t *buf = (uint8_t *)BigBuf; FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz @@ -493,7 +493,7 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) //#define LOW(x) AT91C_BASE_PIOA->PIO_CODR = (x) //#define HIGH(x) AT91C_BASE_PIOA->PIO_SODR = (x) - if ( buff[i] > 0 ){ + if ( buf[i] > 0 ){ HIGH(GPIO_SSC_DOUT); //FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); diff --git a/client/scripts/formatMifare.lua b/client/scripts/formatMifare.lua index 1ced0c28..66a61fba 100644 --- a/client/scripts/formatMifare.lua +++ b/client/scripts/formatMifare.lua @@ -80,18 +80,20 @@ function GetCardInfo() core.clearCommandBuffer() - if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k + if 0x18 == result.sak then -- NXP MIFARE Classic 4k | Plus 4k -- IFARE Classic 4K offers 4096 bytes split into forty sectors, -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. numSectors = 40 - elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k + elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k -- 1K offers 1024 bytes of data storage, split into 16 sector numSectors = 16 - elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k + elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k -- MIFARE Classic mini offers 320 bytes split into five sectors. numSectors = 5 - elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k" + elseif 0x10 == result.sak then -- NXP MIFARE Plus 2k numSectors = 32 + elseif 0x01 == sak then -- NXP MIFARE TNP3xxx 1K + numSectors = 16 else print("I don't know how many sectors there are on this type of card, defaulting to 16") end diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index ea7c3a23..ebe1c6db 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -7,18 +7,23 @@ local md5 = require('md5') example =[[ 1. script run tnp3 - 2. script run tnp3 -k aabbccddeeff + 2. script run tnp3 -n + 3. script run tnp3 -k aabbccddeeff + 4. script run tnp3 -k aabbccddeeff -n ]] author = "Iceman" -usage = "script run tnp3 -k " +usage = "script run tnp3 -k -n" desc =[[ This script will try to dump the contents of a Mifare TNP3xxx card. It will need a valid KeyA in order to find the other keys and decode the card. Arguments: - -h - this help - -k - Sector 0 Key A. + -h : this help + -k : Sector 0 Key A. + -n : Use the nested cmd to find all keys ]] +-- AES konstant? LEN 0x24 36, +-- I dekompilen är det för internal static array = 0x36 54 local hashconstant = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds @@ -63,19 +68,10 @@ function ExitMsg(msg) print() end -local function show(data) - if DEBUG then - local formatString = ("H%d"):format(string.len(data)) - local _,hexdata = bin.unpack(formatString, data) - dbg("Hexdata" , hexdata) - end -end - local function readdumpkeys(infile) t = infile:read("*all") len = string.len(t) local len,hex = bin.unpack(("H%d"):format(len),t) - --print(len,hex) return hex end @@ -102,13 +98,15 @@ local function main(args) local keyA local cmd local err + local useNested = false local cmdReadBlockString = 'hf mf rdbl %d A %s' local input = "dumpkeys.bin" -- Arguments for the script - for o, a in getopt.getopt(args, 'hk:') do + for o, a in getopt.getopt(args, 'hk:n') do if o == "h" then return help() end if o == "k" then keyA = a end + if o == "n" then useNested = true end end -- validate input args. @@ -119,36 +117,33 @@ local function main(args) result, err = lib14a.read1443a(false) if not result then - print(err) - return + return oops(err) end + print((' Found tag : %s'):format(result.name)) core.clearCommandBuffer() if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx - print('This is not a TNP3xxx tag. aborting.') - return + return oops('This is not a TNP3xxx tag. aborting.') end -- Show info print(('Using keyA : %s'):format(keyA)) print( string.rep('--',20) ) - print('Trying to find other keys. ') - --core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) + print('Trying to find other keys.') + if useNested then + core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) + end - -- Reading found keys file + -- Loading keyfile local infile = io.open(input, "rb") if infile == nil then return oops('Could not read file ', input) end local akeys = readdumpkeys(infile):sub(0,12*16) - --print( ('KEYS: %s'):format(akeys)) - - print('Reading data need to dump data') - -- Read block 0 cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA} err = core.SendCommand(cmd:getBytes()) @@ -158,45 +153,46 @@ local function main(args) -- Read block 1 cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1,arg2 = 0,arg3 = 0, data = keyA} - local err = core.SendCommand(cmd:getBytes()) + err = core.SendCommand(cmd:getBytes()) if err then return oops(err) end local block1, err = waitCmd() if err then return oops(err) end - print('Dumping data') + local key + local pos = 0 + local blockNo + local blocks = {} -- main loop - print('BLOCK MD5 DECRYPTED ASCII' ) - - local key - local keyPosStart = 0 - local block - for block = 0, numBlocks-1, 1 do - local b = (block+1)%4 - if b ~= 0 then - keyPosStart = (math.floor( block / 4 ) * 12)+1 - key = akeys:sub(keyPosStart, keyPosStart + 12 ) - --print( ('%02d %s'):format(block, key)) - - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = block ,arg2 = 0,arg3 = 0, data = key} + for blockNo = 8, numBlocks-1, 1 do + local b = blockNo%4 + if b ~= 3 then + pos = (math.floor( blockNo / 4 ) * 12)+1 + key = akeys:sub(pos, pos + 12 ) + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key} local err = core.SendCommand(cmd:getBytes()) if err then return oops(err) end local blockdata, err = waitCmd() if err then return oops(err) end - local base = ('%s%s%02d%s'):format(block0, block1, block, hashconstant) + local base = ('%s%s%d%s'):format(block0, block1, blockNo, hashconstant) local md5hash = md5.sumhexa(base) local aestest = core.aes(md5hash, blockdata) local _,hex = bin.unpack(("H%d"):format(16),aestest) - local hexascii = string.gsub(hex, '(%x%x)', - function(value) - return string.char(tonumber(value, 16)) - end - ) + -- local hexascii = string.gsub(hex, '(%x%x)', + -- function(value) + -- return string.char(tonumber(value, 16)) + -- end + -- ) - print( ('%02d :: %s :: %s :: %s :: %s'):format(block,key,md5hash,hex,hexascii) ) + if string.find(blockdata, '^0+$') then + blocks[blockNo] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) + else + --blocks[blockNo] = ('%02d :: %s :: %s :: %s '):format(blockNo,key,md5hash,hex) + blocks[blockNo] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) + end if core.ukbhit() then print("aborted by user") @@ -204,6 +200,13 @@ local function main(args) end end end + + -- Print results + print('BLK :: DATA DECRYPTED' ) + print( string.rep('--',36) ) + for _,s in pairs(blocks) do + print( s ) + end end main(args) \ No newline at end of file From 1a5ff2c2a7feaaf2ba6dc83bee611d1cab5f4527 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 3 Nov 2014 22:29:43 +0100 Subject: [PATCH 27/78] FIX: fixed the layout of data in tnp3.lua --- client/scripts/tnp3.lua | 77 ++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index ebe1c6db..5b3da98f 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -132,12 +132,14 @@ local function main(args) print(('Using keyA : %s'):format(keyA)) print( string.rep('--',20) ) - print('Trying to find other keys.') + if useNested then + print('Trying to find keys.') core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) end -- Loading keyfile + print('Loading dumpkeys.bin') local infile = io.open(input, "rb") if infile == nil then return oops('Could not read file ', input) @@ -164,40 +166,51 @@ local function main(args) local blocks = {} -- main loop - for blockNo = 8, numBlocks-1, 1 do - local b = blockNo%4 - if b ~= 3 then - pos = (math.floor( blockNo / 4 ) * 12)+1 - key = akeys:sub(pos, pos + 12 ) - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key} - local err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local blockdata, err = waitCmd() - if err then return oops(err) end - - local base = ('%s%s%d%s'):format(block0, block1, blockNo, hashconstant) - local md5hash = md5.sumhexa(base) - local aestest = core.aes(md5hash, blockdata) - - local _,hex = bin.unpack(("H%d"):format(16),aestest) - - -- local hexascii = string.gsub(hex, '(%x%x)', - -- function(value) - -- return string.char(tonumber(value, 16)) - -- end - -- ) + for blockNo = 0, numBlocks-1, 1 do - if string.find(blockdata, '^0+$') then - blocks[blockNo] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) + if core.ukbhit() then + print("aborted by user") + break + end + + pos = (math.floor( blockNo / 4 ) * 12)+1 + key = akeys:sub(pos, pos + 12 ) + cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key} + local err = core.SendCommand(cmd:getBytes()) + if err then return oops(err) end + local blockdata, err = waitCmd() + if err then return oops(err) end + + local b = blockNo%4 + + if b ~= 3 then + if blockNo < 8 then + -- Block 0-7 not encrypted + blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) else - --blocks[blockNo] = ('%02d :: %s :: %s :: %s '):format(blockNo,key,md5hash,hex) - blocks[blockNo] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) - end - - if core.ukbhit() then - print("aborted by user") - break + local base = ('%s%s%d%s'):format(block0, block1, blockNo, hashconstant) + local md5hash = md5.sumhexa(base) + local aestest = core.aes(md5hash, blockdata) + + local _,hex = bin.unpack(("H%d"):format(16),aestest) + + -- local hexascii = string.gsub(hex, '(%x%x)', + -- function(value) + -- return string.char(tonumber(value, 16)) + -- end + -- ) + + if string.find(blockdata, '^0+$') then + blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) + else + --blocks[blockNo+1] = ('%02d :: %s :: %s :: %s '):format(blockNo,key,md5hash,hex) + blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,hex) + end end + + else + -- Sectorblocks, not encrypted + blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) end end From 9b989c45b942356410416b10e96bc4ca624e4563 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 5 Nov 2014 19:16:54 +0100 Subject: [PATCH 28/78] FIX: minor parseing bug when loading dumpkeys.bin file. ADD: added some useful helperfunctions to utils.lua --- client/lualibs/utils.lua | 58 ++++++++++++++++++++++++++++++++++++++-- client/scripts/tnp3.lua | 4 +-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/client/lualibs/utils.lua b/client/lualibs/utils.lua index 3d27d5b6..6b3777db 100644 --- a/client/lualibs/utils.lua +++ b/client/lualibs/utils.lua @@ -47,11 +47,65 @@ local Utils = --- -- Convert Byte array to string of hex ConvertBytes2String = function(bytes) - s = {} + local s = {} for i = 1, #(bytes) do - s[i] = string.format("%02X",bytes[i]) + s[i] = string.format("%02X",bytes[i]) end return table.concat(s) end, + + ConvertStringToBytes = function(s) + local t={} + for k in s:gmatch"(%x%x)" do + table.insert(t,tonumber(k,16)) + end + return t + end, + + -- function convertStringToBytes(str) + -- local bytes = {} + -- local strLength = string.len(str) + -- for i=1,strLength do + -- table.insert(bytes, string.byte(str, i)) + -- end + + -- return bytes +-- end + +-- function convertBytesToString(bytes) + -- local bytesLength = table.getn(bytes) + -- local str = "" + -- for i=1,bytesLength do + -- str = str .. string.char(bytes[i]) + -- end + + -- return str +-- end + +-- function convertHexStringToBytes(str) + -- local bytes = {} + -- local strLength = string.len(str) + -- for k=2,strLength,2 do + -- local hexString = "0x" .. string.sub(str, (k - 1), k) + -- table.insert(bytes, hex.to_dec(hexString)) + -- end + + -- return bytes +-- end + +-- function convertBytesToHexString(bytes) + -- local str = "" + -- local bytesLength = table.getn(bytes) + -- for i=1,bytesLength do + -- local hexString = string.sub(hex.to_hex(bytes[i]), 3) + -- if string.len(hexString) == 1 then + -- hexString = "0" .. hexString + -- end + -- str = str .. hexString + -- end + + -- return str +-- end + } return Utils \ No newline at end of file diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index 5b3da98f..4e8ca77b 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -145,7 +145,7 @@ local function main(args) return oops('Could not read file ', input) end local akeys = readdumpkeys(infile):sub(0,12*16) - + -- Read block 0 cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA} err = core.SendCommand(cmd:getBytes()) @@ -174,7 +174,7 @@ local function main(args) end pos = (math.floor( blockNo / 4 ) * 12)+1 - key = akeys:sub(pos, pos + 12 ) + key = akeys:sub(pos, pos + 11 ) cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key} local err = core.SendCommand(cmd:getBytes()) if err then return oops(err) end From 22f1c57786097d373e6d4706588b5d9e9a09e8e5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 9 Nov 2014 17:22:04 +0100 Subject: [PATCH 29/78] Updated tnp3.lua added some possibilities to abort the "hf mf nested" command added a rudimentary items identification for tnp3xxx --- armsrc/mifarecmd.c | 28 +++++++---- client/.history | 83 +++++++++++++++++++++++++++++++++ client/cmdhfmf.c | 20 ++++---- client/lualibs/default_toys.lua | 63 +++++++++++++++++++++++++ client/mifarehost.c | 7 --- client/scripts/tnp3.lua | 27 +++++++---- 6 files changed, 195 insertions(+), 33 deletions(-) create mode 100644 client/lualibs/default_toys.lua diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 7e3e9293..0d1fb77a 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -76,7 +76,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); @@ -558,6 +558,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // statistics on nonce distance if (calibrate) { // for first call only. Otherwise reuse previous calibration LED_B_ON(); + WDT_HIT(); davg = dmax = 0; dmin = 2000; @@ -596,10 +597,10 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat continue; }; - nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 - for (i = 101; i < 1200; i++) { + nttmp = prng_successor(nt1, 140); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 + for (i = 141; i < 1200; i++) { nttmp = prng_successor(nttmp, 1); - if (nttmp == nt2) break; + if (nttmp == nt2) {break;} } if (i != 1200) { @@ -615,7 +616,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat } } - if (rtr <= 1) return; + if (rtr <= 1) return; davg = (davg + (rtr - 1)/2) / (rtr - 1); @@ -634,9 +635,18 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // get crypted nonces for target sector for(i=0; i < 2; i++) { // look for exactly two different nonces + WDT_HIT(); + if(BUTTON_PRESS()) { + DbpString("Nested: cancelled"); + crypto1_destroy(pcs); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + return; + } + target_nt[i] = 0; while(target_nt[i] == 0) { // continue until we have an unambiguous nonce - + // prepare next select. No need to power down the card. if(mifare_classic_halt(pcs, cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); @@ -697,15 +707,15 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat if (target_nt[i] == 0 && j == dmax+1 && MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (all invalid)", i+1); } } - + LED_C_OFF(); // ----------------------------- crypto1 destroy crypto1_destroy(pcs); // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); +// memset(uid, 0x44, 4); +// LogTrace(uid, 4, 0, 0, TRUE); byte_t buf[4 + 4 * 4]; memcpy(buf, &cuid, 4); diff --git a/client/.history b/client/.history index e20a63e0..d781126a 100644 --- a/client/.history +++ b/client/.history @@ -9,3 +9,86 @@ lf t55xx rd 2 lf em4x 410xsim 124s lf em4x 410xsim 0F0368568B da pl +scr run sky +script list +scr run mifare_autopwn +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 -n +scr run tnp3 +scr run tnp3 -n +hf mf nested 0 a 4b0b20107ccb d +hf mf nested 1 0 a 4b0b20107ccb d +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 +scr run tnp3 -n +scr run tnp3 +hf mf nested 1 0 a 4b0b20107ccb d +scr run tnp3 diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 1d2de683..8a48c19c 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -36,7 +36,6 @@ start: //flush queue while (ukbhit()) getchar(); - // wait cycle while (true) { printf("."); @@ -848,9 +847,7 @@ int CmdHF14AMfNested(const char *Cmd) if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1; } else { - - - + switch (cmdp) { case '0': SectorsCnt = 05; break; case '1': SectorsCnt = 16; break; @@ -935,20 +932,26 @@ int CmdHF14AMfNested(const char *Cmd) } } - // nested sectors iterations = 0; PrintAndLog("nested..."); bool calibrate = true; for (i = 0; i < NESTED_SECTOR_RETRY; i++) { for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { + + if (ukbhit()) { + printf("\naborted via keyboard!\n"); + free(e_sector); + return 2; + } + for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { if (e_sector[sectorNo].foundKey[trgKeyType]) continue; PrintAndLog("-----------------------------------------------"); if(mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate)) { PrintAndLog("Nested error.\n"); - return 2; - } + free(e_sector); + return 2; } else { calibrate = false; } @@ -1018,10 +1021,9 @@ int CmdHF14AMfNested(const char *Cmd) } fclose(fkeys); } - + free(e_sector); } - return 0; } diff --git a/client/lualibs/default_toys.lua b/client/lualibs/default_toys.lua new file mode 100644 index 00000000..abb56515 --- /dev/null +++ b/client/lualibs/default_toys.lua @@ -0,0 +1,63 @@ +local _names = { + --[[ + --]] + ["0400"]="BASH", + ["1600"]="BOOMER" , + ["1800"]="CAMO", + ["3000"]="CHOPCHOP" , + ["2000"]="CYNDER", + ["6400"]="JET-VAC", + ["6700"]="FLASHWING", + ["7000"]="TREE REX", + ["7100"]="LIGHTCORE SHROOMBOOM", + ["1C00"]="DARK SPYRO", + ["0600"]="DINORANG" , + ["1200"]="DOUBLE TROUBLE" , + ["1500"]="DRILLSERGEANT" , + ["1400"]="DROBOT", + ["0900"]="LIGHTCORE ERUPTOR" , + ["0B00"]="FLAMESLINGER" , + ["1F00"]="GHOST ROASTER", + ["0E00"]="GILL GRUNT" , + ["1D00"]="HEX", + ["0A00"]="IGNITOR", + ["0300"]="LIGHTNINGROD", + ["0700"]="LIGHTCORE PRISM BREAK", + ["1500"]="SLAMBAM", + ["0100"]="SONIC BOOM", + ["1000"]="SPYRO", + ["1A00"]="STEALTH ELF", + ["1B00"]="STUMP SMASH", + ["0800"]="SUNBURN", + ["0500"]="TERRAFIN", + ["1300"]="TRIGGER HAPPY", + ["1100"]="VOODOOD", + ["0200"]="WARNADO", + ["0D00"]="WHAM SHELL", + ["0000"]="WHIRLWIND", + ["1700"]="WRECKING BALL", + ["0C00"]="ZAP", + ["1900"]="ZOOK", + ["0300"]="DRAGON", + ["012D"]="ICE", + ["012E"]="PIRATE", + ["0130"]="PVPUNLOCK", + ["012F"]="UNDEAD", + ["0200"]="ANVIL" , + ["CB00"]="CROSSED SWORDS", + ["CC00"]="HOURGLASS", + ["CA00"]="REGENERATION", + ["C900"]="SECRET STASH", + ["CD00"]="SHIELD", + ["CF00"]="SPARX", + ["CE00"]="SPEED BOOTS", + ["0194"]="LEGENDARY BASH", + ["0430"]="LEGENDARY CHOPCHOP", + ["01A0"]="LEGENDARY SPYRO", + ["01A3"]="LEGENDARY TRIGGER HAPPY", + ["0202"]="PET GILL GRUNT", + ["020E"]="PET STEALTH ELF", + ["01F9"]="PET TERRAFIN", + ["0207"]="PET TRIGGER HAPPY", +} +return _names diff --git a/client/mifarehost.c b/client/mifarehost.c index ed62bcee..cda884d9 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -26,8 +26,6 @@ int compar_int(const void * a, const void * b) { else return -1; } - - // Compare 16 Bits out of cryptostate int Compare16Bits(const void * a, const void * b) { if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0; @@ -35,7 +33,6 @@ int Compare16Bits(const void * a, const void * b) { else return -1; } - typedef struct { union { @@ -70,15 +67,11 @@ void* nested_worker_thread(void *arg) return statelist->head.slhead; } - - - int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKey, bool calibrate) { uint16_t i, len; uint32_t uid; UsbCommand resp; - StateList_t statelists[2]; struct Crypto1State *p1, *p2, *p3, *p4; diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index 4e8ca77b..56d0b486 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -4,6 +4,7 @@ local bin = require('bin') local lib14a = require('read14a') local utils = require('utils') local md5 = require('md5') +local toyNames = require('default_toys') example =[[ 1. script run tnp3 @@ -92,8 +93,8 @@ end local function main(args) print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() + --print( string.rep('--',20) ) + --print() local keyA local cmd @@ -114,27 +115,30 @@ local function main(args) if #(keyA) ~= 12 then return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA)) end + + -- Turn off Debug + local cmdSetDbgOff = "hf mf dbg 0" + core.console( cmdSetDbgOff) result, err = lib14a.read1443a(false) if not result then return oops(err) end - print((' Found tag : %s'):format(result.name)) - core.clearCommandBuffer() if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx return oops('This is not a TNP3xxx tag. aborting.') end + print((' Found tag : %s'):format(result.name)) + -- Show info print(('Using keyA : %s'):format(keyA)) print( string.rep('--',20) ) - + --Trying to find the other keys if useNested then - print('Trying to find keys.') core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) end @@ -165,6 +169,8 @@ local function main(args) local blockNo local blocks = {} + print('Reading card data') + -- main loop for blockNo = 0, numBlocks-1, 1 do @@ -188,8 +194,7 @@ local function main(args) -- Block 0-7 not encrypted blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) else - local base = ('%s%s%d%s'):format(block0, block1, blockNo, hashconstant) - local md5hash = md5.sumhexa(base) + local base = ('%s%s%d%s'):format(block0, block1, blockNo, hashconstant) local md5hash = md5.sumhexa(base) local aestest = core.aes(md5hash, blockdata) local _,hex = bin.unpack(("H%d"):format(16),aestest) @@ -215,6 +220,12 @@ local function main(args) end -- Print results + local uid = block0:sub(1,8) + local itemtype = block1:sub(1,4) + local cardid = block1:sub(9,24) + print( (' UID : %s'):format(uid) ) + print( (' ITEM TYPE : %s - %s'):format(itemtype, toyNames[itemtype]) ) + print( (' CARDID : %s'):format(cardid ) ) print('BLK :: DATA DECRYPTED' ) print( string.rep('--',36) ) for _,s in pairs(blocks) do From cd5767d43da36aa44a78bd4dcfbd7016349da3c6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 9 Nov 2014 19:29:47 +0100 Subject: [PATCH 30/78] FIX: I think the dumping of data is correct now in tnp3.lua. MD5 string vs bytearrays in lua are tricky ADD: utils.lua some functions to convert between ascii, bytes and strings. --- client/lualibs/utils.lua | 33 +++++++++++++++++++++++++++++---- client/scripts/tnp3.lua | 38 +++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/client/lualibs/utils.lua b/client/lualibs/utils.lua index 6b3777db..bff89c5f 100644 --- a/client/lualibs/utils.lua +++ b/client/lualibs/utils.lua @@ -46,21 +46,46 @@ local Utils = end, --- -- Convert Byte array to string of hex - ConvertBytes2String = function(bytes) - local s = {} + ConvertBytes2HexString = function(bytes) + if #bytes == 0 then + return '' + end + local s={} for i = 1, #(bytes) do s[i] = string.format("%02X",bytes[i]) end return table.concat(s) end, - - ConvertStringToBytes = function(s) + -- Convert byte array to string with ascii + ConvertBytesToAsciiString = function(bytes) + if #bytes == 0 then + return '' + end + local s={} + for i = 1, #(bytes) do + s[i] = string.char(bytes[i]) + end + return table.concat(s) + end, + ConvertHexStringToBytes = function(s) local t={} + if s == nil then return t end + if #s == 0 then return t end for k in s:gmatch"(%x%x)" do table.insert(t,tonumber(k,16)) end return t end, + ConvertAsciiStringToBytes = function(s) + local t={} + if s == nil then return t end + if #s == 0 then return t end + + for k in s:gmatch"(.)" do + table.insert(t, string.byte(k)) + end + return t + end, -- function convertStringToBytes(str) -- local bytes = {} diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index 56d0b486..303963ba 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -93,7 +93,7 @@ end local function main(args) print( string.rep('--',20) ) - --print( string.rep('--',20) ) + print( string.rep('--',20) ) --print() local keyA @@ -187,35 +187,30 @@ local function main(args) local blockdata, err = waitCmd() if err then return oops(err) end - local b = blockNo%4 - - if b ~= 3 then + if blockNo%4 ~= 3 then if blockNo < 8 then -- Block 0-7 not encrypted - blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) + blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) else - local base = ('%s%s%d%s'):format(block0, block1, blockNo, hashconstant) local md5hash = md5.sumhexa(base) + local base = ('%s%s%02d%s'):format(block0, block1, blockNo, hashconstant) + local baseArr = utils.ConvertHexStringToBytes(base) + local baseStr = utils.ConvertBytesToAsciiString(baseArr) + local md5hash = md5.sumhexa(baseStr) local aestest = core.aes(md5hash, blockdata) - - local _,hex = bin.unpack(("H%d"):format(16),aestest) - - -- local hexascii = string.gsub(hex, '(%x%x)', - -- function(value) - -- return string.char(tonumber(value, 16)) - -- end - -- ) + --print(aestest, type(aestest)) + local hex = utils.ConvertAsciiStringToBytes(aestest) + hex = utils.ConvertBytes2HexString(hex) + --local _,hex = bin.unpack(("H%d"):format(16),aestest) if string.find(blockdata, '^0+$') then - blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) + blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) else - --blocks[blockNo+1] = ('%02d :: %s :: %s :: %s '):format(blockNo,key,md5hash,hex) - blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,hex) + blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) end end - else -- Sectorblocks, not encrypted - blocks[blockNo+1] = ('%02d :: %s :: %s'):format(blockNo,blockdata,blockdata) + blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) end end @@ -226,10 +221,11 @@ local function main(args) print( (' UID : %s'):format(uid) ) print( (' ITEM TYPE : %s - %s'):format(itemtype, toyNames[itemtype]) ) print( (' CARDID : %s'):format(cardid ) ) - print('BLK :: DATA DECRYPTED' ) + print('BLK :: Decrypted Ascii' ) print( string.rep('--',36) ) for _,s in pairs(blocks) do - print( s ) + local arr = utils.ConvertHexStringToBytes(s:sub(7,#s)) + print( s, utils.ConvertBytesToAsciiString(arr) ) end end From f595de25e95a66b9cf0e31c1925500db0abdae08 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 10 Nov 2014 21:46:21 +0100 Subject: [PATCH 31/78] ADD: html_dumplib.lua, added the functionality to save text-files. ADD: tnp3.lua, now will save the dumped data to BIN and EML FIX: tnp3.lua, added some clearcommando buffer to help the pm3 not to be blocked --- client/lualibs/html_dumplib.lua | 16 +++++++- client/scripts/tnp3.lua | 68 ++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/client/lualibs/html_dumplib.lua b/client/lualibs/html_dumplib.lua index b8c7ccaa..a7890885 100644 --- a/client/lualibs/html_dumplib.lua +++ b/client/lualibs/html_dumplib.lua @@ -47,6 +47,18 @@ local function save_HTML(javascript, filename) end +local function save_TEXT(data,filename) + -- Open the output file + local outfile = io.open(filename, "wb") + if outfile == nil then + return oops(string.format("Could not write to file %s",tostring(filename))) + end + + outfile:write(data) + io.close(outfile) + return filename +end + local function save_BIN(data, filename) -- Open the output file @@ -180,5 +192,7 @@ end 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, + convert_eml_to_bin = convert_eml_to_bin, + SaveAsBinary = save_BIN, + SaveAsText = save_TEXT, } diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index 303963ba..44e3753b 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -4,6 +4,7 @@ local bin = require('bin') local lib14a = require('read14a') local utils = require('utils') local md5 = require('md5') +local dumplib = require('html_dumplib') local toyNames = require('default_toys') example =[[ @@ -11,9 +12,12 @@ example =[[ 2. script run tnp3 -n 3. script run tnp3 -k aabbccddeeff 4. script run tnp3 -k aabbccddeeff -n + 5. script run tnp3 -o myfile + 6. script run tnp3 -n -o myfile + 7. script run tnp3 -k aabbccddeeff -n -o myfile ]] author = "Iceman" -usage = "script run tnp3 -k -n" +usage = "script run tnp3 -k -n -o " desc =[[ This script will try to dump the contents of a Mifare TNP3xxx card. It will need a valid KeyA in order to find the other keys and decode the card. @@ -21,10 +25,9 @@ Arguments: -h : this help -k : Sector 0 Key A. -n : Use the nested cmd to find all keys + -o : filename for the saved dumps ]] --- AES konstant? LEN 0x24 36, --- I dekompilen är det för internal static array = 0x36 54 local hashconstant = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds @@ -94,7 +97,6 @@ local function main(args) print( string.rep('--',20) ) print( string.rep('--',20) ) - --print() local keyA local cmd @@ -102,12 +104,14 @@ local function main(args) local useNested = false local cmdReadBlockString = 'hf mf rdbl %d A %s' local input = "dumpkeys.bin" - + local outputTemplate = os.date("toydump-%Y-%m-%d_%H%M%S"); + -- Arguments for the script - for o, a in getopt.getopt(args, 'hk:n') do + for o, a in getopt.getopt(args, 'hk:no:') do if o == "h" then return help() end if o == "k" then keyA = a end if o == "n" then useNested = true end + if o == "o" then outputTemplate = a end end -- validate input args. @@ -130,12 +134,10 @@ local function main(args) if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx return oops('This is not a TNP3xxx tag. aborting.') end - + + -- Show tag info print((' Found tag : %s'):format(result.name)) - - -- Show info print(('Using keyA : %s'):format(keyA)) - print( string.rep('--',20) ) --Trying to find the other keys if useNested then @@ -170,7 +172,8 @@ local function main(args) local blocks = {} print('Reading card data') - + core.clearCommandBuffer() + -- main loop for blockNo = 0, numBlocks-1, 1 do @@ -197,7 +200,7 @@ local function main(args) local baseStr = utils.ConvertBytesToAsciiString(baseArr) local md5hash = md5.sumhexa(baseStr) local aestest = core.aes(md5hash, blockdata) - --print(aestest, type(aestest)) + local hex = utils.ConvertAsciiStringToBytes(aestest) hex = utils.ConvertBytes2HexString(hex) --local _,hex = bin.unpack(("H%d"):format(16),aestest) @@ -210,23 +213,44 @@ local function main(args) end else -- Sectorblocks, not encrypted - blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) + blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) end end + core.clearCommandBuffer() + -- Print results + local bindata = {} + local emldata = '' + + for _,s in pairs(blocks) do + local slice = s:sub(7,#s) + local str = utils.ConvertBytesToAsciiString( + utils.ConvertHexStringToBytes(slice) + ) + emldata = emldata..slice..'\n' + for c in (str):gmatch('.') do + bindata[#bindata+1] = c + end + end + + -- Write dump to files + local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'.bin') + print(("Wrote a BIN dump to the file %s"):format(foo)) + local bar = dumplib.SaveAsText(emldata, outputTemplate..'.eml') + print(("Wrote a EML dump to the file %s"):format(bar)) + local uid = block0:sub(1,8) local itemtype = block1:sub(1,4) local cardid = block1:sub(9,24) - print( (' UID : %s'):format(uid) ) - print( (' ITEM TYPE : %s - %s'):format(itemtype, toyNames[itemtype]) ) - print( (' CARDID : %s'):format(cardid ) ) - print('BLK :: Decrypted Ascii' ) - print( string.rep('--',36) ) - for _,s in pairs(blocks) do - local arr = utils.ConvertHexStringToBytes(s:sub(7,#s)) - print( s, utils.ConvertBytesToAsciiString(arr) ) - end + + -- Show info + print( string.rep('--',20) ) + print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) ) + print( (' UID : 0x%s'):format(uid) ) + print( (' CARDID : 0x%s'):format(cardid ) ) + print( string.rep('--',20) ) + end main(args) \ No newline at end of file From 47cbb2d41851e680c84b3a7dd0465f7f7960a9ec Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 12 Nov 2014 23:18:46 +0100 Subject: [PATCH 32/78] ADD: tnp3.lua can now validate the checkums in the dump ADD: added CRC16 CCITT functionality to LUA FIX: tnp3.lua is now correctly decryping data while dumping --- client/lualibs/utils.lua | 9 +++++ client/scripting.c | 12 +++++++ client/scripts/tnp3.lua | 78 ++++++++++++++++++++++++++++++++++------ common/crc16.c | 23 ++++++++++++ common/crc16.h | 5 +-- 5 files changed, 114 insertions(+), 13 deletions(-) diff --git a/client/lualibs/utils.lua b/client/lualibs/utils.lua index bff89c5f..15b96ee5 100644 --- a/client/lualibs/utils.lua +++ b/client/lualibs/utils.lua @@ -86,6 +86,15 @@ local Utils = end return t end, + ConvertHexToAscii = function(s) + local t={} + if s == nil then return t end + if #s == 0 then return t end + for k in s:gmatch"(%x%x)" do + table.insert(t, string.char(tonumber(k,16))) + end + return table.concat(t) + end, -- function convertStringToBytes(str) -- local bytes = {} diff --git a/client/scripting.c b/client/scripting.c index fd065a04..f0c56baf 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -19,6 +19,7 @@ #include "nonce2key/nonce2key.h" #include "../common/iso15693tools.h" #include +#include "../common/crc16.h" /** * The following params expected: * UsbCommand c @@ -263,6 +264,16 @@ static int l_aes(lua_State *L) return 1;// return 1 to signal one return value } +static int l_crc16(lua_State *L) +{ + size_t size; + const char *p_str = luaL_checklstring(L, 1, &size); + + unsigned short retval = crc16_ccitt( p_str, size); + lua_pushinteger(L, (int) retval); + return 1; +} + /** * @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be * able to do "require('foobar')" if foobar.lua is within lualibs folder. @@ -301,6 +312,7 @@ int set_pm3_libraries(lua_State *L) {"console", l_CmdConsole}, {"iso15693_crc", l_iso15693_crc}, {"aes", l_aes}, + {"crc16", l_crc16}, {NULL, NULL} }; diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index 44e3753b..006e5a5d 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -93,6 +93,16 @@ local function waitCmd() return nil, "No response from device" end +local function computeCrc16(s) + local hash = core.crc16(utils.ConvertHexToAscii(s)) + return hash +end + +local function reverseCrcBytes(crc) + crc2 = crc:sub(3,4)..crc:sub(1,2) + return tonumber(crc2,16) +end + local function main(args) print( string.rep('--',20) ) @@ -104,7 +114,7 @@ local function main(args) local useNested = false local cmdReadBlockString = 'hf mf rdbl %d A %s' local input = "dumpkeys.bin" - local outputTemplate = os.date("toydump-%Y-%m-%d_%H%M%S"); + local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S"); -- Arguments for the script for o, a in getopt.getopt(args, 'hk:no:') do @@ -175,6 +185,7 @@ local function main(args) core.clearCommandBuffer() -- main loop + io.write('Decrypting blocks > ') for blockNo = 0, numBlocks-1, 1 do if core.ukbhit() then @@ -195,9 +206,8 @@ local function main(args) -- Block 0-7 not encrypted blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) else - local base = ('%s%s%02d%s'):format(block0, block1, blockNo, hashconstant) - local baseArr = utils.ConvertHexStringToBytes(base) - local baseStr = utils.ConvertBytesToAsciiString(baseArr) + local base = ('%s%s%02x%s'):format(block0, block1, blockNo, hashconstant) + local baseStr = utils.ConvertHexToAscii(base) local md5hash = md5.sumhexa(baseStr) local aestest = core.aes(md5hash, blockdata) @@ -205,10 +215,12 @@ local function main(args) hex = utils.ConvertBytes2HexString(hex) --local _,hex = bin.unpack(("H%d"):format(16),aestest) + -- blocks with zero not encrypted. if string.find(blockdata, '^0+$') then blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) else - blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) + blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) + io.write( blockNo..',') end end else @@ -216,6 +228,7 @@ local function main(args) blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) end end + io.write('\n') core.clearCommandBuffer() @@ -224,7 +237,7 @@ local function main(args) local emldata = '' for _,s in pairs(blocks) do - local slice = s:sub(7,#s) + local slice = s:sub(8,#s) local str = utils.ConvertBytesToAsciiString( utils.ConvertHexStringToBytes(slice) ) @@ -235,10 +248,12 @@ local function main(args) end -- Write dump to files - local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'.bin') - print(("Wrote a BIN dump to the file %s"):format(foo)) - local bar = dumplib.SaveAsText(emldata, outputTemplate..'.eml') - print(("Wrote a EML dump to the file %s"):format(bar)) + if not DEBUG then + local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'.bin') + print(("Wrote a BIN dump to the file %s"):format(foo)) + local bar = dumplib.SaveAsText(emldata, outputTemplate..'.eml') + print(("Wrote a EML dump to the file %s"):format(bar)) + end local uid = block0:sub(1,8) local itemtype = block1:sub(1,4) @@ -251,6 +266,47 @@ local function main(args) print( (' CARDID : 0x%s'):format(cardid ) ) print( string.rep('--',20) ) -end + print('Validating checksums') + -- Checksum Typ 0 + local test1 = ('%s%s'):format(block0, block1:sub(1,28)) + local crc = block1:sub(29,32) + local revcrc = reverseCrcBytes(crc) + io.write( ('BLOCK 0-1 : %04x = %04x \n'):format(revcrc,computeCrc16(test1))) + + -- Checksum Typ 1 BLOCK 9 + local block9 = blocks[9]:sub(8,35) + test1 = ('%s0500'):format(block9) + crc = blocks[9]:sub(36,39) + revcrc = reverseCrcBytes(crc) + io.write( ('BLOCK 8 : %04x = %04x \n'):format(revcrc,computeCrc16(test1))) + + -- Checksum Typ 1 BLOCK 37 + local block37 = blocks[37]:sub(8,35) + test1 = ('%s0500'):format(block37) + crc = blocks[37]:sub(36,39) + revcrc = reverseCrcBytes(crc) + io.write( ('BLOCK 36 : %04x = %04x \n'):format(revcrc,computeCrc16(test1))) + + -- Checksum Typ 2 + -- 10,11,13 + test1 = blocks[10]:sub(8,39).. + blocks[11]:sub(8,39).. + blocks[13]:sub(8,39) + + crc = blocks[9]:sub(32,35) + revcrc = reverseCrcBytes(crc) + io.write( ('BLOCK 10-11-13 :%04x = %04x \n'):format(revcrc,computeCrc16(test1))) + -- Checksum Typ 3 + -- 15,17,18,19 + crc = blocks[9]:sub(28,31) + revcrc = reverseCrcBytes(crc) + test1 = blocks[14]:sub(8,39).. + blocks[15]:sub(8,39).. + blocks[17]:sub(8,39) + + local tohash = test1..string.rep('00',0xe0) + local hashed = computeCrc16(tohash) + io.write( ('BLOCK 14-15-17 %04x = %04x \n'):format(revcrc,hashed)) +end main(args) \ No newline at end of file diff --git a/common/crc16.c b/common/crc16.c index d181bb2a..973cd103 100644 --- a/common/crc16.c +++ b/common/crc16.c @@ -8,6 +8,7 @@ #include "crc16.h" + unsigned short update_crc16( unsigned short crc, unsigned char c ) { unsigned short i, v, tcrc = 0; @@ -20,3 +21,25 @@ unsigned short update_crc16( unsigned short crc, unsigned char c ) 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; +} + +uint16_t crc16_ccitt(uint8_t const *message, int length) { + return crc16(message, length, 0xffff, 0x1021); +} diff --git a/common/crc16.h b/common/crc16.h index 055a60bc..d16d83b5 100644 --- a/common/crc16.h +++ b/common/crc16.h @@ -5,10 +5,11 @@ //----------------------------------------------------------------------------- // CRC16 //----------------------------------------------------------------------------- +#include #ifndef __CRC16_H #define __CRC16_H - unsigned short update_crc16(unsigned short crc, unsigned char c); - +uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial); +uint16_t crc16_ccitt(uint8_t const *message, int length); #endif From f91f0ebb35c1c131e5e255457212a0784c81dcd6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 13 Nov 2014 20:14:14 +0100 Subject: [PATCH 33/78] CHG - some lua functions in utils.lua --- client/lualibs/commands.lua | 9 ++-- client/lualibs/utils.lua | 87 ++++++++++++++++++++++++++++++++++--- client/scripts/tnp3.lua | 69 +++++++---------------------- 3 files changed, 101 insertions(+), 64 deletions(-) diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index bf2a8a1f..f88eeae2 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -117,10 +117,10 @@ local _commands = { local _reverse_lookup,k,v = {} -for k, v in pairs(_commands) do - _reverse_lookup[v] = k -end -_commands.tostring = function(command) + for k, v in pairs(_commands) do + _reverse_lookup[v] = k + end + _commands.tostring = function(command) if(type(command) == 'number') then return ("%s (%d)"):format(_reverse_lookup[command]or "ERROR UNDEFINED!", command) end @@ -182,7 +182,6 @@ function Command:getBytes() local cmd = self.cmd local arg1, arg2, arg3 = self.arg1, self.arg2, self.arg3 - return bin.pack("LLLLH",cmd, arg1, arg2, arg3,data); end return _commands \ No newline at end of file diff --git a/client/lualibs/utils.lua b/client/lualibs/utils.lua index 15b96ee5..9b36dfc8 100644 --- a/client/lualibs/utils.lua +++ b/client/lualibs/utils.lua @@ -33,9 +33,86 @@ local Utils = return answer end, + + ------------ FILE READING + ReadDumpFile = function (filename) + + if filename == nil then + return nil, 'Filename is empty' + end + if #filename == 0 then + return nil, 'Filename length is zero' + end + + infile = io.open(filename, "rb") + if infile == nil then + return nil, string.format("Could not read file %s",filename) + end + local t = infile:read("*all") + len = string.len(t) + local _,hex = bin.unpack(("H%d"):format(len),t) + io.close(infile) + return hex + end, + + ------------ string split function + Split = function( inSplitPattern, outResults ) + if not outResults then + outResults = {} + end + local start = 1 + local splitStart, splitEnd = string.find( self, inSplitPattern, start ) + while splitStart do + table.insert( outResults, string.sub( self, start, splitStart-1 ) ) + start = splitEnd + 1 + splitStart, splitEnd = string.find( self, inSplitPattern, start ) + end + table.insert( outResults, string.sub( self, start ) ) + return outResults + end, + + ------------ CRC-16 ccitt checksums + + -- Takes a hex string and calculates a crc16 + Crc16 = function(s) + if s == nil then return nil end + if #s == 0 then return nil end + if type(s) == 'string' then + local utils = require('utils') + local asc = utils.ConvertHexToAscii(s) + local hash = core.crc16(asc) + return hash + end + return nil + end, + + -- input parameter is a string + -- Swaps the endianess and returns a number, + -- IE: 'cd7a' -> '7acd' -> 0x7acd + SwapEndianness = function(s, len) + if s == nil then return nil end + if #s == 0 then return '' end + if type(s) ~= 'string' then return nil end + + local retval = 0 + if len == 16 then + local t = s:sub(3,4)..s:sub(1,2) + retval = tonumber(t,16) + elseif len == 24 then + local t = s:sub(5,6)..s:sub(3,4)..s:sub(1,2) + retval = tonumber(t,16) + elseif len == 32 then + local t = s:sub(7,8)..s:sub(5,6)..s:sub(3,4)..s:sub(1,2) + retval = tonumber(t,16) + end + return retval + end, + + ------------ CONVERSIONS + -- -- Converts DECIMAL to HEX - ConvertDec2Hex = function(IN) + ConvertDecToHex = function(IN) local B,K,OUT,I,D=16,"0123456789ABCDEF","",0 while IN>0 do I=I+1 @@ -46,7 +123,7 @@ local Utils = end, --- -- Convert Byte array to string of hex - ConvertBytes2HexString = function(bytes) + ConvertBytesToHex = function(bytes) if #bytes == 0 then return '' end @@ -57,7 +134,7 @@ local Utils = return table.concat(s) end, -- Convert byte array to string with ascii - ConvertBytesToAsciiString = function(bytes) + ConvertBytesToAscii = function(bytes) if #bytes == 0 then return '' end @@ -67,7 +144,7 @@ local Utils = end return table.concat(s) end, - ConvertHexStringToBytes = function(s) + ConvertHexToBytes = function(s) local t={} if s == nil then return t end if #s == 0 then return t end @@ -76,7 +153,7 @@ local Utils = end return t end, - ConvertAsciiStringToBytes = function(s) + ConvertAsciiToBytes = function(s) local t={} if s == nil then return t end if #s == 0 then return t end diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3.lua index 006e5a5d..77de766f 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3.lua @@ -28,10 +28,10 @@ Arguments: -o : filename for the saved dumps ]] -local hashconstant = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' +local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds -local DEBUG = true -- the debug flag +local DEBUG = false -- the debug flag local numBlocks = 64 local numSectors = 16 --- @@ -154,14 +154,17 @@ local function main(args) core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) end + core.clearCommandBuffer() + -- Loading keyfile print('Loading dumpkeys.bin') - local infile = io.open(input, "rb") - if infile == nil then - return oops('Could not read file ', input) + local hex, err = utils.ReadDumpFile(input) + if not hex then + return oops(err) end - local akeys = readdumpkeys(infile):sub(0,12*16) - + + local akeys = hex:sub(0,12*16) + -- Read block 0 cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA} err = core.SendCommand(cmd:getBytes()) @@ -206,13 +209,13 @@ local function main(args) -- Block 0-7 not encrypted blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) else - local base = ('%s%s%02x%s'):format(block0, block1, blockNo, hashconstant) + local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT) local baseStr = utils.ConvertHexToAscii(base) local md5hash = md5.sumhexa(baseStr) local aestest = core.aes(md5hash, blockdata) - local hex = utils.ConvertAsciiStringToBytes(aestest) - hex = utils.ConvertBytes2HexString(hex) + local hex = utils.ConvertAsciiToBytes(aestest) + hex = utils.ConvertBytesToHex(hex) --local _,hex = bin.unpack(("H%d"):format(16),aestest) -- blocks with zero not encrypted. @@ -238,8 +241,8 @@ local function main(args) for _,s in pairs(blocks) do local slice = s:sub(8,#s) - local str = utils.ConvertBytesToAsciiString( - utils.ConvertHexStringToBytes(slice) + local str = utils.ConvertBytesToAscii( + utils.ConvertHexToBytes(slice) ) emldata = emldata..slice..'\n' for c in (str):gmatch('.') do @@ -266,47 +269,5 @@ local function main(args) print( (' CARDID : 0x%s'):format(cardid ) ) print( string.rep('--',20) ) - print('Validating checksums') - -- Checksum Typ 0 - local test1 = ('%s%s'):format(block0, block1:sub(1,28)) - local crc = block1:sub(29,32) - local revcrc = reverseCrcBytes(crc) - - io.write( ('BLOCK 0-1 : %04x = %04x \n'):format(revcrc,computeCrc16(test1))) - - -- Checksum Typ 1 BLOCK 9 - local block9 = blocks[9]:sub(8,35) - test1 = ('%s0500'):format(block9) - crc = blocks[9]:sub(36,39) - revcrc = reverseCrcBytes(crc) - io.write( ('BLOCK 8 : %04x = %04x \n'):format(revcrc,computeCrc16(test1))) - - -- Checksum Typ 1 BLOCK 37 - local block37 = blocks[37]:sub(8,35) - test1 = ('%s0500'):format(block37) - crc = blocks[37]:sub(36,39) - revcrc = reverseCrcBytes(crc) - io.write( ('BLOCK 36 : %04x = %04x \n'):format(revcrc,computeCrc16(test1))) - - -- Checksum Typ 2 - -- 10,11,13 - test1 = blocks[10]:sub(8,39).. - blocks[11]:sub(8,39).. - blocks[13]:sub(8,39) - - crc = blocks[9]:sub(32,35) - revcrc = reverseCrcBytes(crc) - io.write( ('BLOCK 10-11-13 :%04x = %04x \n'):format(revcrc,computeCrc16(test1))) - -- Checksum Typ 3 - -- 15,17,18,19 - crc = blocks[9]:sub(28,31) - revcrc = reverseCrcBytes(crc) - test1 = blocks[14]:sub(8,39).. - blocks[15]:sub(8,39).. - blocks[17]:sub(8,39) - - local tohash = test1..string.rep('00',0xe0) - local hashed = computeCrc16(tohash) - io.write( ('BLOCK 14-15-17 %04x = %04x \n'):format(revcrc,hashed)) end main(args) \ No newline at end of file From 5c065fa089f7864548bb91ef4779cf6ec054319f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 13 Nov 2014 22:02:36 +0100 Subject: [PATCH 34/78] FIX: Corrected the bug mention http://www.proxmark.org/forum/viewtopic.php?id=1612 filepath too short in "hf mf eload / esave / cload / csave" commands. Length was 14, is now 250. Should be enough for awhile. --- client/cmdhfmf.c | 16 ++++++++-------- client/mifarehost.c | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 8a48c19c..4b620275 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1419,7 +1419,7 @@ int CmdHF14AMfESet(const char *Cmd) int CmdHF14AMfELoad(const char *Cmd) { FILE * f; - char filename[20]; + char filename[255]; char *fnameptr = filename; char buf[64]; uint8_t buf8[64]; @@ -1436,7 +1436,7 @@ int CmdHF14AMfELoad(const char *Cmd) } len = strlen(Cmd); - if (len > 14) len = 14; + if (len > 250) len = 250; memcpy(filename, Cmd, len); fnameptr += len; @@ -1494,7 +1494,7 @@ int CmdHF14AMfELoad(const char *Cmd) int CmdHF14AMfESave(const char *Cmd) { FILE * f; - char filename[20]; + char filename[255]; char * fnameptr = filename; uint8_t buf[64]; int i, j, len; @@ -1511,7 +1511,7 @@ int CmdHF14AMfESave(const char *Cmd) } len = strlen(Cmd); - if (len > 14) len = 14; + if (len > 250) len = 250; if (len < 1) { // get filename @@ -1687,7 +1687,7 @@ int CmdHF14AMfCSetBlk(const char *Cmd) int CmdHF14AMfCLoad(const char *Cmd) { FILE * f; - char filename[20]; + char filename[255]; char * fnameptr = filename; char buf[64]; uint8_t buf8[64]; @@ -1728,7 +1728,7 @@ int CmdHF14AMfCLoad(const char *Cmd) return 0; } else { len = strlen(Cmd); - if (len > 14) len = 14; + if (len > 250) len = 250; memcpy(filename, Cmd, len); fnameptr += len; @@ -1851,7 +1851,7 @@ int CmdHF14AMfCGetSc(const char *Cmd) { int CmdHF14AMfCSave(const char *Cmd) { FILE * f; - char filename[20]; + char filename[255]; char * fnameptr = filename; uint8_t fillFromEmulator = 0; uint8_t buf[64]; @@ -1893,7 +1893,7 @@ int CmdHF14AMfCSave(const char *Cmd) { return 0; } else { len = strlen(Cmd); - if (len > 14) len = 14; + if (len > 250) len = 250; if (len < 1) { // get filename diff --git a/client/mifarehost.c b/client/mifarehost.c index cda884d9..358799cb 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -216,7 +216,7 @@ int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) { UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}}; SendCommand(&c); - UsbCommand resp; + UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) return 1; memcpy(data, resp.d.asBytes, blocksCount * 16); return 0; From a0bf7ba787ea7b309d034e1d5412a7d63b1c2fa3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 13 Nov 2014 22:13:46 +0100 Subject: [PATCH 35/78] FIX: The hf mf ekeyprn defaults to print all 40 sectorblocks of keys. (ie 4K card). Now its optional 1K / 4K and defaults to 1K. --- client/cmdhfmf.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 4b620275..10c56cdc 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1592,13 +1592,32 @@ int CmdHF14AMfECFill(const char *Cmd) int CmdHF14AMfEKeyPrn(const char *Cmd) { int i; + uint8_t numSectors; uint8_t data[16]; uint64_t keyA, keyB; + if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { + PrintAndLog("It prints the keys loaded in the emulator memory"); + PrintAndLog("Usage: hf mf ekeyprn [card memory]"); + PrintAndLog(" [card memory]: 1 = 1K (default), 4 = 4K"); + PrintAndLog(""); + PrintAndLog(" sample: hf mf ekeyprn 1"); + return 0; + } + + char cmdp = param_getchar(Cmd, 0); + + switch (cmdp) { + case '1' : + case '\0': numSectors = 16; break; + case '4' : numSectors = 40; break; + default: numSectors = 16; + } + PrintAndLog("|---|----------------|----------------|"); PrintAndLog("|sec|key A |key B |"); PrintAndLog("|---|----------------|----------------|"); - for (i = 0; i < 40; i++) { + for (i = 0; i < numSectors; i++) { if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); break; From 85578fcd4e4c1ef9df478722d4fedc42f5c02d31 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 13 Nov 2014 22:21:39 +0100 Subject: [PATCH 36/78] FIX: since the "hf mf ecfill" command supports 0,1,2,4 in card sizes, I consequently changed "hf mf ekeyprn" --- client/cmdhfmf.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 10c56cdc..1519c201 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1596,10 +1596,10 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) uint8_t data[16]; uint64_t keyA, keyB; - if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { + if (param_getchar(Cmd, 0) == 'h') { PrintAndLog("It prints the keys loaded in the emulator memory"); PrintAndLog("Usage: hf mf ekeyprn [card memory]"); - PrintAndLog(" [card memory]: 1 = 1K (default), 4 = 4K"); + PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLog(""); PrintAndLog(" sample: hf mf ekeyprn 1"); return 0; @@ -1607,12 +1607,14 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) char cmdp = param_getchar(Cmd, 0); - switch (cmdp) { + switch (ctmp) { + case '0' : numSectors = 5; break; case '1' : case '\0': numSectors = 16; break; + case '2' : numSectors = 32; break; case '4' : numSectors = 40; break; default: numSectors = 16; - } + } PrintAndLog("|---|----------------|----------------|"); PrintAndLog("|sec|key A |key B |"); From b22f7a6bc68319533f9c83c24045d4bd79994f1f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 13 Nov 2014 22:23:30 +0100 Subject: [PATCH 37/78] FIX: Minor correction of variablename. don't even ask. --- client/cmdhfmf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 1519c201..901ccd49 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1607,7 +1607,7 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) char cmdp = param_getchar(Cmd, 0); - switch (ctmp) { + switch (cmdp) { case '0' : numSectors = 5; break; case '1' : case '\0': numSectors = 16; break; From bd5d0f07e9330f18088f626bc1d18857aeaeaa8e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 14 Nov 2014 13:24:45 +0100 Subject: [PATCH 38/78] REN: renamed tnp3.lua to tnp3dump.lua since that name is more explainatory ADD: added tnp3sim.lua a script which loads a dump and sends it to the pm3 device memory. --- client/cmdhfmf.c | 1 + client/scripts/test.lua | 10 - client/scripts/{tnp3.lua => tnp3dump.lua} | 17 +- client/scripts/tnp3sim.lua | 383 ++++++++++++++++++++++ 4 files changed, 392 insertions(+), 19 deletions(-) delete mode 100644 client/scripts/test.lua rename client/scripts/{tnp3.lua => tnp3dump.lua} (95%) create mode 100644 client/scripts/tnp3sim.lua diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 901ccd49..35bf2a00 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1623,6 +1623,7 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); break; + break; } keyA = bytes_to_num(data, 6); keyB = bytes_to_num(data + 10, 6); diff --git a/client/scripts/test.lua b/client/scripts/test.lua deleted file mode 100644 index 76adc985..00000000 --- a/client/scripts/test.lua +++ /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 diff --git a/client/scripts/tnp3.lua b/client/scripts/tnp3dump.lua similarity index 95% rename from client/scripts/tnp3.lua rename to client/scripts/tnp3dump.lua index 77de766f..520161b9 100644 --- a/client/scripts/tnp3.lua +++ b/client/scripts/tnp3dump.lua @@ -8,16 +8,16 @@ local dumplib = require('html_dumplib') local toyNames = require('default_toys') example =[[ - 1. script run tnp3 - 2. script run tnp3 -n - 3. script run tnp3 -k aabbccddeeff - 4. script run tnp3 -k aabbccddeeff -n - 5. script run tnp3 -o myfile - 6. script run tnp3 -n -o myfile - 7. script run tnp3 -k aabbccddeeff -n -o myfile + 1. script run tnp3dump + 2. script run tnp3dump -n + 3. script run tnp3dump -k aabbccddeeff + 4. script run tnp3dump -k aabbccddeeff -n + 5. script run tnp3dump -o myfile + 6. script run tnp3dump -n -o myfile + 7. script run tnp3dump -k aabbccddeeff -n -o myfile ]] author = "Iceman" -usage = "script run tnp3 -k -n -o " +usage = "script run tnp3dump -k -n -o " desc =[[ This script will try to dump the contents of a Mifare TNP3xxx card. It will need a valid KeyA in order to find the other keys and decode the card. @@ -216,7 +216,6 @@ local function main(args) local hex = utils.ConvertAsciiToBytes(aestest) hex = utils.ConvertBytesToHex(hex) - --local _,hex = bin.unpack(("H%d"):format(16),aestest) -- blocks with zero not encrypted. if string.find(blockdata, '^0+$') then diff --git a/client/scripts/tnp3sim.lua b/client/scripts/tnp3sim.lua new file mode 100644 index 00000000..ce772022 --- /dev/null +++ b/client/scripts/tnp3sim.lua @@ -0,0 +1,383 @@ +local cmds = require('commands') +local getopt = require('getopt') +local bin = require('bin') +local lib14a = require('read14a') +local utils = require('utils') +local md5 = require('md5') +local toyNames = require('default_toys') + +example =[[ + 1. script run tnp3sim + 2. script run tnp3sim -m + 3. script run tnp3sim -m -i myfile +]] +author = "Iceman" +usage = "script run tnp3sim -h -m -i " +desc =[[ +This script will try to dump the contents of a Mifare TNP3xxx card. +It will need a valid KeyA in order to find the other keys and decode the card. +Arguments: + -h : this help + -m : Maxed out item + -i : filename for the datadump to read (bin) +]] + +local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' + +local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds +local DEBUG = true -- the debug flag +--- +-- A debug printout-function +function dbg(args) + if not DEBUG then + return + end + + if type(args) == "table" then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print("###", args) + end +end +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) +end +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end +-- +-- Exit message +function ExitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + +local function writedumpfile(infile) + t = infile:read("*all") + len = string.len(t) + local len,hex = bin.unpack(("H%d"):format(len),t) + return hex +end +-- blocks with data +-- there are two dataareas, in block 8 or block 36, ( 1==8 , +-- checksum type = 0, 1, 2, 3 +local function GetCheckSum(blocks, dataarea, chksumtype) + + local crc + local area = 36 + if dataarea == 1 then + area = 8 + end + + if chksumtype == 0 then + crc = blocks[1]:sub(29,32) + elseif chksumtype == 1 then + crc = blocks[area]:sub(29,32) + elseif chksumtype == 2 then + crc = blocks[area]:sub(25,28) + elseif chksumtype == 3 then + crc = blocks[area]:sub(21,24) + end + return utils.SwapEndianness(crc,16) +end + +local function SetCheckSum(blocks, chksumtype) + + if blocks == nil then return nil, 'Argument \"blocks\" nil' end + local newcrc + local area1 = 8 + local area2 = 36 + + if chksumtype == 0 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0)) + blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + elseif chksumtype == 1 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1)) + blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1)) + blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) + elseif chksumtype == 2 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2)) + blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2)) + blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32) + elseif chksumtype == 3 then + newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3)) + blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32) + newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3)) + blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32) + end +end + +function CalcCheckSum(blocks, dataarea, chksumtype) + local area = 36 + if dataarea == 1 then + area = 8 + end + + if chksumtype == 0 then + data = blocks[0]..blocks[1]:sub(1,28) + elseif chksumtype == 1 then + data = blocks[area]:sub(1,28)..'0500' + elseif chksumtype == 2 then + data = blocks[area+1]..blocks[area+2]..blocks[area+4] + elseif chksumtype == 3 then + data = blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0) + end + return utils.Crc16(data) +end + +local function ValidateCheckSums(blocks) + + local isOk, crc, calc + -- Checksum Type 0 + crc = GetCheckSum(blocks,1,0) + calc = CalcCheckSum(blocks, 1, 0) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 0 : %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 1 (DATAAREAHEADER 1) + crc = GetCheckSum(blocks,1,1) + calc = CalcCheckSum(blocks,1,1) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 1 (DATAAREAHEADER 2) + crc = GetCheckSum(blocks,2,1) + calc = CalcCheckSum(blocks,2,1) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 2 (DATAAREA 1) + crc = GetCheckSum(blocks,1,2) + calc = CalcCheckSum(blocks,1,2) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 2 (DATAAREA 2) + crc = GetCheckSum(blocks,2,2) + calc = CalcCheckSum(blocks,2,2) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 3 (DATAAREA 1) + crc = GetCheckSum(blocks,1,3) + calc = CalcCheckSum(blocks,1,3) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) + + -- Checksum Type 3 (DATAAREA 2) + crc = GetCheckSum(blocks,2,3) + calc = CalcCheckSum(blocks,2,3) + if crc == calc then isOk='Ok' else isOk = 'Error' end + io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) +end + +-- function EncryptData() + -- local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' + -- if blockNo%4 ~= 3 then + -- if blockNo < 8 then + -- -- Block 0-7 not encrypted + -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) + -- else + -- local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT) + -- local baseStr = utils.ConvertHexToAscii(base) + -- local md5hash = md5.sumhexa(baseStr) + -- local aestest = core.aes(md5hash, blockdata) + + -- local hex = utils.ConvertAsciiToBytes(aestest) + -- hex = utils.ConvertBytesToHex(hex) + -- --local _,hex = bin.unpack(("H%d"):format(16),aestest) + + -- -- blocks with zero not encrypted. + -- if string.find(blockdata, '^0+$') then + -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) + -- else + -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) + -- io.write( blockNo..',') + -- end + -- end + -- else + -- -- Sectorblocks, not encrypted + -- blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) + -- end + +-- end + +local function LoadEmulator(blocks) + local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' + local cmd + local blockdata + for _,b in pairs(blocks) do + + blockdata = b + + if _%4 ~= 3 then + if (_ >= 8 and _<=21) or (_ >= 36 and _<=49) then + local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , HASHCONSTANT) + local baseStr = utils.ConvertHexToAscii(base) + local key = md5.sumhexa(baseStr) + local enc = core.aes(key, blockdata) + local hex = utils.ConvertAsciiToBytes(enc) + hex = utils.ConvertBytesToHex(hex) + + blockdata = hex + io.write( _..',') + end + end + + cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 0, data = blockdata} + local err = core.SendCommand(cmd:getBytes()) + if err then + return err + end + end + io.write('\n') +end + +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + + local result, err, hex + local maxed = false + local inputTemplate = "dumpdata.bin" + local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M"); + + -- Arguments for the script + for o, a in getopt.getopt(args, 'hmi:o:') do + if o == "h" then return help() end + if o == "m" then maxed = true end + if o == "o" then outputTemplate = a end + if o == "i" then inputTemplate = a end + end + + -- Turn off Debug + local cmdSetDbgOff = "hf mf dbg 0" + core.console( cmdSetDbgOff) + + -- Look for tag present on reader, + result, err = lib14a.read1443a(false) + if not result then return oops(err) end + + core.clearCommandBuffer() + + if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx + return oops('This is not a TNP3xxx tag. aborting.') + end + + -- Show tag info + print((' Found tag : %s'):format(result.name)) + + -- Load dump.bin file + print( (' Load data from %s'):format(inputTemplate)) + hex, err = utils.ReadDumpFile(inputTemplate) + if not hex then return oops(err) end + + local blocks = {} + local blockindex = 0 + for i = 1, #hex, 32 do + blocks[blockindex] = hex:sub(i,i+31) + blockindex = blockindex + 1 + end + + if DEBUG then + print('Validating checksums in the loaded datadump') + ValidateCheckSums(blocks) + end + + -- + print( string.rep('--',20) ) + print(' Gathering info') + local uid = blocks[0]:sub(1,8) + local itemtype = blocks[1]:sub(1,4) + local cardid = blocks[1]:sub(9,24) + + -- Show info + print( string.rep('--',20) ) + print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) ) + print( (' UID : 0x%s'):format(uid) ) + print( (' CARDID : 0x%s'):format(cardid ) ) + print( string.rep('--',20) ) + + -- lets do something. + -- + local experience = blocks[8]:sub(1,6) + print(('Experience : %d'):format(utils.SwapEndianness(experience,24))) + local money = blocks[8]:sub(7,10) + print(('Money : %d'):format(utils.SwapEndianness(money,16))) + local fairy = blocks[9]:sub(1,8) + --FD0F = Left, FF0F = Right + local path = 'not choosen' + if fairy:sub(2,2) == 'D' then + path = 'Left' + elseif fairy:sub(2,2) == 'F' then + path = 'Right' + end + print(('Fairy : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path)) + + local hat = blocks[9]:sub(8,11) + print(('Hat : %d'):format(utils.SwapEndianness(hat,16))) + + --0x0D 0x29 0x0A 0x02 16-bit hero points value. Maximum 100. + local heropoints = blocks[13]:sub(20,23) + print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16))) + + --0x10 0x2C 0x0C 0x04 32 bit flag value indicating heroic challenges completed. + local challenges = blocks[16]:sub(25,32) + print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32))) + + if maxed then + print('Lets try to max out some values') + -- max out money, experience + --print (blocks[8]) + blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32) + blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32) + --print (blocks[8]) + + -- max out hero challenges + --print (blocks[16]) + blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF' + blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF' + --print (blocks[16]) + + -- max out heropoints + --print (blocks[13]) + blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32) + blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32) + --print (blocks[13]) + + -- Update Checksums + print('Updating all checksums') + SetCheckSum(blocks, 3) + SetCheckSum(blocks, 2) + SetCheckSum(blocks, 1) + SetCheckSum(blocks, 0) + + print('Validating all checksums') + ValidateCheckSums(blocks) + end + + --Load dumpdata to emulator memory + if DEBUG then + print('Sending dumpdata to emulator memory') + err = LoadEmulator(blocks) + if err then return oops(err) end + core.clearCommandBuffer() + print('The simulation is now prepared. run \"hf mf sim\" ') + end +end +main(args) \ No newline at end of file From 961658bba9f9deac3d1fd58a13fd92b428b1af40 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 14 Nov 2014 13:32:11 +0100 Subject: [PATCH 39/78] FIX: rewrote the help text, cleaned up the code --- client/scripts/tnp3sim.lua | 42 +++++++------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/client/scripts/tnp3sim.lua b/client/scripts/tnp3sim.lua index ce772022..02749d3e 100644 --- a/client/scripts/tnp3sim.lua +++ b/client/scripts/tnp3sim.lua @@ -14,16 +14,17 @@ example =[[ author = "Iceman" usage = "script run tnp3sim -h -m -i " desc =[[ -This script will try to dump the contents of a Mifare TNP3xxx card. -It will need a valid KeyA in order to find the other keys and decode the card. +This script will try to load a binary datadump of a Mifare TNP3xxx card. +It vill try to validate all checksums and view some information stored in the dump +For an experimental mode, it tries to manipulate some data. +At last it sends all data to the PM3 device memory where it can be used in the command "hf mf sim" + Arguments: -h : this help - -m : Maxed out item + -m : Maxed out items (experimental) -i : filename for the datadump to read (bin) ]] -local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' - local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds local DEBUG = true -- the debug flag --- @@ -64,6 +65,7 @@ function ExitMsg(msg) print() end + local function writedumpfile(infile) t = infile:read("*all") len = string.len(t) @@ -185,36 +187,6 @@ local function ValidateCheckSums(blocks) io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) end --- function EncryptData() - -- local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' - -- if blockNo%4 ~= 3 then - -- if blockNo < 8 then - -- -- Block 0-7 not encrypted - -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) - -- else - -- local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT) - -- local baseStr = utils.ConvertHexToAscii(base) - -- local md5hash = md5.sumhexa(baseStr) - -- local aestest = core.aes(md5hash, blockdata) - - -- local hex = utils.ConvertAsciiToBytes(aestest) - -- hex = utils.ConvertBytesToHex(hex) - -- --local _,hex = bin.unpack(("H%d"):format(16),aestest) - - -- -- blocks with zero not encrypted. - -- if string.find(blockdata, '^0+$') then - -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) - -- else - -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) - -- io.write( blockNo..',') - -- end - -- end - -- else - -- -- Sectorblocks, not encrypted - -- blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) - -- end - --- end local function LoadEmulator(blocks) local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' From 463ca973e7cf1e866bb60d7cc33d38e473aa4d3d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 16 Nov 2014 11:22:06 +0100 Subject: [PATCH 40/78] FIX: hf mf eload - now supports specifying 0,1,2,4 in card memory for the file to be loaded. FIX: hf mf esave - now supports specifying 0,1,2,4 in card memory for the file to be saved. ADD: data.h - added FILE_PATH_SIZE constant ADD: hf legic load - a command help and checks for FILE_PATH_SIZE ADD: hf legis save - now checks for FILE_PATH_SIZE ADD: lf hitag - now checks for FILE_PATH_SIZE ADD: util.c - AddLogLine now checks for FILE_PATH_SIZE ADD: data load / save - now checks for FILE_PATH_SIZE FIX: ui.c - added a case of closing a filehandle FIX: hf mf cload / csave now checks for FILE_PATH_SIZE FIX: armsrc/mifarecmd.c - adjusted the buffersize in MifareEMemget from 48 to USB_CMD_DATA_SIZE --- armsrc/mifarecmd.c | 8 +- client/cmddata.c | 29 +++++-- client/cmdhflegic.c | 22 +++++- client/cmdhfmf.c | 142 +++++++++++++++++++++++------------ client/cmdlfhitag.c | 16 ++-- client/data.h | 1 + client/loclass/elite_crack.c | 1 - client/loclass/main.c | 2 - client/proxmark3.c | 2 +- client/ui.c | 1 + client/util.c | 12 ++- client/util.h | 1 + 12 files changed, 161 insertions(+), 76 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 0d1fb77a..4f3556b2 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -714,8 +714,8 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat crypto1_destroy(pcs); // add trace trailer -// memset(uid, 0x44, 4); -// LogTrace(uid, 4, 0, 0, TRUE); + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); byte_t buf[4 + 4 * 4]; memcpy(buf, &cuid, 4); @@ -826,11 +826,11 @@ void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) } void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - byte_t buf[48]; + byte_t buf[USB_CMD_DATA_SIZE]; emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4) LED_B_ON(); - cmd_send(CMD_ACK,arg0,arg1,0,buf,48); + cmd_send(CMD_ACK,arg0,arg1,0,buf,USB_CMD_DATA_SIZE); LED_B_OFF(); } diff --git a/client/cmddata.c b/client/cmddata.c index 1df3486d..9fa26721 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -478,11 +478,18 @@ int CmdSamples(const char *Cmd) int CmdLoad(const char *Cmd) { - FILE *f = fopen(Cmd, "r"); - if (!f) { - PrintAndLog("couldn't open '%s'", Cmd); - return 0; - } + char filename[FILE_PATH_SIZE] = {0x00}; + int len = 0; + + len = strlen(Cmd); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); + + FILE *f = fopen(filename, "r"); + if (!f) { + PrintAndLog("couldn't open '%s'", filename); + return 0; + } GraphTraceLen = 0; char line[80]; @@ -780,9 +787,17 @@ int CmdPlot(const char *Cmd) int CmdSave(const char *Cmd) { - FILE *f = fopen(Cmd, "w"); + char filename[FILE_PATH_SIZE] = {0x00}; + int len = 0; + + len = strlen(Cmd); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); + + + FILE *f = fopen(filename, "w"); if(!f) { - PrintAndLog("couldn't open '%s'", Cmd); + PrintAndLog("couldn't open '%s'", filename); return 0; } int i; diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 340fd2b0..35ba1f28 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -218,7 +218,24 @@ int CmdLegicRFRead(const char *Cmd) int CmdLegicLoad(const char *Cmd) { - FILE *f = fopen(Cmd, "r"); + char filename[FILE_PATH_SIZE] = {0x00}; + int len = 0; + + if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { + PrintAndLog("It loads datasamples from the file `filename`"); + PrintAndLog("Usage: hf legic load "); + PrintAndLog(" sample: hf legic load filename"); + return 0; + } + + len = strlen(Cmd); + if (len > FILE_PATH_SIZE) { + PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE); + return 0; + } + memcpy(filename, Cmd, len); + + FILE *f = fopen(filename, "r"); if(!f) { PrintAndLog("couldn't open '%s'", Cmd); return -1; @@ -251,7 +268,7 @@ int CmdLegicSave(const char *Cmd) int requested = 1024; int offset = 0; int delivered = 0; - char filename[1024]; + char filename[FILE_PATH_SIZE]; uint8_t got[1024]; sscanf(Cmd, " %s %i %i", filename, &requested, &offset); @@ -265,7 +282,6 @@ int CmdLegicSave(const char *Cmd) int remainder = requested % 8; requested = requested + 8 - remainder; } - if (offset + requested > sizeof(got)) { PrintAndLog("Tried to read past end of buffer, + > 1024"); return 0; diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 35bf2a00..b7f336db 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -680,11 +680,10 @@ int CmdHF14AMfDump(const char *Cmd) int CmdHF14AMfRestore(const char *Cmd) { - uint8_t sectorNo,blockNo; uint8_t keyType = 0; - uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t key[6] = {0xFF}; + uint8_t bldata[16] = {0x00}; uint8_t keyA[40][6]; uint8_t keyB[40][6]; uint8_t numSectors; @@ -702,7 +701,7 @@ int CmdHF14AMfRestore(const char *Cmd) default: numSectors = 16; } - if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { + if (cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: hf mf restore [card memory]"); PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLog(""); @@ -710,11 +709,7 @@ int CmdHF14AMfRestore(const char *Cmd) PrintAndLog(" hf mf restore 4"); return 0; } - - if ((fdump = fopen("dumpdata.bin","rb")) == NULL) { - PrintAndLog("Could not find file dumpdata.bin"); - return 1; - } + if ((fkeys = fopen("dumpkeys.bin","rb")) == NULL) { PrintAndLog("Could not find file dumpkeys.bin"); return 1; @@ -734,6 +729,12 @@ int CmdHF14AMfRestore(const char *Cmd) } } + fclose(fkeys); + + if ((fdump = fopen("dumpdata.bin","rb")) == NULL) { + PrintAndLog("Could not find file dumpdata.bin"); + return 1; + } PrintAndLog("Restoring dumpdata.bin to card"); for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { @@ -777,7 +778,7 @@ int CmdHF14AMfRestore(const char *Cmd) } fclose(fdump); - fclose(fkeys); + return 0; } @@ -1043,7 +1044,7 @@ int CmdHF14AMfChk(const char *Cmd) } FILE * f; - char filename[256]={0}; + char filename[FILE_PATH_SIZE]={0}; char buf[13]; uint8_t *keyBlock = NULL, *p; uint8_t stKeyBlock = 20; @@ -1135,7 +1136,7 @@ int CmdHF14AMfChk(const char *Cmd) keycnt++; } else { // May be a dic file - if ( param_getstr(Cmd, 2 + i,filename) > 255 ) { + if ( param_getstr(Cmd, 2 + i,filename) >= FILE_PATH_SIZE ) { PrintAndLog("File name too long"); free(keyBlock); return 2; @@ -1419,26 +1420,44 @@ int CmdHF14AMfESet(const char *Cmd) int CmdHF14AMfELoad(const char *Cmd) { FILE * f; - char filename[255]; + char filename[FILE_PATH_SIZE]; char *fnameptr = filename; char buf[64]; uint8_t buf8[64]; - int i, len, blockNum; + int i, len, blockNum, numBlocks; + int nameParamNo = 1; memset(filename, 0, sizeof(filename)); memset(buf, 0, sizeof(buf)); - if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { + char ctmp = param_getchar(Cmd, 0); + + if ( ctmp == 'h' || ctmp == 0x00) { PrintAndLog("It loads emul dump from the file `filename.eml`"); - PrintAndLog("Usage: hf mf eload "); + PrintAndLog("Usage: hf mf eload [card memory] "); + PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLog(""); PrintAndLog(" sample: hf mf eload filename"); + PrintAndLog(" hf mf eload 4 filename"); return 0; } - len = strlen(Cmd); - if (len > 250) len = 250; + switch (ctmp) { + case '0' : numBlocks = 5*4; break; + case '1' : + case '\0': numBlocks = 16*4; break; + case '2' : numBlocks = 32*4; break; + case '4' : numBlocks = 256; break; + default: { + numBlocks = 16*4; + nameParamNo = 0; + } + } + + len = param_getstr(Cmd,nameParamNo,filename); + + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); fnameptr += len; sprintf(fnameptr, ".eml"); @@ -1446,43 +1465,49 @@ int CmdHF14AMfELoad(const char *Cmd) // open file f = fopen(filename, "r"); if (f == NULL) { - PrintAndLog("File not found or locked."); + PrintAndLog("File %s not found or locked", filename); return 1; } +// for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { +// for(blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) { + blockNum = 0; while(!feof(f)){ memset(buf, 0, sizeof(buf)); + if (fgets(buf, sizeof(buf), f) == NULL) { - if((blockNum == 16*4) || (blockNum == 32*4 + 8*16)) { // supports both old (1K) and new (4K) .eml files) - break; - } + + if (blockNum >= numBlocks) break; + PrintAndLog("File reading error."); fclose(f); return 2; } + if (strlen(buf) < 32){ if(strlen(buf) && feof(f)) break; PrintAndLog("File content error. Block data must include 32 HEX symbols"); return 2; } + for (i = 0; i < 32; i += 2) { sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]); -// PrintAndLog("data[%02d]:%s", blockNum, sprint_hex(buf8, 16)); } + if (mfEmlSetMem(buf8, blockNum, 1)) { PrintAndLog("Cant set emul block: %3d", blockNum); return 3; } blockNum++; - if (blockNum >= 32*4 + 8*16) break; + if (blockNum >= numBlocks) break; } fclose(f); - if ((blockNum != 16*4) && (blockNum != 32*4 + 8*16)) { - PrintAndLog("File content error. There must be 64 or 256 blocks."); + if ((blockNum != numBlocks)) { + PrintAndLog("File content error. Got %d must be %d blocks.",blockNum, numBlocks); fclose(f); return 4; } @@ -1494,56 +1519,76 @@ int CmdHF14AMfELoad(const char *Cmd) int CmdHF14AMfESave(const char *Cmd) { FILE * f; - char filename[255]; + char filename[FILE_PATH_SIZE]; char * fnameptr = filename; uint8_t buf[64]; - int i, j, len; + int i, j, len, numBlocks; + int nameParamNo = 1; memset(filename, 0, sizeof(filename)); memset(buf, 0, sizeof(buf)); - if (param_getchar(Cmd, 0) == 'h') { - PrintAndLog("It saves emul dump into the file `filename.eml` or `cardID.eml`"); - PrintAndLog("Usage: hf mf esave [file name w/o `.eml`]"); + char ctmp = param_getchar(Cmd, 0); + + if ( ctmp == 'h') { + PrintAndLog("It saves emul dump into the file `filename.eml` or `cardID.eml`"); + PrintAndLog(" Usage: hf mf esave [card memory] [file name w/o `.eml`]"); + PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLog(""); PrintAndLog(" sample: hf mf esave "); - PrintAndLog(" hf mf esave filename"); + PrintAndLog(" hf mf esave 4"); + PrintAndLog(" hf mf esave 4 filename"); return 0; } - - len = strlen(Cmd); - if (len > 250) len = 250; + switch (ctmp) { + case '0' : numBlocks = 5*4; break; + case '1' : + case '\0': numBlocks = 16*4; break; + case '2' : numBlocks = 32*4; break; + case '4' : numBlocks = 256; break; + default: { + numBlocks = 16*4; + nameParamNo = 0; + } + } + + len = param_getstr(Cmd,nameParamNo,filename); + + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + + // user supplied filename? if (len < 1) { - // get filename + // get filename (UID from memory) if (mfEmlGetMem(buf, 0, 1)) { - PrintAndLog("Cant get block: %d", 0); - return 1; + PrintAndLog("Can\'t get UID from block: %d", 0); + sprintf(filename, "dump.eml"); } for (j = 0; j < 7; j++, fnameptr += 2) - sprintf(fnameptr, "%02x", buf[j]); + sprintf(fnameptr, "%02X", buf[j]); } else { - memcpy(filename, Cmd, len); fnameptr += len; } + // add file extension sprintf(fnameptr, ".eml"); // open file f = fopen(filename, "w+"); // put hex - for (i = 0; i < 32*4 + 8*16; i++) { + for (i = 0; i < numBlocks; i++) { if (mfEmlGetMem(buf, i, 1)) { PrintAndLog("Cant get block: %d", i); break; } for (j = 0; j < 16; j++) - fprintf(f, "%02x", buf[j]); + fprintf(f, "%02X", buf[j]); fprintf(f,"\n"); } fclose(f); - PrintAndLog("Saved to file: %s", filename); + PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename); return 0; } @@ -1623,7 +1668,6 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); break; - break; } keyA = bytes_to_num(data, 6); keyB = bytes_to_num(data + 10, 6); @@ -1709,7 +1753,7 @@ int CmdHF14AMfCSetBlk(const char *Cmd) int CmdHF14AMfCLoad(const char *Cmd) { FILE * f; - char filename[255]; + char filename[FILE_PATH_SIZE]; char * fnameptr = filename; char buf[64]; uint8_t buf8[64]; @@ -1750,7 +1794,7 @@ int CmdHF14AMfCLoad(const char *Cmd) return 0; } else { len = strlen(Cmd); - if (len > 250) len = 250; + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd, len); fnameptr += len; @@ -1873,7 +1917,7 @@ int CmdHF14AMfCGetSc(const char *Cmd) { int CmdHF14AMfCSave(const char *Cmd) { FILE * f; - char filename[255]; + char filename[FILE_PATH_SIZE]; char * fnameptr = filename; uint8_t fillFromEmulator = 0; uint8_t buf[64]; @@ -1915,7 +1959,7 @@ int CmdHF14AMfCSave(const char *Cmd) { return 0; } else { len = strlen(Cmd); - if (len > 250) len = 250; + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; if (len < 1) { // get filename diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 331f2c87..ede03575 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -133,13 +133,17 @@ int CmdLFHitagSnoop(const char *Cmd) { } int CmdLFHitagSim(const char *Cmd) { - UsbCommand c = {CMD_SIMULATE_HITAG}; - char filename[256] = { 0x00 }; + + UsbCommand c = {CMD_SIMULATE_HITAG}; + char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf; bool tag_mem_supplied; + int len = 0; - param_getstr(Cmd,0,filename); - + len = strlen(Cmd); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); + if (strlen(filename) > 0) { if ((pf = fopen(filename,"rb+")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); @@ -147,9 +151,9 @@ int CmdLFHitagSim(const char *Cmd) { } tag_mem_supplied = true; if (fread(c.d.asBytes,48,1,pf) == 0) { - PrintAndLog("Error: File reading error"); + PrintAndLog("Error: File reading error"); return 1; - } + } fclose(pf); } else { tag_mem_supplied = false; diff --git a/client/data.h b/client/data.h index 33ee9d04..eead3fa8 100644 --- a/client/data.h +++ b/client/data.h @@ -13,6 +13,7 @@ #include +#define FILE_PATH_SIZE 1000 #define SAMPLE_BUFFER_SIZE 64 extern uint8_t* sample_buf; diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index cba31808..a2bd6647 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -552,7 +552,6 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) */ int bruteforceFile(const char *filename, uint16_t keytable[]) { - FILE *f = fopen(filename, "rb"); if(!f) { prnlog("Failed to read from file '%s'", filename); diff --git a/client/loclass/main.c b/client/loclass/main.c index b7ea53e5..50671a19 100644 --- a/client/loclass/main.c +++ b/client/loclass/main.c @@ -78,8 +78,6 @@ int showHelp() int main (int argc, char **argv) { - - prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n"); prnlog("Comes with ABSOLUTELY NO WARRANTY"); prnlog("Released as GPLv2\n"); diff --git a/client/proxmark3.c b/client/proxmark3.c index d2bb2011..66571144 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -115,7 +115,7 @@ static void *main_loop(void *targ) { } FILE *script_file = NULL; - char script_cmd_buf[256]; + char script_cmd_buf[256]; // iceman, needs lua script the same file_path_buffer as the rest if (arg->script_cmds_file) { diff --git a/client/ui.c b/client/ui.c index 5111e295..d4758525 100644 --- a/client/ui.c +++ b/client/ui.c @@ -79,6 +79,7 @@ void PrintAndLog(char *fmt, ...) vfprintf(logfile, fmt, argptr2); fprintf(logfile,"\n"); fflush(logfile); + fclose(logfile); // ICEMAN, this logfile is never closed?!? } va_end(argptr2); diff --git a/client/util.c b/client/util.c index 903791a0..56c4998d 100644 --- a/client/util.c +++ b/client/util.c @@ -46,12 +46,18 @@ int ukbhit(void) { #endif // log files functions -void AddLogLine(char *fileName, char *extData, char *c) { +void AddLogLine(char *file, char *extData, char *c) { FILE *fLog = NULL; + char filename[FILE_PATH_SIZE] = {0x00}; + int len = 0; - fLog = fopen(fileName, "a"); + len = strlen(file); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, file, len); + + fLog = fopen(filename, "a"); if (!fLog) { - printf("Could not append log file %s", fileName); + printf("Could not append log file %s", filename); return; } diff --git a/client/util.h b/client/util.h index 2677ab84..54562a07 100644 --- a/client/util.h +++ b/client/util.h @@ -15,6 +15,7 @@ #include #include #include +#include "data.h" #ifndef MIN # define MIN(a, b) (((a) < (b)) ? (a) : (b)) From 95e635947bc4628b713fa00d7a533a881bca7fc4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 26 Nov 2014 13:52:39 +0100 Subject: [PATCH 41/78] ADD: the option to simulate tnp3xxx inthe command "hf mf sim" ADD: found some new default keys ADD: changed alot of memorys buffers to use constant values. like usbbuffer sizes, tracelogs, etc etc ADD: all changes Peter filmoore has in his pull request. --- armsrc/appmain.c | 10 +++++--- armsrc/apps.h | 9 ++++--- armsrc/iclass.c | 28 ++++++++++------------ armsrc/iso14443a.c | 38 ++++++++++++++++++++---------- armsrc/iso14443a.h | 2 +- armsrc/mifareutil.h | 2 +- armsrc/string.h | 4 ++-- armsrc/util.c | 9 +++++++ armsrc/util.h | 2 ++ client/cmdhf14a.c | 9 +++---- client/cmdhf14b.c | 11 ++++----- client/cmdhfepa.c | 3 ++- client/cmdhficlass.c | 4 ++-- client/cmdhfmf.c | 9 +++---- client/cmdhfmfdes.c | 10 ++------ client/cmdhfmfdes.h | 2 +- client/cmdlfhitag.c | 11 ++++----- client/data.h | 2 ++ client/lualibs/mf_default_keys.lua | 12 ++++++++++ client/scripts/tnp3sim.lua | 2 +- include/usb_cmd.h | 2 ++ 21 files changed, 106 insertions(+), 75 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index be904b4f..09acf41f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -311,7 +311,7 @@ extern struct version_information version_information; extern char *_bootphase1_version_pointer, _flash_start, _flash_end; void SendVersion(void) { - char temp[256]; /* Limited data payload in USB packets */ + char temp[512]; /* Limited data payload in USB packets */ DbpString("Prox/RFID mark3 RFID instrument"); /* Try to find the bootrom version information. Expect to find a pointer at @@ -367,9 +367,8 @@ void SamyRun() for (;;) { -// UsbPoll(FALSE); usb_poll(); - WDT_HIT(); + WDT_HIT(); // Was our button held down or pressed? int button_pressed = BUTTON_HELD(1000); @@ -792,10 +791,15 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_SIMULATE_TAG_ISO_14443a: SimulateIso14443aTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); // ## Simulate iso14443a tag - pass tag type & UID break; + case CMD_EPA_PACE_COLLECT_NONCE: EPA_PACE_Collect_Nonce(c); break; + // case CMD_EPA_: + // EpaFoo(c); + // break; + case CMD_READER_MIFARE: ReaderMifare(c->arg[0]); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 0db2a19d..c9616e5e 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -32,10 +32,13 @@ // The large multi-purpose buffer, typically used to hold A/D samples, // maybe processed in some way. -uint32_t BigBuf[10000]; +//#define BIG_BUFF_SIZE 10000 // PM3 w. 256KB ram +#define BIG_BUFF_SIZE 10000 // PM3 w. 512KB ram + +uint32_t BigBuf[BIG_BUFF_SIZE]; // BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT #define TRACE_OFFSET 0 -#define TRACE_SIZE 3000 +#define TRACE_SIZE 4096 #define RECV_CMD_OFFSET 3032 #define RECV_CMD_SIZE 64 #define RECV_RES_OFFSET 3096 @@ -45,7 +48,7 @@ uint32_t BigBuf[10000]; #define FREE_BUFFER_OFFSET 7256 #define FREE_BUFFER_SIZE 2744 -extern const uint8_t OddByteParity[256]; +//extern const uint8_t OddByteParity[256]; extern uint8_t *trace; // = (uint8_t *) BigBuf; extern int traceLen; // = 0; extern int rsamples; // = 0; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 6ceb436b..91a802ca 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -228,7 +228,8 @@ static RAMFUNC int OutOfNDecoding(int bit) // Calculate the parity bit for the client... Uart.parityBits <<= 1; - Uart.parityBits ^= OddByteParity[(Uart.shiftReg & 0xff)]; + //Uart.parityBits ^= OddByteParity[(Uart.shiftReg & 0xff)]; + Uart.parityBits ^= oddparity(Uart.shiftReg & 0xff); Uart.bitCnt = 0; Uart.shiftReg = 0; @@ -251,7 +252,8 @@ static RAMFUNC int OutOfNDecoding(int bit) // Calculate the parity bit for the client... Uart.parityBits <<= 1; - Uart.parityBits ^= OddByteParity[(Uart.dropPosition & 0xff)]; + //Uart.parityBits ^= OddByteParity[(Uart.dropPosition & 0xff)]; + Uart.parityBits ^= oddparity((Uart.dropPosition & 0xff)); Uart.bitCnt = 0; Uart.shiftReg = 0; @@ -452,8 +454,7 @@ static RAMFUNC int ManchesterDecoding(int v) else { modulation = bit & Demod.syncBit; modulation |= ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; - //modulation = ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; - + Demod.samples += 4; if(Demod.posCount==0) { @@ -488,7 +489,8 @@ static RAMFUNC int ManchesterDecoding(int v) Demod.output[Demod.len] = 0x0f; Demod.len++; Demod.parityBits <<= 1; - Demod.parityBits ^= OddByteParity[0x0f]; + //Demod.parityBits ^= OddByteParity[0x0f]; + Demod.parityBits ^= oddparity(0x0f); Demod.state = DEMOD_UNSYNCD; // error = 0x0f; return TRUE; @@ -613,7 +615,8 @@ static RAMFUNC int ManchesterDecoding(int v) // FOR ISO15639 PARITY NOT SEND OTA, JUST CALCULATE IT FOR THE CLIENT Demod.parityBits <<= 1; - Demod.parityBits ^= OddByteParity[(Demod.shiftReg & 0xff)]; + //Demod.parityBits ^= OddByteParity[(Demod.shiftReg & 0xff)]; + Demod.parityBits ^= oddparity((Demod.shiftReg & 0xff)); Demod.bitCount = 0; Demod.shiftReg = 0; @@ -870,10 +873,7 @@ static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - /*if(OutOfNDecoding((b & 0xf0) >> 4)) { - *len = Uart.byteCnt; - return TRUE; - }*/ + if(OutOfNDecoding(b & 0x0f)) { *len = Uart.byteCnt; return TRUE; @@ -1395,7 +1395,6 @@ void ReaderTransmitIClass(uint8_t* frame, int len) int par = 0; // This is tied to other size changes - // uint8_t* frame_addr = ((uint8_t*)BigBuf) + 2024; CodeIClassCommand(frame,len); // Select the card @@ -1435,7 +1434,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!! @@ -1446,10 +1445,7 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; skip = !skip; if(skip) continue; - /*if(ManchesterDecoding((b>>4) & 0xf)) { - *samples = ((c - 1) << 3) + 4; - return TRUE; - }*/ + if(ManchesterDecoding(b & 0x0f)) { *samples = c << 3; return TRUE; diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 6fe83c6e..fcd51d63 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -124,6 +124,8 @@ uint32_t LastProxToAirDuration; #define SEC_Y 0x00 #define SEC_Z 0xc0 +//replaced large parity table with small parity generation function - saves flash code +/* const uint8_t OddByteParity[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, @@ -142,7 +144,7 @@ const uint8_t OddByteParity[256] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; - +*/ void iso14a_set_trigger(bool enable) { trigger = enable; @@ -165,10 +167,12 @@ void iso14a_set_timeout(uint32_t timeout) { // Generate the parity value for a byte sequence // //----------------------------------------------------------------------------- +/* byte_t oddparity (const byte_t bt) { return OddByteParity[bt]; } +*/ uint32_t GetParity(const uint8_t * pbtCmd, int iLen) { @@ -178,7 +182,8 @@ uint32_t GetParity(const uint8_t * pbtCmd, int iLen) // Generate the parity bits for (i = 0; i < iLen; i++) { // and save them to a 32Bit word - dwPar |= ((OddByteParity[pbtCmd[i]]) << i); + //dwPar |= ((OddByteParity[pbtCmd[i]]) << i); + dwPar |= (oddparity(pbtCmd[i]) << i); } return dwPar; } @@ -683,7 +688,8 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, int len, uint32_t dwParity } // Get the parity bit - if ((dwParity >> i) & 0x01) { + //if ((dwParity >> i) & 0x01) { + if (oddparity(cmd[i]) & 0x01) { ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; } else { @@ -891,6 +897,12 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) response1[1] = 0x00; sak = 0x28; } break; + case 5: { // MIFARE TNP3XXX + // Says: I am a toy + response1[0] = 0x01; + response1[1] = 0x0f; + sak = 0x01; + } break; default: { Dbprintf("Error: unkown tagtype (%d)",tagType); return; @@ -1695,7 +1707,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u memcpy(uid_resp,resp,4); } uid_resp_len = 4; - // Dbprintf("uid: %02x %02x %02x %02x",uid_resp[0],uid_resp[1],uid_resp[2],uid_resp[3]); + // calculate crypto UID. Always use last 4 Bytes. if(cuid_ptr) { @@ -1713,6 +1725,8 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u if (!ReaderReceive(resp)) return 0; sak = resp[0]; + //Dbprintf("SAK: %02x",resp[0]); + // Test if more parts of the uid are comming if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: @@ -1770,8 +1784,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Signal field is on with the appropriate LED - if (fpga_minor_mode == FPGA_HF_ISO14443A_READER_MOD - || fpga_minor_mode == FPGA_HF_ISO14443A_READER_LISTEN) { + if (fpga_minor_mode == FPGA_HF_ISO14443A_READER_MOD || fpga_minor_mode == FPGA_HF_ISO14443A_READER_LISTEN) { LED_D_ON(); } else { LED_D_OFF(); @@ -1859,10 +1872,10 @@ void ReaderIso14443a(UsbCommand *c) if(param & ISO14A_APPEND_CRC) { AppendCrc14443a(cmd,len); len += 2; - lenbits += 16; + if(lenbits>0) + lenbits += 16; } - if(lenbits>0) { - + if(lenbits>0) { ReaderTransmitBitsPar(cmd,lenbits,GetParity(cmd,lenbits/8), NULL); } else { ReaderTransmit(cmd,len, NULL); @@ -1937,8 +1950,8 @@ void ReaderMifare(bool first_try) uint32_t nt = 0; uint32_t previous_nt = 0; static uint32_t nt_attacked = 0; - byte_t par_list[8] = {0,0,0,0,0,0,0,0}; - byte_t ks_list[8] = {0,0,0,0,0,0,0,0}; + byte_t par_list[8] = {0x00}; + byte_t ks_list[8] = {0x00}; static uint32_t sync_time; static uint32_t sync_cycles; @@ -1947,8 +1960,6 @@ void ReaderMifare(bool first_try) uint16_t consecutive_resyncs = 0; int isOK = 0; - - if (first_try) { mf_nr_ar3 = 0; iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); @@ -1971,6 +1982,7 @@ void ReaderMifare(bool first_try) LED_C_OFF(); + Dbprintf("Mifare: Before loopen"); for(uint16_t i = 0; TRUE; i++) { WDT_HIT(); diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 3c3993ba..b2c59907 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -75,7 +75,7 @@ typedef struct { -extern byte_t oddparity (const byte_t bt); +//extern byte_t oddparity (const byte_t bt); extern uint32_t GetParity(const uint8_t *pbtCmd, int iLen); extern void AppendCrc14443a(uint8_t *data, int len); diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index f9d74384..bd313699 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -53,7 +53,7 @@ extern int MF_DBGLEVEL; #define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); //functions -uint8_t* mifare_get_bigbufptr(void); + int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing); int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint8_t *timing); int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint32_t *timing); diff --git a/armsrc/string.h b/armsrc/string.h index 1067b91f..6e2c7883 100644 --- a/armsrc/string.h +++ b/armsrc/string.h @@ -16,9 +16,9 @@ #include int strlen(const char *str); -void *memcpy(void *dest, const void *src, int len); +RAMFUNC void *memcpy(void *dest, const void *src, int len); void *memset(void *dest, int c, int len); -int memcmp(const void *av, const void *bv, int len); +RAMFUNC int memcmp(const void *av, const void *bv, int len); void memxor(uint8_t * dest, uint8_t * src, size_t len); char *strncat(char *dest, const char *src, unsigned int n); char *strcat(char *dest, const char *src); diff --git a/armsrc/util.c b/armsrc/util.c index 0558fb94..b1ef6ea0 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -85,6 +85,15 @@ int32_t le24toh (uint8_t data[3]) return (data[2] << 16) | (data[1] << 8) | data[0]; } +//added here for parity calulations +uint8_t oddparity(uint8_t bt) +{ + uint16_t v = bt; + v ^= v >> 4; + v &= 0xF; + return ((0x9669 >> v) & 1); +} + void LEDsoff() { LED_A_OFF(); diff --git a/armsrc/util.h b/armsrc/util.h index c6503395..80ed9b54 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -35,6 +35,8 @@ uint64_t bytes_to_num(uint8_t* src, size_t len); void rol(uint8_t *data, const size_t len); void lsl (uint8_t *data, size_t len); int32_t le24toh (uint8_t data[3]); +//added parity generation function here +uint8_t oddparity(uint8_t bt); void SpinDelay(int ms); void SpinDelayUs(int us); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 0f2b5222..391908e7 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -44,7 +44,7 @@ int CmdHF14AList(const char *Cmd) ShowWaitCycles = true; } - uint8_t got[1920]; + uint8_t got[TRACE_BUFFER_SIZE]; GetFromBigBuf(got,sizeof(got),0); WaitForResponse(CMD_ACK,NULL); @@ -62,7 +62,7 @@ int CmdHF14AList(const char *Cmd) uint32_t EndOfTransmissionTimestamp = 0; for (;;) { - if(i >= 1900) { + if(i >= TRACE_BUFFER_SIZE) { break; } @@ -86,7 +86,7 @@ int CmdHF14AList(const char *Cmd) if (len > 100) { break; } - if (i + len >= 1900) { + if (i + len >= TRACE_BUFFER_SIZE) { break; } @@ -400,6 +400,7 @@ int CmdHF14ASim(const char *Cmd) PrintAndLog(" 2 = MIFARE Ultralight"); PrintAndLog(" 3 = MIFARE DESFIRE"); PrintAndLog(" 4 = ISO/IEC 14443-4"); + PrintAndLog(" 5 = MIFARE TNP3XXX"); PrintAndLog(""); return 1; } @@ -628,7 +629,7 @@ static void waitCmd(uint8_t iSelect) UsbCommand resp; char *hexout; - if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + if (WaitForResponseTimeout(CMD_ACK,&resp,10000)) { recv = resp.d.asBytes; uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0]; PrintAndLog("received %i octets",iLen); diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index f580e6d5..2c4c5949 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -144,7 +144,7 @@ demodError: int CmdHF14BList(const char *Cmd) { - uint8_t got[960]; + uint8_t got[TRACE_BUFFER_SIZE]; GetFromBigBuf(got,sizeof(got),0); WaitForResponse(CMD_ACK,NULL); @@ -156,9 +156,8 @@ int CmdHF14BList(const char *Cmd) int prev = -1; for(;;) { - if(i >= 900) { - break; - } + + if(i >= TRACE_BUFFER_SIZE) { break; } bool isResponse; int timestamp = *((uint32_t *)(got+i)); @@ -175,7 +174,7 @@ int CmdHF14BList(const char *Cmd) if(len > 100) { break; } - if(i + len >= 900) { + if(i + len >= TRACE_BUFFER_SIZE) { break; } @@ -357,7 +356,7 @@ int CmdHF14BCmdRaw (const char *cmd) { SendCommand(&c); if (reply) { - if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + if (WaitForResponseTimeout(CMD_ACK,&resp,10000)) { recv = resp.d.asBytes; PrintAndLog("received %i octets",resp.arg[0]); if(!resp.arg[0]) diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index 92e61c68..c893da76 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -45,7 +45,7 @@ int CmdHFEPACollectPACENonces(const char *Cmd) SendCommand(&c); UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); + WaitForResponse(CMD_ACK,&resp); // check if command failed if (resp.arg[0] != 0) { @@ -68,6 +68,7 @@ int CmdHFEPACollectPACENonces(const char *Cmd) return 1; } +// UI-related stuff // UI-related stuff static const command_t CommandTable[] = diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 47ff2db0..7bbf26b2 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -55,7 +55,7 @@ int CmdHFiClassList(const char *Cmd) return 0; } - uint8_t got[1920]; + uint8_t got[TRACE_BUFFER_SIZE]; GetFromBigBuf(got,sizeof(got),0); WaitForResponse(CMD_ACK,NULL); @@ -77,7 +77,7 @@ int CmdHFiClassList(const char *Cmd) uint32_t EndOfTransmissionTimestamp = 0; - for( i=0; i < 1900;) + for( i=0; i < TRACE_BUFFER_SIZE;) { //First 32 bits contain // isResponse (1 bit) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index b7f336db..54d0f4f1 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -2003,7 +2003,7 @@ int CmdHF14AMfCSave(const char *Cmd) { int CmdHF14AMfSniff(const char *Cmd){ - // params + bool wantLogToFile = 0; bool wantDecrypt = 0; //bool wantSaveToEml = 0; TODO @@ -2031,8 +2031,8 @@ int CmdHF14AMfSniff(const char *Cmd){ PrintAndLog(" l - save encrypted sequence to logfile `uid.log`"); PrintAndLog(" d - decrypt sequence and put it to log file `uid.log`"); PrintAndLog(" n/a e - decrypt sequence, collect read and write commands and save the result of the sequence to emulator memory"); - PrintAndLog(" r - decrypt sequence, collect read and write commands and save the result of the sequence to emulator dump file `uid.eml`"); - PrintAndLog("Usage: hf mf sniff [l][d][e][r]"); + PrintAndLog(" f - decrypt sequence, collect read and write commands and save the result of the sequence to emulator dump file `uid.eml`"); + PrintAndLog("Usage: hf mf sniff [l][d][e][f]"); PrintAndLog(" sample: hf mf sniff l d e"); return 0; } @@ -2220,9 +2220,6 @@ int GetCardSize() return -1; } - - - static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index c0c7a67e..75aaa084 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -27,9 +27,9 @@ uint8_t CMDPOS = 0; uint8_t LENPOS = 1; -uint8_t key_zero_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +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_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }; 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); @@ -537,11 +537,6 @@ int CmdHF14ADesEnumApplications(const char *Cmd){ return 1; } -int CmdHF14ADesNonces(const char *Cmd){ - return 1; -} - -// // MIAFRE DesFire Authentication // #define BUFSIZE 256 @@ -670,7 +665,6 @@ static command_t CommandTable[] = {"wb", CmdHF14ADesWb, 0, "write MIFARE DesFire block"}, {"info", CmdHF14ADesInfo, 0, "Get MIFARE DesFire information"}, {"enum", CmdHF14ADesEnumApplications,0, "Tries enumerate all applications"}, - {"nonce", CmdHF14ADesNonces, 0, " Collect n>0 nonces"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhfmfdes.h b/client/cmdhfmfdes.h index 06f592ed..6ebc98ae 100644 --- a/client/cmdhfmfdes.h +++ b/client/cmdhfmfdes.h @@ -14,7 +14,7 @@ int CmdHF14ADesRb(const char* cmd); int CmdHF14ADesWb(const char* cmd); int CmdHF14ADesInfo(const char *Cmd); int CmdHF14ADesEnumApplications(const char *Cmd); -int CmdHF14ADesNonces(const char *Cmd); + char * GetCardSizeStr( uint8_t fsize ); char * GetVendorStr( uint8_t id); char * GetProtocolStr(uint8_t id); diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index ede03575..9a228b2b 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -29,7 +29,7 @@ size_t nbytes(size_t nbits) { int CmdLFHitagList(const char *Cmd) { - uint8_t got[3000]; + uint8_t got[TRACE_BUFFER_SIZE]; GetFromBigBuf(got,sizeof(got),0); WaitForResponse(CMD_ACK,NULL); @@ -44,9 +44,8 @@ int CmdLFHitagList(const char *Cmd) FILE* pf = NULL; for (;;) { - if(i >= 1900) { - break; - } + + if(i >= TRACE_BUFFER_SIZE) { break; } bool isResponse; int timestamp = *((uint32_t *)(got+i)); @@ -71,9 +70,7 @@ int CmdLFHitagList(const char *Cmd) if (len > 100) { break; } - if (i + len >= 1900) { - break; - } + if (i + len >= TRACE_BUFFER_SIZE) { break;} uint8_t *frame = (got+i+9); diff --git a/client/data.h b/client/data.h index eead3fa8..41bd9a41 100644 --- a/client/data.h +++ b/client/data.h @@ -13,6 +13,8 @@ #include +//trace buffer size as defined in armsrc/apps.h TRACE_SIZE +#define TRACE_BUFFER_SIZE 4096 #define FILE_PATH_SIZE 1000 #define SAMPLE_BUFFER_SIZE 64 diff --git a/client/lualibs/mf_default_keys.lua b/client/lualibs/mf_default_keys.lua index b9b414d8..810f0d6e 100644 --- a/client/lualibs/mf_default_keys.lua +++ b/client/lualibs/mf_default_keys.lua @@ -147,6 +147,18 @@ local _keys = { --]] '4b0b20107ccb', + --[[ + Kiev metro cards + --]] + '8fe644038790', + 'f14ee7cae863', + '632193be1c3c', + '569369c5a0e5', + '9de89e070277', + 'eff603e1efe9', + '644672bd4afe', + + 'b5ff67cba951', } --- diff --git a/client/scripts/tnp3sim.lua b/client/scripts/tnp3sim.lua index 02749d3e..f43dafa2 100644 --- a/client/scripts/tnp3sim.lua +++ b/client/scripts/tnp3sim.lua @@ -349,7 +349,7 @@ local function main(args) err = LoadEmulator(blocks) if err then return oops(err) end core.clearCommandBuffer() - print('The simulation is now prepared. run \"hf mf sim\" ') + print('The simulation is now prepared.\n --> run \"hf mf sim 5 '..uid..'\" <--') end end main(args) \ No newline at end of file diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 36fcf248..55df18f4 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -112,7 +112,9 @@ typedef struct { #define CMD_SIMULATE_TAG_LEGIC_RF 0x0387 #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 From 06b58a94f0be3256853a97387fc7e5782ce335c7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 27 Nov 2014 22:16:17 +0100 Subject: [PATCH 42/78] BUG: don't try to fix things that ain't broken.. or not. My try for a fix ended up making the PrintAndLog function stop working. Just by calling a fclose.. fixed. --- armsrc/appmain.c | 1 + armsrc/lfops.c | 62 +++++++++++++++++++++------------------------- client/cmdlfem4x.c | 13 +++------- client/scripting.c | 4 +-- client/ui.c | 1 - 5 files changed, 35 insertions(+), 46 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 09acf41f..18c65e80 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -674,6 +674,7 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_SIMULATE_TAG_125K: LED_A_ON(); SimulateTagLowFrequency(c->arg[0], c->arg[1], 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_A_OFF(); break; case CMD_LF_SIMULATE_BIDIR: diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 1a7c3224..0755e1e5 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -449,6 +449,12 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) DbpString("Now use tiread to check"); } + + +// PIO_CODR = Clear Output Data Register +// PIO_SODR = Set Output Data Register +//#define LOW(x) AT91C_BASE_PIOA->PIO_CODR = (x) +//#define HIGH(x) AT91C_BASE_PIOA->PIO_SODR = (x) void SimulateTagLowFrequency(int period, int gap, int ledcontrol) { int i = 0; @@ -456,76 +462,64 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); // Connect the A/D to the peak-detected low-frequency path. - //SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; // (PIO_PER) PIO Enable Register , - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; // (PIO_OER) Output Enable Register - AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; // (PIO_ODR) Output Disable Register + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(150); + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low + // Configure output and enable pin that is connected to the FPGA (for modulating) + // AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; // (PIO_PER) PIO Enable Register + // AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; // (PIO_OER) Output Enable Register + // AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; // (PIO_ODR) Output Disable Register + + AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0; while(!BUTTON_PRESS()) { WDT_HIT(); // PIO_PDSR = Pin Data Status Register // GPIO_SSC_CLK = SSC Transmit Clock - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { // wait for ssp_clk to go high + // wait ssp_clk == high + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { if(BUTTON_PRESS()) { DbpString("Stopped at 0"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off return; } WDT_HIT(); } - - // PIO_CODR = Clear Output Data Register - // PIO_SODR = Set Output Data Register - //#define LOW(x) AT91C_BASE_PIOA->PIO_CODR = (x) - //#define HIGH(x) AT91C_BASE_PIOA->PIO_SODR = (x) if ( buf[i] > 0 ){ - HIGH(GPIO_SSC_DOUT); - //FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + OPEN_COIL(); } else { - LOW(GPIO_SSC_DOUT); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SHORT_COIL(); } - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { // wait for ssp_clk to go low + DbpString("Enter Sim3"); + // wait ssp_clk == low + while( (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) ) { if(BUTTON_PRESS()) { - DbpString("Stopped at 1"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + DbpString("stopped at 1"); return; } WDT_HIT(); - } + } + DbpString("Enter Sim4 "); //SpinDelayUs(512); ++i; if(i == period) { i = 0; if (gap) { - // turn of modulation - LOW(GPIO_SSC_DOUT); - // wait - SpinDelay(gap); + SHORT_COIL(); + SpinDelay(gap); } } } DbpString("Stopped"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); return; } diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 07f909ac..8c6461df 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -196,7 +196,7 @@ retest: */ int CmdEM410xSim(const char *Cmd) { - int i, n, j, h, binary[4], parity[4]; + int i, n, j, binary[4], parity[4]; char cmdp = param_getchar(Cmd, 0); uint8_t uid[5] = {0x00}; @@ -222,9 +222,6 @@ int CmdEM410xSim(const char *Cmd) /* clear our graph */ ClearGraph(0); - /* write it out a few times */ - //for (h = 0; h < 4; h++) - //{ /* write 9 start bits */ for (i = 0; i < 9; i++) AppendGraph(0, clock, 1); @@ -260,11 +257,9 @@ int CmdEM410xSim(const char *Cmd) AppendGraph(0, clock, parity[2]); AppendGraph(0, clock, parity[3]); - /* stop bit */ - AppendGraph(0, clock, 0); - //} - - /* modulate that biatch */ + /* stop bit */ + AppendGraph(0, clock, 0); + //CmdManchesterMod("64"); /* booyah! */ diff --git a/client/scripting.c b/client/scripting.c index f0c56baf..cc59f995 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -268,8 +268,8 @@ static int l_crc16(lua_State *L) { size_t size; const char *p_str = luaL_checklstring(L, 1, &size); - - unsigned short retval = crc16_ccitt( p_str, size); + + uint16_t retval = crc16_ccitt( (uint8_t*) p_str, size); lua_pushinteger(L, (int) retval); return 1; } diff --git a/client/ui.c b/client/ui.c index d4758525..5111e295 100644 --- a/client/ui.c +++ b/client/ui.c @@ -79,7 +79,6 @@ void PrintAndLog(char *fmt, ...) vfprintf(logfile, fmt, argptr2); fprintf(logfile,"\n"); fflush(logfile); - fclose(logfile); // ICEMAN, this logfile is never closed?!? } va_end(argptr2); From 02306bac2dc44bd1de5422f9db127b231cde304f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 30 Nov 2014 19:16:28 +0100 Subject: [PATCH 43/78] ADD: Enio's intuative function for the command: "hw tune", where you plot the tuning-data :) ADD: added optional parameter to "hw tune" to show graf direct. Sample usage: "hw tune p" --- armsrc/appmain.c | 4 ++-- client/cmddata.c | 22 +++++++++++++++++++++- client/cmddata.h | 2 +- client/cmdhw.c | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 18c65e80..56467827 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -168,13 +168,13 @@ int AvgAdc(int ch) // was static - merlok void MeasureAntennaTuning(void) { - uint8_t *dest = (uint8_t *)BigBuf+FREE_BUFFER_OFFSET; + uint8_t *dest = (uint8_t *)BigBuf + FREE_BUFFER_OFFSET; int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0 int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV LED_B_ON(); DbpString("Measuring antenna characteristics, please wait..."); - memset(dest,0,sizeof(FREE_BUFFER_SIZE)); + memset(dest,0,FREE_BUFFER_SIZE); /* * Sweeps the useful LF range of the proxmark from diff --git a/client/cmddata.c b/client/cmddata.c index 9fa26721..b4752b1f 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -475,6 +475,25 @@ int CmdSamples(const char *Cmd) RepaintGraphWindow(); return 0; } +int CmdTuneSamples(const char *Cmd) +{ + int cnt = 0; + int n = 255; + uint8_t got[255] = {0x00}; + + PrintAndLog("Reading %d samples\n", n); + GetFromBigBuf(got,n,7256); // armsrc/apps.h: #define FREE_BUFFER_OFFSET 7256 + WaitForResponse(CMD_ACK,NULL); + for (int j = 0; j < n; j++) { + GraphBuffer[cnt++] = ((int)got[j]) - 128; + } + + PrintAndLog("Done! Divisor 89 is 134khz, 95 is 125khz.\n"); + GraphTraceLen = n; + RepaintGraphWindow(); + return 0; +} + int CmdLoad(const char *Cmd) { @@ -909,6 +928,7 @@ static command_t CommandTable[] = {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, {"dec", CmdDec, 1, "Decimate samples"}, {"detectclock", CmdDetectClockRate, 1, "Detect clock rate"}, + {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"}, {"grid", CmdGrid, 1, " -- overlay grid on graph window, use zero value to turn off either"}, {"hexsamples", CmdHexsamples, 0, " [] -- Dump big buffer as hex bytes"}, @@ -924,8 +944,8 @@ static command_t CommandTable[] = {"save", CmdSave, 1, " -- Save trace (from graph window)"}, {"scale", CmdScale, 1, " -- Set cursor display scale"}, {"threshold", CmdThreshold, 1, " -- Maximize/minimize every value in the graph window depending on threshold"}, + {"tune", CmdTuneSamples, 0, "Get hw tune samples for graph window"}, {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"}, - {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmddata.h b/client/cmddata.h index 716c9c39..8073c34c 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -40,5 +40,5 @@ int CmdScale(const char *Cmd); int CmdThreshold(const char *Cmd); int CmdDirectionalThreshold(const char *Cmd); int CmdZerocrossings(const char *Cmd); - +int CmdTuneSamples(const char *Cmd); #endif diff --git a/client/cmdhw.c b/client/cmdhw.c index 68e99276..28cd01ba 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -15,6 +15,7 @@ #include "ui.h" #include "proxmark3.h" #include "cmdparser.h" +#include "cmddata.h" #include "cmdhw.h" #include "cmdmain.h" @@ -392,6 +393,20 @@ int CmdTune(const char *Cmd) { UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING}; SendCommand(&c); + + char cmdp = param_getchar(Cmd, 0); + if (cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hw tune

"); + PrintAndLog(""); + PrintAndLog(" sample: hw tune"); + PrintAndLog(" hw tune p"); + return 0; + } + + if ( cmdp == 'p' || cmdp == 'P'){ + ShowGraphWindow(); + CmdTuneSamples(""); + } return 0; } From a501c82b196b614295a6e3bf7481da84affb0d8e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Dec 2014 20:33:21 +0100 Subject: [PATCH 44/78] Applied Holiman's fixes for iclass.c and CSNs Applied PwPiwi's new parity fix. Applied Marshmellw's fixes for FSKdemod (HID, IO) FIX: a potential bigbuffer fault given pwpiwi's change inside lfops.c CmdIOdemodFSK & CmdHIDdemodFSK FIX: change some "int" parameters to uint's. FIX: changed the lfops.c - DoAcquisition125k_internal to respect pwpiwi's definitions of FREE_BUFFER_OFFSET HEADS up: The ultralight functions hasn't been verified since pwpiwi's changes. --- armsrc/appmain.c | 27 +- armsrc/apps.h | 45 +-- armsrc/epa.c | 118 +++++-- armsrc/hitag2.c | 20 +- armsrc/iclass.c | 96 +++--- armsrc/iso14443.c | 3 +- armsrc/iso14443a.c | 620 +++++++++++++++++++++---------------- armsrc/iso14443a.h | 32 +- armsrc/iso15693.c | 4 +- armsrc/lfops.c | 359 +++++++++++++-------- armsrc/mifarecmd.c | 50 ++- armsrc/mifaredesfire.c | 22 +- armsrc/mifaresniff.c | 8 +- armsrc/mifaresniff.h | 2 +- armsrc/mifareutil.c | 250 ++++++++------- armsrc/mifareutil.h | 25 +- armsrc/util.c | 9 - armsrc/util.h | 2 - client/cmddata.c | 2 +- client/cmdhf14a.c | 164 +++++----- client/cmdhficlass.c | 39 ++- client/cmdhfmf.c | 25 +- client/cmdlf.c | 13 +- client/cmdlfem4x.c | 13 +- client/cmdlfhid.c | 15 +- client/cmdlfhitag.c | 28 +- client/cmdlfio.c | 14 +- client/cmdlft55xx.c | 20 +- client/cmdmain.c | 3 +- client/flash.c | 29 +- client/loclass/fileutils.c | 16 +- client/mifarehost.c | 13 +- client/mifarehost.h | 6 +- 33 files changed, 1140 insertions(+), 952 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 56467827..2ee234fb 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -37,7 +37,8 @@ // is the order in which they go out on the wire. //============================================================================= -uint8_t ToSend[512]; +#define TOSEND_BUFFER_SIZE (9*MAX_FRAME_SIZE + 1 + 1 + 2) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits +uint8_t ToSend[TOSEND_BUFFER_SIZE]; int ToSendMax; static int ToSendBit; struct common_area common_area __attribute__((section(".commonarea"))); @@ -68,7 +69,7 @@ void ToSendStuffBit(int b) ToSendBit++; - if(ToSendBit >= sizeof(ToSend)) { + if(ToSendMax >= sizeof(ToSend)) { ToSendBit = 0; DbpString("ToSendStuffBit overflowed!"); } @@ -648,18 +649,18 @@ void UsbPacketReceived(uint8_t *packet, int len) cmd_send(CMD_ACK,0,0,0,0,0); break; case CMD_HID_DEMOD_FSK: - CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag + CmdHIDdemodFSK(c->arg[0], 0, 0, 1); break; case CMD_HID_SIM_TAG: - CmdHIDsimTAG(c->arg[0], c->arg[1], 1); // Simulate HID tag by ID + CmdHIDsimTAG(c->arg[0], c->arg[1], 1); break; - case CMD_HID_CLONE_TAG: // Clone HID tag by ID to T55x7 + case CMD_HID_CLONE_TAG: CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]); break; case CMD_IO_DEMOD_FSK: - CmdIOdemodFSK(1, 0, 0, 1); // Demodulate IO tag + CmdIOdemodFSK(c->arg[0], 0, 0, 1); break; - case CMD_IO_CLONE_TAG: // Clone IO tag by ID to T55x7 + case CMD_IO_CLONE_TAG: CopyIOtoT55x7(c->arg[0], c->arg[1], c->d.asBytes[0]); break; case CMD_EM410X_WRITE_TAG: @@ -672,18 +673,16 @@ void UsbPacketReceived(uint8_t *packet, int len) WriteTItag(c->arg[0],c->arg[1],c->arg[2]); break; case CMD_SIMULATE_TAG_125K: - LED_A_ON(); SimulateTagLowFrequency(c->arg[0], c->arg[1], 0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); + //SimulateTagLowFrequencyA(c->arg[0], c->arg[1]); break; case CMD_LF_SIMULATE_BIDIR: SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]); break; - case CMD_INDALA_CLONE_TAG: // Clone Indala 64-bit tag by UID to T55x7 + case CMD_INDALA_CLONE_TAG: CopyIndala64toT55x7(c->arg[0], c->arg[1]); break; - case CMD_INDALA_CLONE_TAG_L: // Clone Indala 224-bit tag by UID to T55x7 + case CMD_INDALA_CLONE_TAG_L: CopyIndala224toT55x7(c->d.asDwords[0], c->d.asDwords[1], c->d.asDwords[2], c->d.asDwords[3], c->d.asDwords[4], c->d.asDwords[5], c->d.asDwords[6]); break; case CMD_T55XX_READ_BLOCK: @@ -692,10 +691,10 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_T55XX_WRITE_BLOCK: T55xxWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]); break; - case CMD_T55XX_READ_TRACE: // Clone HID tag by ID to T55x7 + case CMD_T55XX_READ_TRACE: T55xxReadTrace(); break; - case CMD_PCF7931_READ: // Read PCF7931 tag + case CMD_PCF7931_READ: ReadPCF7931(); cmd_send(CMD_ACK,0,0,0,0,0); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index c9616e5e..6725741f 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -32,23 +32,24 @@ // The large multi-purpose buffer, typically used to hold A/D samples, // maybe processed in some way. -//#define BIG_BUFF_SIZE 10000 // PM3 w. 256KB ram -#define BIG_BUFF_SIZE 10000 // PM3 w. 512KB ram +#define BIGBUF_SIZE 40000 +uint32_t BigBuf[BIGBUF_SIZE / sizeof(uint32_t)]; +#define TRACE_OFFSET 0 +#define TRACE_SIZE 3000 +#define RECV_CMD_OFFSET (TRACE_OFFSET + TRACE_SIZE) +#define MAX_FRAME_SIZE 256 +#define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 1)/ 8) +#define RECV_CMD_PAR_OFFSET (RECV_CMD_OFFSET + MAX_FRAME_SIZE) +#define RECV_RESP_OFFSET (RECV_CMD_PAR_OFFSET + MAX_PARITY_SIZE) +#define RECV_RESP_PAR_OFFSET (RECV_RESP_OFFSET + MAX_FRAME_SIZE) +#define CARD_MEMORY_OFFSET (RECV_RESP_PAR_OFFSET + MAX_PARITY_SIZE) +#define CARD_MEMORY_SIZE 4096 +#define DMA_BUFFER_OFFSET CARD_MEMORY_OFFSET +#define DMA_BUFFER_SIZE CARD_MEMORY_SIZE +#define FREE_BUFFER_OFFSET (CARD_MEMORY_OFFSET + CARD_MEMORY_SIZE) +#define FREE_BUFFER_SIZE (BIGBUF_SIZE - FREE_BUFFER_OFFSET - 1) -uint32_t BigBuf[BIG_BUFF_SIZE]; -// BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT -#define TRACE_OFFSET 0 -#define TRACE_SIZE 4096 -#define RECV_CMD_OFFSET 3032 -#define RECV_CMD_SIZE 64 -#define RECV_RES_OFFSET 3096 -#define RECV_RES_SIZE 64 -#define DMA_BUFFER_OFFSET 3160 -#define DMA_BUFFER_SIZE 4096 -#define FREE_BUFFER_OFFSET 7256 -#define FREE_BUFFER_SIZE 2744 - -//extern const uint8_t OddByteParity[256]; +extern const uint8_t OddByteParity[256]; extern uint8_t *trace; // = (uint8_t *) BigBuf; extern int traceLen; // = 0; extern int rsamples; // = 0; @@ -143,8 +144,10 @@ void ReadTItag(void); void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc); void AcquireTiType(void); void AcquireRawBitsTI(void); -void SimulateTagLowFrequency(int period, int gap, int ledcontrol); -void CmdHIDsimTAG(int hi, int lo, int ledcontrol); +void SimulateTagLowFrequency( uint16_t period, uint32_t gap, uint8_t ledcontrol); +void SimulateTagLowFrequencyA(int period, int gap); + +void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol); void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol); void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol); void CopyIOtoT55x7(uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an ioProx card to T5557/T5567 @@ -176,8 +179,8 @@ void RAMFUNC SnoopIso14443a(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 -bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t iSamples, uint32_t dwParity, bool readerToTag); -uint32_t GetParity(const uint8_t * pbtCmd, int iLen); +bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t len, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); +void GetParity(const uint8_t * pbtCmd, uint16_t len, uint8_t *parity); void iso14a_set_trigger(bool enable); void iso14a_clear_trace(); void iso14a_set_tracing(bool enable); @@ -193,7 +196,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); void MifareUReadBlock(uint8_t arg0,uint8_t *datain); void MifareUC_Auth1(uint8_t arg0, uint8_t *datain); void MifareUC_Auth2(uint32_t arg0, uint8_t *datain); -void MifareUReadCard(uint8_t arg0,int Pages,uint8_t *datain); +void MifareUReadCard(uint8_t arg0, int Pages, uint8_t *datain); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0,uint8_t *datain); diff --git a/armsrc/epa.c b/armsrc/epa.c index 69599dc9..a3c6669e 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -185,6 +185,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) || response_apdu[rapdu_length - 4] != 0x90 || response_apdu[rapdu_length - 3] != 0x00) { + Dbprintf("epa - no select cardaccess"); return -1; } @@ -196,6 +197,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) || response_apdu[rapdu_length - 4] != 0x90 || response_apdu[rapdu_length - 3] != 0x00) { + Dbprintf("epa - no read cardaccess"); return -1; } @@ -222,8 +224,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); -//UsbSendPacket((void *)ack, sizeof(UsbCommand)); + cmd_send(CMD_ACK,step,func_return,0,0,0); } //----------------------------------------------------------------------------- @@ -243,7 +244,7 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) */ // return value of a function - int func_return; + int func_return = 0; // // initialize ack with 0s // memset(ack->arg, 0, 12); @@ -251,13 +252,15 @@ 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; } // increase the timeout (at least some cards really do need this!) iso14a_set_timeout(0x0002FFFF); + Dbprintf("epa: Epic!"); // read the CardAccess file // this array will hold the CardAccess file @@ -265,10 +268,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 @@ -280,6 +286,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); @@ -301,8 +309,7 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) // save received information // ack->arg[1] = func_return; // memcpy(ack->d.asBytes, nonce, func_return); -// UsbSendPacket((void *)ack, sizeof(UsbCommand)); - cmd_send(CMD_ACK,0,func_return,0,nonce,func_return); + cmd_send(CMD_ACK,0,func_return,0,nonce,func_return); } //----------------------------------------------------------------------------- @@ -417,27 +424,88 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) int EPA_Setup() { // return code - int return_code = 0; + //int return_code = 0; + // card UID - uint8_t uid[10]; - // card select information - iso14a_card_select_t card_select_info; + //uint8_t uid[10] = {0x00}; + // 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) { - return 1; - } - - // send the PPS request - ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); - uint8_t pps_response[3]; - return_code = ReaderReceive(pps_response); - if (return_code != 3 || pps_response[0] != 0xD0) { - return return_code == 0 ? 2 : return_code; - } + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14a_set_timeout(10500); - return 0; + // card select information + byte_t cardbuf[USB_CMD_DATA_SIZE]; + memset(cardbuf,0,USB_CMD_DATA_SIZE); + iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; + + // select the card + // if (!iso14443a_select_card(uid, &card_info, NULL)) { + // Dbprintf("Epa: Can't select card"); + // return -1; + // } + + uint8_t wupa[] = { 0x26 }; // 0x26 - REQA 0x52 - WAKE-UP + uint8_t sel_all[] = { 0x93,0x20 }; + uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t rats[] = { 0xE0,0x81,0x00,0x00 }; // FSD=256, FSDI=8, CID=1 + + uint8_t *resp = ((uint8_t *)BigBuf) + RECV_RESP_OFFSET; + uint8_t *resp_par = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; + + byte_t uid_resp[4]; + size_t uid_resp_len = 4; + + uint8_t sak = 0x04; // cascade uid + int len; + + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field + ReaderTransmitBitsPar(wupa,7,0, NULL); + + // Receive the ATQA + if(!ReaderReceive(resp, resp_par)) return -1; + + // SELECT_ALL + ReaderTransmit(sel_all,sizeof(sel_all), NULL); + if (!ReaderReceive(resp, resp_par)) return -1; + + // uid response from tag + memcpy(uid_resp,resp,uid_resp_len); + + // Construct SELECT UID command + // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) + memcpy(sel_uid+2,uid_resp,4); // the UID + sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC + AppendCrc14443a(sel_uid,7); // calculate and add CRC + ReaderTransmit(sel_uid,sizeof(sel_uid), NULL); + + // Receive the SAK + if (!ReaderReceive(resp, resp_par)) return -1; + sak = resp[0]; + + // Request for answer to select + AppendCrc14443a(rats, 2); + ReaderTransmit(rats, sizeof(rats), NULL); + + if ( !(len = ReaderReceive(resp, resp_par) )) return -1; + + // populate the collected data. + memcpy( card->uid, uid_resp, uid_resp_len); + card->uidlen += uid_resp_len; + card->sak = sak; + card->ats_len = len; + memcpy(card->ats, resp, sizeof(card->ats)); + + + // send the PPS request + // ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); + // uint8_t pps_response[3]; + // uint8_t pps_response_par[1]; + // return_code = ReaderReceive(pps_response,pps_response_par); + // if (return_code != 3 || pps_response[0] != 0xD0) { + // return return_code == 0 ? 2 : return_code; + // } + + return -1; } \ No newline at end of file diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 7d6668eb..33cc3b7f 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -744,7 +744,7 @@ void SnoopHitag(uint32_t type) { // Set up eavesdropping mode, frequency divisor which will drive the FPGA // and analog mux selection. FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); @@ -968,7 +968,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { // Set up simulator mode, frequency divisor which will drive the FPGA // and analog mux selection. FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); @@ -987,21 +987,21 @@ 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, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on rising edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; - // Enable and reset counter - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - // Reset the received frame, frame count and timing info memset(rx,0x00,sizeof(rx)); frame_count = 0; response = 0; overflow = 0; + + // Enable and reset counter + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; while(!BUTTON_PRESS()) { // Watchdog hit @@ -1105,9 +1105,9 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); -// Dbprintf("frame received: %d",frame_count); -// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); -// DbpString("All done"); + + DbpString("Sim Stopped"); + } void ReaderHitag(hitag_function htf, hitag_data* htd) { diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 91a802ca..f53f3041 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -73,14 +73,13 @@ static struct { int nOutOfCnt; int OutOfCnt; int syncBit; - int parityBits; int samples; int highCnt; int swapper; int counter; int bitBuffer; int dropPosition; - uint8_t *output; + uint8_t *output; } Uart; static RAMFUNC int OutOfNDecoding(int bit) @@ -139,11 +138,8 @@ static RAMFUNC int OutOfNDecoding(int bit) if(Uart.byteCnt == 0) { // Its not straightforward to show single EOFs // So just leave it and do not return TRUE - Uart.output[Uart.byteCnt] = 0xf0; + Uart.output[0] = 0xf0; Uart.byteCnt++; - - // Calculate the parity bit for the client... - Uart.parityBits = 1; } else { return TRUE; @@ -225,12 +221,6 @@ static RAMFUNC int OutOfNDecoding(int bit) if(Uart.bitCnt == 8) { Uart.output[Uart.byteCnt] = (Uart.shiftReg & 0xff); Uart.byteCnt++; - - // Calculate the parity bit for the client... - Uart.parityBits <<= 1; - //Uart.parityBits ^= OddByteParity[(Uart.shiftReg & 0xff)]; - Uart.parityBits ^= oddparity(Uart.shiftReg & 0xff); - Uart.bitCnt = 0; Uart.shiftReg = 0; } @@ -249,12 +239,6 @@ static RAMFUNC int OutOfNDecoding(int bit) Uart.dropPosition--; Uart.output[Uart.byteCnt] = (Uart.dropPosition & 0xff); Uart.byteCnt++; - - // Calculate the parity bit for the client... - Uart.parityBits <<= 1; - //Uart.parityBits ^= OddByteParity[(Uart.dropPosition & 0xff)]; - Uart.parityBits ^= oddparity((Uart.dropPosition & 0xff)); - Uart.bitCnt = 0; Uart.shiftReg = 0; Uart.nOutOfCnt = 0; @@ -315,7 +299,6 @@ static RAMFUNC int OutOfNDecoding(int bit) Uart.state = STATE_START_OF_COMMUNICATION; Uart.bitCnt = 0; Uart.byteCnt = 0; - Uart.parityBits = 0; Uart.nOutOfCnt = 0; Uart.OutOfCnt = 4; // Start at 1/4, could switch to 1/256 Uart.dropPosition = 0; @@ -357,7 +340,6 @@ static struct { int bitCount; int posCount; int syncBit; - int parityBits; uint16_t shiftReg; int buffer; int buffer2; @@ -424,7 +406,6 @@ static RAMFUNC int ManchesterDecoding(int v) Demod.sub = SUB_FIRST_HALF; Demod.bitCount = 0; Demod.shiftReg = 0; - Demod.parityBits = 0; Demod.samples = 0; if(Demod.posCount) { //if(trigger) LED_A_OFF(); // Not useful in this case... @@ -488,9 +469,6 @@ static RAMFUNC int ManchesterDecoding(int v) if(Demod.state == DEMOD_SOF_COMPLETE) { Demod.output[Demod.len] = 0x0f; Demod.len++; - Demod.parityBits <<= 1; - //Demod.parityBits ^= OddByteParity[0x0f]; - Demod.parityBits ^= oddparity(0x0f); Demod.state = DEMOD_UNSYNCD; // error = 0x0f; return TRUE; @@ -571,11 +549,9 @@ static RAMFUNC int ManchesterDecoding(int v) // Tag response does not need to be a complete byte! if(Demod.len > 0 || Demod.bitCount > 0) { if(Demod.bitCount > 1) { // was > 0, do not interpret last closing bit, is part of EOF - Demod.shiftReg >>= (9 - Demod.bitCount); + Demod.shiftReg >>= (9 - Demod.bitCount); // rright align data Demod.output[Demod.len] = Demod.shiftReg & 0xff; Demod.len++; - // No parity bit, so just shift a 0 - Demod.parityBits <<= 1; } Demod.state = DEMOD_UNSYNCD; @@ -612,12 +588,6 @@ static RAMFUNC int ManchesterDecoding(int v) Demod.shiftReg >>= 1; Demod.output[Demod.len] = (Demod.shiftReg & 0xff); Demod.len++; - - // FOR ISO15639 PARITY NOT SEND OTA, JUST CALCULATE IT FOR THE CLIENT - Demod.parityBits <<= 1; - //Demod.parityBits ^= OddByteParity[(Demod.shiftReg & 0xff)]; - Demod.parityBits ^= oddparity((Demod.shiftReg & 0xff)); - Demod.bitCount = 0; Demod.shiftReg = 0; } @@ -674,7 +644,7 @@ void RAMFUNC SnoopIClass(void) // So 32 should be enough! uint8_t *readerToTagCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); // The response (tag -> reader) that we're receiving. - uint8_t *tagToReaderResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET); + uint8_t *tagToReaderResponse = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -774,10 +744,10 @@ void RAMFUNC SnoopIClass(void) //if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,TRUE)) break; //if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break; - if(tracing) - { - LogTrace(Uart.output,Uart.byteCnt, (GetCountSspClk()-time_0) << 4, Uart.parityBits,TRUE); - LogTrace(NULL, 0, (GetCountSspClk()-time_0) << 4, 0, TRUE); + if(tracing) { + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(Uart.output, Uart.byteCnt, parity); + LogTrace(Uart.output,Uart.byteCnt, (GetCountSspClk()-time_0) << 4, (GetCountSspClk()-time_0) << 4, parity, TRUE); } @@ -798,10 +768,10 @@ void RAMFUNC SnoopIClass(void) rsamples = samples - Demod.samples; LED_B_ON(); - if(tracing) - { - LogTrace(Demod.output,Demod.len, (GetCountSspClk()-time_0) << 4 , Demod.parityBits,FALSE); - LogTrace(NULL, 0, (GetCountSspClk()-time_0) << 4, 0, FALSE); + if(tracing) { + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(Demod.output, Demod.len, parity); + LogTrace(Demod.output, Demod.len, (GetCountSspClk()-time_0) << 4, (GetCountSspClk()-time_0) << 4, parity, FALSE); } @@ -996,7 +966,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain { uint8_t mac_responses[64] = { 0 }; - Dbprintf("Going into attack mode"); + Dbprintf("Going into attack mode, %d CSNS sent", numberOfCSNS); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time // in order to collect MAC's from the reader. This can later be used in an offlne-attack // in order to obtain the keys, as in the "dismantling iclass"-paper. @@ -1006,7 +976,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. memcpy(csn_crc, datain+(i*8), 8); - if(doIClassSimulation(csn_crc,1,mac_responses)) + if(doIClassSimulation(csn_crc,1,mac_responses+i*8)) { return; // Button pressed } @@ -1029,8 +999,6 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain */ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf) { - - // CSN followed by two CRC bytes uint8_t response2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t response3[] = { 0,0,0,0,0,0,0,0,0,0}; @@ -1081,7 +1049,7 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader // + 1720.. uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); - memset(receivedCmd, 0x44, RECV_CMD_SIZE); + memset(receivedCmd, 0x44, MAX_FRAME_SIZE); int len; // Prepare card messages @@ -1179,7 +1147,7 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader // 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[0], receivedCmd[1], receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5], receivedCmd[6], receivedCmd[7], receivedCmd[8]); if (reader_mac_buf != NULL) @@ -1221,14 +1189,13 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader } if (tracing) { - LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, Uart.parityBits,TRUE); - LogTrace(NULL,0, (r2t_time-time_0) << 4, 0,TRUE); + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(receivedCmd, len, parity); + LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, TRUE); if (respdata != NULL) { - LogTrace(respdata,respsize, (t2r_time-time_0) << 4,SwapBits(GetParity(respdata,respsize),respsize),FALSE); - LogTrace(NULL,0, (t2r_time-time_0) << 4,0,FALSE); - - + GetParity(respdata, respsize, parity); + LogTrace(respdata, respsize, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, FALSE); } if(!tracing) { DbpString("Trace full"); @@ -1236,7 +1203,7 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader } } - memset(receivedCmd, 0x44, RECV_CMD_SIZE); + memset(receivedCmd, 0x44, MAX_FRAME_SIZE); } //Dbprintf("%x", cmdsRecvd); @@ -1392,7 +1359,6 @@ void ReaderTransmitIClass(uint8_t* frame, int len) { int wait = 0; int samples = 0; - int par = 0; // This is tied to other size changes CodeIClassCommand(frame,len); @@ -1403,7 +1369,11 @@ void ReaderTransmitIClass(uint8_t* frame, int len) LED_A_ON(); // Store reader command in buffer - if (tracing) LogTrace(frame,len,rsamples,par,TRUE); + if (tracing) { + uint8_t par[MAX_PARITY_SIZE]; + GetParity(frame, len, par); + LogTrace(frame, len, rsamples, rsamples, par, TRUE); + } } //----------------------------------------------------------------------------- @@ -1459,7 +1429,11 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer) int samples = 0; if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return FALSE; rsamples += samples; - if (tracing) LogTrace(receivedAnswer,Demod.len,rsamples,Demod.parityBits,FALSE); + if (tracing){ + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(receivedAnswer, Demod.len, parity); + LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,FALSE); + } if(samples == 0) return FALSE; return Demod.len; } @@ -1499,7 +1473,7 @@ void ReaderIClass(uint8_t arg0) { uint8_t card_data[24]={0}; uint8_t last_csn[8]={0}; - uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + uint8_t *resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); int read_status= 0; bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; @@ -1590,7 +1564,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { int keyaccess; } memory; - uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + uint8_t* resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); setupIclassReader(); @@ -1709,7 +1683,7 @@ void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, uint8_ uint16_t crc = 0; - uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + uint8_t* resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); // Reset trace buffer memset(trace, 0x44, RECV_CMD_OFFSET); diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c index bc7b9b16..28ab54d6 100644 --- a/armsrc/iso14443.c +++ b/armsrc/iso14443.c @@ -401,8 +401,7 @@ void SimulateIso14443Tag(void) // Modulate BPSK // Signal field is off with the appropriate LED LED_D_OFF(); - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); AT91C_BASE_SSC->SSC_THR = 0xff; FpgaSetupSsc(); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index fcd51d63..aed6a1fe 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -103,9 +103,9 @@ uint16_t FpgaSendQueueDelay; //variables used for timing purposes: //these are in ssp_clk cycles: -uint32_t NextTransferTime; -uint32_t LastTimeProxToAirStart; -uint32_t LastProxToAirDuration; +static uint32_t NextTransferTime; +static uint32_t LastTimeProxToAirStart; +static uint32_t LastProxToAirDuration; @@ -124,8 +124,6 @@ uint32_t LastProxToAirDuration; #define SEC_Y 0x00 #define SEC_Z 0xc0 -//replaced large parity table with small parity generation function - saves flash code -/* const uint8_t OddByteParity[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, @@ -144,7 +142,6 @@ const uint8_t OddByteParity[256] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; -*/ void iso14a_set_trigger(bool enable) { trigger = enable; @@ -167,25 +164,33 @@ void iso14a_set_timeout(uint32_t timeout) { // Generate the parity value for a byte sequence // //----------------------------------------------------------------------------- -/* byte_t oddparity (const byte_t bt) { return OddByteParity[bt]; } -*/ -uint32_t GetParity(const uint8_t * pbtCmd, int iLen) +void GetParity(const uint8_t * pbtCmd, uint16_t iLen, uint8_t *par) { - int i; - uint32_t dwPar = 0; + uint16_t paritybit_cnt = 0; + uint16_t paritybyte_cnt = 0; + uint8_t parityBits = 0; - // Generate the parity bits - for (i = 0; i < iLen; i++) { - // and save them to a 32Bit word - //dwPar |= ((OddByteParity[pbtCmd[i]]) << i); - dwPar |= (oddparity(pbtCmd[i]) << i); + for (uint16_t i = 0; i < iLen; i++) { + // Generate the parity bits + parityBits |= ((OddByteParity[pbtCmd[i]]) << (7-paritybit_cnt)); + if (paritybit_cnt == 7) { + par[paritybyte_cnt] = parityBits; // save 8 Bits parity + parityBits = 0; // and advance to next Parity Byte + paritybyte_cnt++; + paritybit_cnt = 0; + } else { + paritybit_cnt++; + } } - return dwPar; + + // save remaining parity bits + par[paritybyte_cnt] = parityBits; + } void AppendCrc14443a(uint8_t* data, int len) @@ -194,33 +199,57 @@ void AppendCrc14443a(uint8_t* data, int len) } // The function LogTrace() is also used by the iClass implementation in iClass.c -bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t timestamp, uint32_t dwParity, bool readerToTag) +bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) { if (!tracing) return FALSE; + + uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity + uint16_t duration = timestamp_end - timestamp_start; + // Return when trace is full - if (traceLen + sizeof(timestamp) + sizeof(dwParity) + iLen >= TRACE_SIZE) { + if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= TRACE_SIZE) { tracing = FALSE; // don't trace any more return FALSE; } - // Trace the random, i'm curious - trace[traceLen++] = ((timestamp >> 0) & 0xff); - trace[traceLen++] = ((timestamp >> 8) & 0xff); - trace[traceLen++] = ((timestamp >> 16) & 0xff); - trace[traceLen++] = ((timestamp >> 24) & 0xff); + // Traceformat: + // 32 bits timestamp (little endian) + // 16 bits duration (little endian) + // 16 bits data length (little endian, Highest Bit used as readerToTag flag) + // y Bytes data + // x Bytes parity (one byte per 8 bytes data) + // timestamp (start) + trace[traceLen++] = ((timestamp_start >> 0) & 0xff); + trace[traceLen++] = ((timestamp_start >> 8) & 0xff); + trace[traceLen++] = ((timestamp_start >> 16) & 0xff); + trace[traceLen++] = ((timestamp_start >> 24) & 0xff); + + // duration + trace[traceLen++] = ((duration >> 0) & 0xff); + trace[traceLen++] = ((duration >> 8) & 0xff); + + // data length + trace[traceLen++] = ((iLen >> 0) & 0xff); + trace[traceLen++] = ((iLen >> 8) & 0xff); + + // readerToTag flag if (!readerToTag) { trace[traceLen - 1] |= 0x80; - } - trace[traceLen++] = ((dwParity >> 0) & 0xff); - trace[traceLen++] = ((dwParity >> 8) & 0xff); - trace[traceLen++] = ((dwParity >> 16) & 0xff); - trace[traceLen++] = ((dwParity >> 24) & 0xff); - trace[traceLen++] = iLen; + } + + // data bytes if (btBytes != NULL && iLen != 0) { memcpy(trace + traceLen, btBytes, iLen); } - traceLen += iLen; + traceLen += iLen; + + // parity bytes + if (parity != NULL && iLen != 0) { + memcpy(trace + traceLen, parity, num_paritybytes); + } + traceLen += num_paritybytes; + return TRUE; } @@ -256,14 +285,21 @@ void UartReset() Uart.state = STATE_UNSYNCD; Uart.bitCount = 0; Uart.len = 0; // number of decoded data bytes + Uart.parityLen = 0; // number of decoded parity bytes Uart.shiftReg = 0; // shiftreg to hold decoded data bits - Uart.parityBits = 0; // + Uart.parityBits = 0; // holds 8 parity bits Uart.twoBits = 0x0000; // buffer for 2 Bits Uart.highCnt = 0; Uart.startTime = 0; Uart.endTime = 0; } +void UartInit(uint8_t *data, uint8_t *parity) +{ + Uart.output = data; + Uart.parity = parity; + UartReset(); +} // use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) @@ -271,14 +307,14 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.twoBits = (Uart.twoBits << 8) | bit; - if (Uart.state == STATE_UNSYNCD) { // not yet synced + if (Uart.state == STATE_UNSYNCD) { // not yet synced + if (Uart.highCnt < 7) { // wait for a stable unmodulated signal - if (Uart.twoBits == 0xffff) { + if (Uart.twoBits == 0xffff) Uart.highCnt++; - } else { + else Uart.highCnt = 0; - } - } else { + } else { Uart.syncBit = 0xFFFF; // not set // look for 00xx1111 (the start bit) if ((Uart.twoBits & 0x6780) == 0x0780) Uart.syncBit = 7; @@ -318,6 +354,10 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; + if((Uart.len & 0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + Uart.parityBits = 0; + } } } } @@ -333,17 +373,28 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; + if ((Uart.len & 0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + Uart.parityBits = 0; + } } } else { // no modulation in both halves - Sequence Y if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication Uart.state = STATE_UNSYNCD; - if(Uart.len == 0 && Uart.bitCount > 0) { // if we decoded some bits - Uart.shiftReg >>= (9 - Uart.bitCount); // add them to the output - Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // no parity bit - add "0" - Uart.bitCount--; // last "0" was part of the EOC sequence - } + Uart.bitCount--; // last "0" was part of EOC sequence + Uart.shiftReg <<= 1; // drop it + if(Uart.bitCount > 0) { // if we decoded some bits + Uart.shiftReg >>= (9 - Uart.bitCount); // right align them + Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); // add last byte to the output + Uart.parityBits <<= 1; // add a (void) parity bit + Uart.parityBits <<= (8 - (Uart.len & 0x0007)); // left align parity bits + Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store it return TRUE; + } else if (Uart.len & 0x0007) { // there are some parity bits to store + Uart.parityBits <<= (8 - (Uart.len & 0x0007)); // left align remaining parity bits + Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them + return TRUE; // we are finished with decoding the raw data sequence + } } if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC UartReset(); @@ -358,12 +409,16 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; + if ((Uart.len & 0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + Uart.parityBits = 0; + } } } } } - } + } return FALSE; // not finished yet, need more data } @@ -402,6 +457,7 @@ void DemodReset() { Demod.state = DEMOD_UNSYNCD; Demod.len = 0; // number of decoded data bytes + Demod.parityLen = 0; Demod.shiftReg = 0; // shiftreg to hold decoded data bits Demod.parityBits = 0; // Demod.collisionPos = 0; // Position of collision bit @@ -411,6 +467,13 @@ void DemodReset() Demod.endTime = 0; } +void DemodInit(uint8_t *data, uint8_t *parity) +{ + Demod.output = data; + Demod.parity = parity; + DemodReset(); +} + // use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time) { @@ -459,6 +522,10 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; + if((Demod.len & 0x0007) == 0) { // every 8 data bytes + Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits + Demod.parityBits = 0; + } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1) - 4; } else { // no modulation in first half @@ -471,17 +538,24 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; + if ((Demod.len & 0x0007) == 0) { // every 8 data bytes + Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits1 + Demod.parityBits = 0; + } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1); } else { // no modulation in both halves - End of communication - if (Demod.len > 0 || Demod.bitCount > 0) { // received something - if(Demod.bitCount > 0) { // if we decoded bits - Demod.shiftReg >>= (9 - Demod.bitCount); // add the remaining decoded bits to the output - Demod.output[Demod.len++] = Demod.shiftReg & 0xff; - // No parity bit, so just shift a 0 - Demod.parityBits <<= 1; - } - return TRUE; // we are finished with decoding the raw data sequence + if(Demod.bitCount > 0) { // there are some remaining data bits + Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits + Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output + Demod.parityBits <<= 1; // add a (void) parity bit + Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits + Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + return TRUE; + } else if (Demod.len & 0x0007) { // there are some parity bits to store + Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits + Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + return TRUE; // we are finished with decoding the raw data sequence } else { // nothing received. Start over DemodReset(); } @@ -522,10 +596,13 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // The command (reader -> tag) that we're receiving. // The length of a received command will in most cases be no more than 18 bytes. // So 32 should be enough! - uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); + uint8_t *receivedCmd = ((uint8_t *)BigBuf) + RECV_CMD_OFFSET; + uint8_t *receivedCmdPar = ((uint8_t *)BigBuf) + RECV_CMD_PAR_OFFSET; + // The response (tag -> reader) that we're receiving. - uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET); - + uint8_t *receivedResponse = ((uint8_t *)BigBuf) + RECV_RESP_OFFSET; + uint8_t *receivedResponsePar = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; + // 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; @@ -542,10 +619,10 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); // Set up the demodulator for tag -> reader responses. - Demod.output = receivedResponse; + DemodInit(receivedResponse, receivedResponsePar); // Set up the demodulator for the reader -> tag commands - Uart.output = receivedCmd; + UartInit(receivedCmd, receivedCmdPar); // Setup and start DMA. FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); @@ -603,8 +680,12 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) triggered = TRUE; if(triggered) { - if (!LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, Uart.parityBits, TRUE)) break; - if (!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break; + if (!LogTrace(receivedCmd, + Uart.len, + Uart.startTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, + Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, + Uart.parity, + TRUE)) break; } /* And ready to receive another command. */ UartReset(); @@ -621,8 +702,12 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { if(ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { LED_B_ON(); - if (!LogTrace(receivedResponse, Demod.len, Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, Demod.parityBits, FALSE)) break; - if (!LogTrace(NULL, 0, Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, 0, FALSE)) break; + if (!LogTrace(receivedResponse, + Demod.len, + Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, + Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, + Demod.parity, + FALSE)) break; if ((!triggered) && (param & 0x01)) triggered = TRUE; @@ -653,10 +738,8 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { //----------------------------------------------------------------------------- // Prepare tag messages //----------------------------------------------------------------------------- -static void CodeIso14443aAsTagPar(const uint8_t *cmd, int len, uint32_t dwParity) +static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity) { - int i; - ToSendReset(); // Correction bit, might be removed when not needed @@ -673,12 +756,11 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, int len, uint32_t dwParity ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; - for(i = 0; i < len; i++) { - int j; + for( uint16_t i = 0; i < len; i++) { uint8_t b = cmd[i]; // Data bits - for(j = 0; j < 8; j++) { + for(uint16_t j = 0; j < 8; j++) { if(b & 1) { ToSend[++ToSendMax] = SEC_D; } else { @@ -688,8 +770,7 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, int len, uint32_t dwParity } // Get the parity bit - //if ((dwParity >> i) & 0x01) { - if (oddparity(cmd[i]) & 0x01) { + if (parity[i>>3] & (0x80>>(i&0x0007))) { ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; } else { @@ -705,8 +786,12 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, int len, uint32_t dwParity ToSendMax++; } -static void CodeIso14443aAsTag(const uint8_t *cmd, int len){ - CodeIso14443aAsTagPar(cmd, len, GetParity(cmd, len)); +static void CodeIso14443aAsTag(const uint8_t *cmd, uint16_t len) +{ + uint8_t par[MAX_PARITY_SIZE]; + + GetParity(cmd, len, par); + CodeIso14443aAsTagPar(cmd, len, par); } @@ -753,7 +838,7 @@ static void Code4bitAnswerAsTag(uint8_t cmd) // Stop when button is pressed // Or return TRUE when command is captured //----------------------------------------------------------------------------- -static int GetIso14443aCommandFromReader(uint8_t *received, int *len, int maxLen) +static int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len) { // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen // only, since we are receiving, not transmitting). @@ -762,8 +847,7 @@ static int GetIso14443aCommandFromReader(uint8_t *received, int *len, int maxLen FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); // Now run a `software UART' on the stream of incoming samples. - UartReset(); - Uart.output = received; + UartInit(received, parity); // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -783,16 +867,15 @@ static int GetIso14443aCommandFromReader(uint8_t *received, int *len, int maxLen } } -static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, bool correctionNeeded); +static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen, bool correctionNeeded); int EmSend4bitEx(uint8_t resp, bool correctionNeeded); int EmSend4bit(uint8_t resp); -int EmSendCmdExPar(uint8_t *resp, int respLen, bool correctionNeeded, uint32_t par); -int EmSendCmdExPar(uint8_t *resp, int respLen, bool correctionNeeded, uint32_t par); -int EmSendCmdEx(uint8_t *resp, int respLen, bool correctionNeeded); -int EmSendCmd(uint8_t *resp, int respLen); -int EmSendCmdPar(uint8_t *resp, int respLen, uint32_t par); -bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint32_t reader_Parity, - uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint32_t tag_Parity); +int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, bool correctionNeeded, uint8_t *par); +int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool correctionNeeded); +int EmSendCmd(uint8_t *resp, uint16_t respLen); +int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par); +bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity, + uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity); static uint8_t* free_buffer_pointer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); @@ -845,7 +928,7 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info) { response_info->modulation = free_buffer_pointer; // Determine the maximum size we can use from our buffer - size_t max_buffer_size = (((uint8_t *)BigBuf)+FREE_BUFFER_OFFSET+FREE_BUFFER_SIZE)-free_buffer_pointer; + size_t max_buffer_size = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + FREE_BUFFER_SIZE) - free_buffer_pointer; // Forward the prepare tag modulation function to the inner function if (prepare_tag_modulation(response_info,max_buffer_size)) { @@ -944,7 +1027,11 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce - uint8_t response6[] = { 0x04, 0x58, 0x00, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS + 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 + // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) + // TC(1) = 0x02: CID supported, NAD not supported ComputeCrc14443(CRC_14443_A, response6, 4, &response6[4], &response6[5]); #define TAG_RESPONSE_COUNT 7 @@ -980,7 +1067,6 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) prepare_allocated_tag_modulation(&responses[i]); } - uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); int len = 0; // To control where we are in the protocol @@ -995,6 +1081,10 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) // We need to listen to the high-frequency, peak-detected path. iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); + // buffers used on software Uart: + uint8_t *receivedCmd = ((uint8_t *)BigBuf) + RECV_CMD_OFFSET; + uint8_t *receivedCmdPar = ((uint8_t *)BigBuf) + RECV_CMD_PAR_OFFSET; + cmdsRecvd = 0; tag_response_info_t* p_response; @@ -1002,14 +1092,13 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) for(;;) { // Clean receive command buffer - if(!GetIso14443aCommandFromReader(receivedCmd, &len, RECV_CMD_SIZE)) { + if(!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { DbpString("Button press"); - break; + break; } p_response = NULL; - // doob - added loads of debug strings so we can see what the reader is saying to us during the sim as hi14alist is not populated // Okay, look at the command now. lastorder = order; if(receivedCmd[0] == 0x26) { // Received a REQUEST @@ -1018,22 +1107,21 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) p_response = &responses[0]; order = 6; } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // Received request for UID (cascade 1) p_response = &responses[1]; order = 2; - } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2) + } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2) p_response = &responses[2]; order = 20; } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) { // Received a SELECT (cascade 1) p_response = &responses[3]; order = 3; } 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[0]),16,false); + 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; } else if(receivedCmd[0] == 0x50) { // Received a HALT -// DbpString("Reader requested we HALT!:"); + if (tracing) { - LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); } p_response = NULL; } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) { // Received an authentication request @@ -1045,10 +1133,9 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) } else { p_response = &responses[6]; order = 70; } - } else if (order == 7 && len == 8) { // Received authentication request + } else if (order == 7 && len == 8) { // Received {nr] and {ar} (part of authentication) if (tracing) { - LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); } uint32_t nr = bytes_to_num(receivedCmd,4); uint32_t ar = bytes_to_num(receivedCmd+4,4); @@ -1092,8 +1179,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) default: { // Never seen this command before if (tracing) { - LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); } Dbprintf("Received unknown command (len=%d):",len); Dbhexdump(len,receivedCmd,false); @@ -1113,8 +1199,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) if (prepare_tag_modulation(&dynamic_response_info,DYNAMIC_MODULATION_BUFFER_SIZE) == false) { Dbprintf("Error preparing tag response"); if (tracing) { - LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); } break; } @@ -1137,16 +1222,19 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) if (p_response != NULL) { EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n, receivedCmd[0] == 0x52); // do the tracing for the previous reader request and this tag answer: + uint8_t par[MAX_PARITY_SIZE]; + GetParity(p_response->response, p_response->response_n, par); + EmLogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.parityBits, + Uart.parity, p_response->response, p_response->response_n, LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, (LastTimeProxToAirStart + p_response->ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, - SwapBits(GetParity(p_response->response, p_response->response_n), p_response->response_n)); + par); } if (!tracing) { @@ -1192,7 +1280,7 @@ void PrepareDelayedTransfer(uint16_t delay) // if == 0: transfer immediately and return time of transfer // if != 0: delay transfer until time specified //------------------------------------------------------------------------------------- -static void TransmitFor14443a(const uint8_t *cmd, int len, uint32_t *timing) +static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) { FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); @@ -1235,7 +1323,7 @@ static void TransmitFor14443a(const uint8_t *cmd, int len, uint32_t *timing) //----------------------------------------------------------------------------- // Prepare reader command (in bits, support short frames) to send to FPGA //----------------------------------------------------------------------------- -void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, int bits, uint32_t dwParity) +void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, uint16_t bits, const uint8_t *parity) { int i, j; int last; @@ -1275,10 +1363,10 @@ void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, int bits, uint32_t dwPari b >>= 1; } - // Only transmit (last) parity bit if we transmitted a complete byte + // Only transmit parity bit if we transmitted a complete byte if (j == 8) { // Get the parity bit - if ((dwParity >> i) & 0x01) { + if (parity[i>>3] & (0x80 >> (i&0x0007))) { // Sequence X ToSend[++ToSendMax] = SEC_X; LastProxToAirDuration = 8 * (ToSendMax+1) - 2; @@ -1316,9 +1404,9 @@ void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, int bits, uint32_t dwPari //----------------------------------------------------------------------------- // Prepare reader command to send to FPGA //----------------------------------------------------------------------------- -void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) +void CodeIso14443aAsReaderPar(const uint8_t * cmd, uint16_t len, const uint8_t *parity) { - CodeIso14443aBitsAsReaderPar(cmd,len*8,dwParity); + CodeIso14443aBitsAsReaderPar(cmd, len*8, parity); } //----------------------------------------------------------------------------- @@ -1326,7 +1414,7 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) // Stop when button is pressed (return 1) or field was gone (return 2) // Or return 0 when command is captured //----------------------------------------------------------------------------- -static int EmGetCmd(uint8_t *received, int *len) +static int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity) { *len = 0; @@ -1351,8 +1439,7 @@ static int EmGetCmd(uint8_t *received, int *len) AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; // Now run a 'software UART' on the stream of incoming samples. - UartReset(); - Uart.output = received; + UartInit(received, parity); // Clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -1393,7 +1480,7 @@ static int EmGetCmd(uint8_t *received, int *len) } -static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, bool correctionNeeded) +static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen, bool correctionNeeded) { uint8_t b; uint16_t i = 0; @@ -1460,16 +1547,18 @@ int EmSend4bitEx(uint8_t resp, bool correctionNeeded){ Code4bitAnswerAsTag(resp); int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded); // do the tracing for the previous reader request and this tag answer: + uint8_t par[1]; + GetParity(&resp, 1, par); EmLogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.parityBits, + Uart.parity, &resp, 1, LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, - SwapBits(GetParity(&resp, 1), 1)); + par); return res; } @@ -1477,7 +1566,7 @@ int EmSend4bit(uint8_t resp){ return EmSend4bitEx(resp, false); } -int EmSendCmdExPar(uint8_t *resp, int respLen, bool correctionNeeded, uint32_t par){ +int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, bool correctionNeeded, uint8_t *par){ CodeIso14443aAsTagPar(resp, respLen, par); int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded); // do the tracing for the previous reader request and this tag answer: @@ -1485,51 +1574,48 @@ int EmSendCmdExPar(uint8_t *resp, int respLen, bool correctionNeeded, uint32_t p Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.parityBits, + Uart.parity, resp, respLen, LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, - SwapBits(GetParity(resp, respLen), respLen)); + par); return res; } -int EmSendCmdEx(uint8_t *resp, int respLen, bool correctionNeeded){ - return EmSendCmdExPar(resp, respLen, correctionNeeded, GetParity(resp, respLen)); +int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool correctionNeeded){ + uint8_t par[MAX_PARITY_SIZE]; + GetParity(resp, respLen, par); + return EmSendCmdExPar(resp, respLen, correctionNeeded, par); } - -int EmSendCmd(uint8_t *resp, int respLen){ - return EmSendCmdExPar(resp, respLen, false, GetParity(resp, respLen)); -} - -int EmSendCmdPar(uint8_t *resp, int respLen, uint32_t par){ + +int EmSendCmd(uint8_t *resp, uint16_t respLen){ + uint8_t par[MAX_PARITY_SIZE]; + GetParity(resp, respLen, par); return EmSendCmdExPar(resp, respLen, false, par); } -bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint32_t reader_Parity, - uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint32_t tag_Parity) +int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ + return EmSendCmdExPar(resp, respLen, false, par); +} + +bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity, + uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity) { - if (tracing) { - // we cannot exactly measure the end and start of a received command from reader. However we know that the delay from - // end of the received command to start of the tag's (simulated by us) answer is n*128+20 or n*128+84 resp. - // with n >= 9. The start of the tags answer can be measured and therefore the end of the received command be calculated: - uint16_t reader_modlen = reader_EndTime - reader_StartTime; - uint16_t approx_fdt = tag_StartTime - reader_EndTime; - uint16_t exact_fdt = (approx_fdt - 20 + 32)/64 * 64 + 20; - reader_EndTime = tag_StartTime - exact_fdt; - reader_StartTime = reader_EndTime - reader_modlen; - if (!LogTrace(reader_data, reader_len, reader_StartTime, reader_Parity, TRUE)) { - return FALSE; - } else if (!LogTrace(NULL, 0, reader_EndTime, 0, TRUE)) { - return FALSE; - } else if (!LogTrace(tag_data, tag_len, tag_StartTime, tag_Parity, FALSE)) { - return FALSE; - } else { - return (!LogTrace(NULL, 0, tag_EndTime, 0, FALSE)); - } - } else { - return TRUE; - } + if (!tracing) return true; + + // we cannot exactly measure the end and start of a received command from reader. However we know that the delay from + // end of the received command to start of the tag's (simulated by us) answer is n*128+20 or n*128+84 resp. + // with n >= 9. The start of the tags answer can be measured and therefore the end of the received command be calculated: + uint16_t reader_modlen = reader_EndTime - reader_StartTime; + uint16_t approx_fdt = tag_StartTime - reader_EndTime; + uint16_t exact_fdt = (approx_fdt - 20 + 32)/64 * 64 + 20; + reader_EndTime = tag_StartTime - exact_fdt; + reader_StartTime = reader_EndTime - reader_modlen; + if (!LogTrace(reader_data, reader_len, reader_StartTime, reader_EndTime, reader_Parity, TRUE)) { + return FALSE; + } else + return(!LogTrace(tag_data, tag_len, tag_StartTime, tag_EndTime, tag_Parity, FALSE)); } //----------------------------------------------------------------------------- @@ -1537,7 +1623,7 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start // If a response is captured return TRUE // If it takes too long return FALSE //----------------------------------------------------------------------------- -static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint16_t offset, int maxLen) +static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) { uint16_t c; @@ -1548,9 +1634,8 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint16_t offset, FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); // Now get the answer from the card - DemodReset(); - Demod.output = receivedResponse; - + DemodInit(receivedResponse, receivedResponsePar); + // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -1563,17 +1648,16 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint16_t offset, if(ManchesterDecoding(b, offset, 0)) { NextTransferTime = MAX(NextTransferTime, Demod.endTime - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/16 + FRAME_DELAY_TIME_PICC_TO_PCD); return TRUE; - } else if(c++ > iso14a_timeout) { + } else if (c++ > iso14a_timeout) { return FALSE; } } } } -void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par, uint32_t *timing) +void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing) { - - CodeIso14443aBitsAsReaderPar(frame,bits,par); + CodeIso14443aBitsAsReaderPar(frame, bits, par); // Send command to tag TransmitFor14443a(ToSend, ToSendMax, timing); @@ -1582,51 +1666,47 @@ void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par, uint32_t *tim // Log reader command in trace buffer if (tracing) { - LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, par, TRUE); - LogTrace(NULL, 0, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, 0, TRUE); + LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, TRUE); } } -void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par, uint32_t *timing) +void ReaderTransmitPar(uint8_t* frame, uint16_t len, uint8_t *par, uint32_t *timing) { - ReaderTransmitBitsPar(frame,len*8,par, timing); + ReaderTransmitBitsPar(frame, len*8, par, timing); } -void ReaderTransmitBits(uint8_t* frame, int len, uint32_t *timing) +void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing) { - // Generate parity and redirect - ReaderTransmitBitsPar(frame,len,GetParity(frame,len/8), timing); + // Generate parity and redirect + uint8_t par[MAX_PARITY_SIZE]; + GetParity(frame, len/8, par); + ReaderTransmitBitsPar(frame, len, par, timing); } -void ReaderTransmit(uint8_t* frame, int len, uint32_t *timing) +void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing) { - // Generate parity and redirect - ReaderTransmitBitsPar(frame,len*8,GetParity(frame,len), timing); + // Generate parity and redirect + uint8_t par[MAX_PARITY_SIZE]; + GetParity(frame, len, par); + ReaderTransmitBitsPar(frame, len*8, par, timing); } -int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset) +int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t *parity) { - if (!GetIso14443aAnswerFromTag(receivedAnswer,offset,160)) return FALSE; + if (!GetIso14443aAnswerFromTag(receivedAnswer,parity,offset)) return FALSE; if (tracing) { - LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.parityBits, FALSE); - LogTrace(NULL, 0, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, 0, FALSE); + LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, FALSE); } return Demod.len; } -int ReaderReceive(uint8_t* receivedAnswer) +int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) { - return ReaderReceiveOffset(receivedAnswer, 0); -} + if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, 0)) return FALSE; -int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr) -{ - if (!GetIso14443aAnswerFromTag(receivedAnswer,0,160)) return FALSE; if (tracing) { - LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.parityBits, FALSE); - LogTrace(NULL, 0, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, 0, FALSE); + LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, FALSE); } - *parptr = Demod.parityBits; return Demod.len; } @@ -1634,23 +1714,29 @@ int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr) * fills the uid pointer unless NULL * fills resp_data unless NULL */ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { - uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP - uint8_t sel_all[] = { 0x93,0x20 }; - uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 - uint8_t* resp = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes - byte_t uid_resp[4]; - size_t uid_resp_len; + uint8_t halt[] = { 0x50 }; // HALT + uint8_t wupa[] = { 0x52 }; // WAKE-UP + //uint8_t reqa[] = { 0x26 }; // REQUEST A + uint8_t sel_all[] = { 0x93,0x20 }; + uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 + uint8_t *resp = ((uint8_t *)BigBuf) + RECV_RESP_OFFSET; + uint8_t *resp_par = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; + + byte_t uid_resp[4]; + size_t uid_resp_len; uint8_t sak = 0x04; // cascade uid int cascade_level = 0; int len; - + + ReaderTransmit(halt,sizeof(halt), NULL); + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitBitsPar(wupa,7,0, NULL); + ReaderTransmitBitsPar(wupa,7,0, NULL); // Receive the ATQA - if(!ReaderReceive(resp)) return 0; + if(!ReaderReceive(resp, resp_par)) return 0; // Dbprintf("atqa: %02x %02x",resp[0],resp[1]); if(p_hi14a_card) { @@ -1673,7 +1759,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u // SELECT_ALL ReaderTransmit(sel_all,sizeof(sel_all), NULL); - if (!ReaderReceive(resp)) return 0; + if (!ReaderReceive(resp, resp_par)) return 0; if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit memset(uid_resp, 0, 4); @@ -1695,7 +1781,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u } collision_answer_offset = uid_resp_bits%8; ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL); - if (!ReaderReceiveOffset(resp, collision_answer_offset)) return 0; + if (!ReaderReceiveOffset(resp, collision_answer_offset,resp_par)) return 0; } // finally, add the last bits and BCC of the UID for (uint16_t i = collision_answer_offset; i < (Demod.len-1)*8; i++, uid_resp_bits++) { @@ -1722,23 +1808,25 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u ReaderTransmit(sel_uid,sizeof(sel_uid), NULL); // Receive the SAK - if (!ReaderReceive(resp)) return 0; + if (!ReaderReceive(resp, resp_par)) return 0; sak = resp[0]; //Dbprintf("SAK: %02x",resp[0]); // Test if more parts of the uid are comming if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { - // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: - // http://www.nxp.com/documents/application_note/AN10927.pdf - // This was earlier: - //memcpy(uid_resp, uid_resp + 1, 3); - // But memcpy should not be used for overlapping arrays, - // and memmove appears to not be available in the arm build. - // So this has been replaced with a for-loop: - for(int xx = 0; xx < 3; xx++) - uid_resp[xx] = uid_resp[xx+1]; - uid_resp_len = 3; + // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: + // http://www.nxp.com/documents/application_note/AN10927.pdf + // This was earlier: + //memcpy(uid_resp, uid_resp + 1, 3); + // But memcpy should not be used for overlapping arrays, + // and memmove appears to not be available in the arm build. + // Therefore: + uid_resp[0] = uid_resp[1]; + uid_resp[1] = uid_resp[2]; + uid_resp[2] = uid_resp[3]; + + uid_resp_len = 3; } if(uid_ptr) { @@ -1764,7 +1852,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); - if (!(len = ReaderReceive(resp))) return 0; + if (!(len = ReaderReceive(resp,resp_par))) return 0; if(p_hi14a_card) { memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); @@ -1800,7 +1888,8 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { iso14a_set_timeout(1050); // 10ms default 10*105 = } -int iso14_apdu(uint8_t * cmd, size_t cmd_len, void * data) { +int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) { + uint8_t parity[MAX_PARITY_SIZE]; uint8_t real_cmd[cmd_len+4]; real_cmd[0] = 0x0a; //I-Block // put block number into the PCB @@ -1810,7 +1899,7 @@ int iso14_apdu(uint8_t * cmd, size_t cmd_len, void * data) { AppendCrc14443a(real_cmd,cmd_len+2); ReaderTransmit(real_cmd, cmd_len+4, NULL); - size_t len = ReaderReceive(data); + size_t len = ReaderReceive(data, parity); uint8_t * data_bytes = (uint8_t *) data; if (!len) return 0; //DATA LINK ERROR @@ -1835,10 +1924,11 @@ void ReaderIso14443a(UsbCommand *c) { iso14a_command_t param = c->arg[0]; uint8_t *cmd = c->d.asBytes; - size_t len = c->arg[1] & 0xFFFF; - size_t lenbits = c->arg[1] >> 16; + size_t len = c->arg[1]; + size_t lenbits = c->arg[2]; uint32_t arg0 = 0; byte_t buf[USB_CMD_DATA_SIZE]; + uint8_t par[MAX_PARITY_SIZE]; if(param & ISO14A_CONNECT) { iso14a_clear_trace(); @@ -1872,15 +1962,15 @@ void ReaderIso14443a(UsbCommand *c) if(param & ISO14A_APPEND_CRC) { AppendCrc14443a(cmd,len); len += 2; - if(lenbits>0) - lenbits += 16; + if (lenbits) lenbits += 16; } - if(lenbits>0) { - ReaderTransmitBitsPar(cmd,lenbits,GetParity(cmd,lenbits/8), NULL); + if(lenbits>0) { + GetParity(cmd, lenbits/8, par); + ReaderTransmitBitsPar(cmd, lenbits, par, NULL); } else { ReaderTransmit(cmd,len, NULL); } - arg0 = ReaderReceive(buf); + arg0 = ReaderReceive(buf, par); cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf)); } @@ -1934,17 +2024,17 @@ void ReaderMifare(bool first_try) uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; static uint8_t mf_nr_ar3; - uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); + uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); + uint8_t* receivedAnswerPar = (((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET); iso14a_clear_trace(); iso14a_set_tracing(TRUE); byte_t nt_diff = 0; - byte_t par = 0; - //byte_t par_mask = 0xff; + 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]; + uint8_t uid[10] ={0}; uint32_t cuid; uint32_t nt = 0; @@ -1967,14 +2057,13 @@ void ReaderMifare(bool first_try) sync_cycles = 65536; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). nt_attacked = 0; nt = 0; - par = 0; + par[0] = 0; } else { // we were unsuccessful on a previous call. Try another READER nonce (first 3 parity bits remain the same) - // nt_attacked = prng_successor(nt_attacked, 1); mf_nr_ar3++; mf_nr_ar[3] = mf_nr_ar3; - par = par_low; + par[0] = par_low; } LED_A_ON(); @@ -1982,7 +2071,6 @@ void ReaderMifare(bool first_try) LED_C_OFF(); - Dbprintf("Mifare: Before loopen"); for(uint16_t i = 0; TRUE; i++) { WDT_HIT(); @@ -2011,7 +2099,7 @@ void ReaderMifare(bool first_try) ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); // Receive the (4 Byte) "random" nonce - if (!ReaderReceive(receivedAnswer)) { + if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) { if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce"); continue; } @@ -2063,19 +2151,19 @@ void ReaderMifare(bool first_try) consecutive_resyncs = 0; // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding - if (ReaderReceive(receivedAnswer)) + if (ReaderReceive(receivedAnswer, receivedAnswerPar)) { catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer if (nt_diff == 0) { - par_low = par & 0x07; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change + par_low = par[0] & 0xE0; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change } led_on = !led_on; if(led_on) LED_B_ON(); else LED_B_OFF(); - par_list[nt_diff] = par; + par_list[nt_diff] = SwapBits(par[0], 8); ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; // Test if the information is complete @@ -2086,13 +2174,13 @@ void ReaderMifare(bool first_try) nt_diff = (nt_diff + 1) & 0x07; mf_nr_ar[3] = (mf_nr_ar[3] & 0x1F) | (nt_diff << 5); - par = par_low; + par[0] = par_low; } else { if (nt_diff == 0 && first_try) { - par++; + par[0]++; } else { - par = (((par >> 3) + 1) << 3) | par_low; + par[0] = ((par[0] & 0x1F) + 1) | par_low; } } } @@ -2134,8 +2222,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * int res; uint32_t selTimer = 0; uint32_t authTimer = 0; - uint32_t par = 0; - int len = 0; + uint16_t len = 0; uint8_t cardWRBL = 0; uint8_t cardAUTHSC = 0; uint8_t cardAUTHKEY = 0xff; // no authentication @@ -2149,8 +2236,10 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * struct Crypto1State *pcs; pcs = &mpcs; uint32_t numReads = 0;//Counts numer of times reader read a block - uint8_t* receivedCmd = eml_get_bigbufptr_recbuf(); - uint8_t *response = eml_get_bigbufptr_sendbuf(); + uint8_t* receivedCmd = get_bigbufptr_recvcmdbuf(); + uint8_t* receivedCmd_par = receivedCmd + MAX_FRAME_SIZE; + uint8_t* response = get_bigbufptr_recvrespbuf(); + uint8_t* response_par = response + MAX_FRAME_SIZE; uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; @@ -2217,9 +2306,12 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (MF_DBGLEVEL >= 1) { if (!_7BUID) { - Dbprintf("4B UID: %02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3]); + Dbprintf("4B UID: %02x%02x%02x%02x", + rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]); } else { - Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3],rUIDBCC2[0],rUIDBCC2[1] ,rUIDBCC2[2] , rUIDBCC2[3]); + Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x", + rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], + rUIDBCC2[0], rUIDBCC2[1] ,rUIDBCC2[2], rUIDBCC2[3]); } } @@ -2241,7 +2333,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * //Now, get data - res = EmGetCmd(receivedCmd, &len); + res = EmGetCmd(receivedCmd, &len, receivedCmd_par); if (res == 2) { //Field is off! cardSTATE = MFEMUL_NOFIELD; LEDsoff(); @@ -2268,8 +2360,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * case MFEMUL_NOFIELD: case MFEMUL_HALTED: case MFEMUL_IDLE:{ - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } case MFEMUL_SELECT1:{ @@ -2304,12 +2395,11 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if( len != 8) { cardSTATE_TO_IDLE(); - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } uint32_t ar = bytes_to_num(receivedCmd, 4); - uint32_t nr= bytes_to_num(&receivedCmd[4], 4); + uint32_t nr = bytes_to_num(&receivedCmd[4], 4); //Collect AR/NR if(ar_nr_collected < 2){ @@ -2329,14 +2419,15 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // test if auth OK if (cardRr != prng_successor(nonce, 64)){ - if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x",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)); // 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.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } @@ -2354,8 +2445,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } case MFEMUL_SELECT2:{ if (!len) { - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } if (len == 2 && (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x20)) { @@ -2376,8 +2466,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // i guess there is a command). go into the work state. if (len != 4) { - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } cardSTATE = MFEMUL_WORK; @@ -2387,8 +2476,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * case MFEMUL_WORK:{ if (len == 0) { - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } @@ -2436,8 +2524,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } if(len != 4) { - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } @@ -2466,8 +2553,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } emlGetMem(response, receivedCmd[1], 1); AppendCrc14443a(response, 16); - mf_crypto1_encrypt(pcs, response, 18, &par); - EmSendCmdPar(response, 18, par); + mf_crypto1_encrypt(pcs, response, 18, response_par); + EmSendCmdPar(response, 18, response_par); numReads++; if(exitAfterNReads > 0 && numReads == exitAfterNReads) { Dbprintf("%d reads done, exiting", numReads); @@ -2516,8 +2603,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * LED_C_OFF(); cardSTATE = MFEMUL_HALTED; if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED. Selected time: %d ms", GetTickCount() - selTimer); - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); break; } // RATS @@ -2538,8 +2624,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * cardSTATE = MFEMUL_WORK; } else { cardSTATE_TO_IDLE(); - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); } break; } @@ -2552,8 +2637,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * cardSTATE_TO_IDLE(); break; } - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); cardINTREG = cardINTREG + ans; cardSTATE = MFEMUL_WORK; break; @@ -2566,8 +2650,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * cardSTATE_TO_IDLE(); break; } - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); cardINTREG = cardINTREG - ans; cardSTATE = MFEMUL_WORK; break; @@ -2580,8 +2663,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * cardSTATE_TO_IDLE(); break; } - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); - LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, TRUE); cardSTATE = MFEMUL_WORK; break; } @@ -2645,9 +2727,11 @@ void RAMFUNC SniffMifare(uint8_t param) { // The length of a received command will in most cases be no more than 18 bytes. // So 32 should be enough! uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); + uint8_t *receivedCmdPar = ((uint8_t *)BigBuf) + RECV_CMD_PAR_OFFSET; // The response (tag -> reader) that we're receiving. - uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET); - + uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); + uint8_t *receivedResponsePar = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; + // 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; @@ -2664,10 +2748,10 @@ void RAMFUNC SniffMifare(uint8_t param) { iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); // Set up the demodulator for tag -> reader responses. - Demod.output = receivedResponse; + DemodInit(receivedResponse, receivedResponsePar); // Set up the demodulator for the reader -> tag commands - Uart.output = receivedCmd; + UartInit(receivedCmd, receivedCmdPar); // Setup for the DMA. FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer. @@ -2739,7 +2823,7 @@ void RAMFUNC SniffMifare(uint8_t param) { uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if(MillerDecoding(readerdata, (sniffCounter-1)*4)) { LED_C_INV(); - if (MfSniffLogic(receivedCmd, Uart.len, Uart.parityBits, Uart.bitCount, TRUE)) break; + if (MfSniffLogic(receivedCmd, Uart.len, Uart.parity, Uart.bitCount, TRUE)) break; /* And ready to receive another command. */ UartReset(); @@ -2755,7 +2839,7 @@ void RAMFUNC SniffMifare(uint8_t param) { if(ManchesterDecoding(tagdata, 0, (sniffCounter-1)*4)) { LED_C_INV(); - if (MfSniffLogic(receivedResponse, Demod.len, Demod.parityBits, Demod.bitCount, FALSE)) break; + if (MfSniffLogic(receivedResponse, Demod.len, Demod.parity, Demod.bitCount, FALSE)) break; // And ready to receive another response. DemodReset(); diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index b2c59907..15e2a2f0 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -15,13 +15,6 @@ #include "../include/common.h" #include "mifaresniff.h" -// mifare reader over DMA buffer (SnoopIso14443a())!!! -#define MIFARE_BUFF_OFFSET 3560 // \/ \/ \/ -// card emulator memory -#define EML_RESPONSES 4000 -#define CARD_MEMORY 6000 -#define CARD_MEMORY_LEN 4096 - typedef struct { enum { DEMOD_UNSYNCD, @@ -35,12 +28,14 @@ typedef struct { uint16_t bitCount; uint16_t collisionPos; uint16_t syncBit; - uint32_t parityBits; + uint8_t parityBits; + uint8_t parityLen; uint16_t shiftReg; uint16_t samples; uint16_t len; uint32_t startTime, endTime; uint8_t *output; + uint8_t *parity; } tDemod; typedef enum { @@ -66,32 +61,33 @@ typedef struct { uint16_t byteCntMax; uint16_t posCnt; uint16_t syncBit; - uint32_t parityBits; + uint8_t parityBits; + uint8_t parityLen; uint16_t highCnt; uint16_t twoBits; uint32_t startTime, endTime; uint8_t *output; + uint8_t *parity; } tUart; -//extern byte_t oddparity (const byte_t bt); -extern uint32_t GetParity(const uint8_t *pbtCmd, int iLen); +extern byte_t oddparity (const byte_t bt); +extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); extern void AppendCrc14443a(uint8_t *data, int len); -extern void ReaderTransmit(uint8_t *frame, int len, uint32_t *timing); -extern void ReaderTransmitBitsPar(uint8_t *frame, int bits, uint32_t par, uint32_t *timing); -extern void ReaderTransmitPar(uint8_t *frame, int len, uint32_t par, uint32_t *timing); -extern int ReaderReceive(uint8_t *receivedAnswer); -extern int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr); +extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing); +extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing); +extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing); +extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par); extern void iso14443a_setup(uint8_t fpga_minor_mode); -extern int iso14_apdu(uint8_t *cmd, size_t cmd_len, void *data); +extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data); extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr); extern void iso14a_set_trigger(bool enable); extern void iso14a_set_timeout(uint32_t timeout); -extern void iso14a_clear_tracelen(); +extern void iso14a_clear_trace(); extern void iso14a_set_tracing(bool enable); #endif /* __ISO14443A_H */ diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 11a49902..4a767b56 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -586,7 +586,7 @@ static void BuildIdentifyRequest(void); //----------------------------------------------------------------------------- void AcquireRawAdcSamplesIso15693(void) { - uint8_t *dest = mifare_get_bigbufptr(); + uint8_t *dest = get_bigbufptr_recvrespbuf(); int c = 0; int getNext = 0; @@ -668,7 +668,7 @@ void AcquireRawAdcSamplesIso15693(void) void RecordRawAdcSamplesIso15693(void) { - uint8_t *dest = mifare_get_bigbufptr(); + uint8_t *dest = get_bigbufptr_recvrespbuf(); int c = 0; int getNext = 0; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 0755e1e5..15af6d65 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -17,6 +17,12 @@ #include "crapto1.h" #include "mifareutil.h" +// 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 +#define T0 192 + #define SHORT_COIL() LOW(GPIO_SSC_DOUT) #define OPEN_COIL() HIGH(GPIO_SSC_DOUT) @@ -57,10 +63,9 @@ void SnoopLFRawAdcSamples(int divisor, int trigger_threshold) // split into two routines so we can avoid timing issues after sending commands // void DoAcquisition125k_internal(int trigger_threshold, bool silent) { - uint8_t *dest = mifare_get_bigbufptr(); - int n = 24000; - int i = 0; - memset(dest, 0x00, n); + uint8_t *dest = get_bigbufptr_recvrespbuf(); + uint16_t i = 0; + memset(dest, 0x00, FREE_BUFFER_SIZE); for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { @@ -74,7 +79,7 @@ void DoAcquisition125k_internal(int trigger_threshold, bool silent) continue; else trigger_threshold = -1; - if (++i >= n) break; + if (++i >= FREE_BUFFER_SIZE) break; } } if (!silent){ @@ -91,25 +96,20 @@ void DoAcquisition125k() { void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) { - - /* Make sure the tag is reset */ FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + /* Make sure the tag is reset */ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(2500); - int divisor_used = 95; // 125 KHz + int divisor = 95; // 125 KHz // see if 'h' was specified - if (command[strlen((char *) command) - 1] == 'h') - divisor_used = 88; // 134.8 KHz + divisor = 88; // 134.8 KHz - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); - - - // And a little more time for the tag to fully power up SpinDelay(2000); // Now set up the SSC to get the ADC samples that are now streaming at us. @@ -120,7 +120,7 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); LED_D_ON(); @@ -132,8 +132,7 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); - + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); // now do the read @@ -455,72 +454,162 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) // PIO_SODR = Set Output Data Register //#define LOW(x) AT91C_BASE_PIOA->PIO_CODR = (x) //#define HIGH(x) AT91C_BASE_PIOA->PIO_SODR = (x) -void SimulateTagLowFrequency(int period, int gap, int ledcontrol) +void SimulateTagLowFrequency( uint16_t period, uint32_t gap, uint8_t ledcontrol) { - int i = 0; + LED_D_ON(); + + uint16_t i = 0; + uint8_t send = 0; + + //int overflow = 0; + uint8_t *buf = (uint8_t *)BigBuf; + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + RELAY_OFF(); + + // Configure output pin that is connected to the FPGA (for modulating) + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + SHORT_COIL(); + + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + // 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, + // external trigger rising edge, load RA on rising edge of TIOA. + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; + + // Enable and reset counter + //AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + while(!BUTTON_PRESS()) { + WDT_HIT(); + + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0 * 55) { + + // Check if rising edge in modulation is detected + if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + //int ra = (AT91C_BASE_TC1->TC_RA/T0) + overflow; + //Dbprintf("Timing value - %d %d", ra, overflow); + //overflow = 0; + + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + send = 1; + + LED_B_ON(); + } + } + + if ( send ) { + // Disable timer 1 with external trigger to avoid triggers during our own modulation + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, + // not that since the clock counts since the rising edge, but T_Wait1 is + // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) + // periods. The gap time T_Low varies (4..10). All timer values are in + // terms of T0 units + while(AT91C_BASE_TC0->TC_CV < T0 * 16 ); + + // datat kommer in som 1 bit för varje position i arrayn + for(i = 0; i < period; ++i) { + + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + if ( buf[i] > 0 ) + HIGH(GPIO_SSC_DOUT); + else + LOW(GPIO_SSC_DOUT); + + while(AT91C_BASE_TC0->TC_CV < T0 * 1 ); + } + // Drop modulation + LOW(GPIO_SSC_DOUT); + + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + LED_B_OFF(); + } + + send = 0; + + // Save the timer overflow, will be 0 when frame was received + //overflow += (AT91C_BASE_TC1->TC_CV/T0); + + // Reset the timer to restart while-loop that receives frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + } + + LED_B_OFF(); + LED_D_OFF(); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + DbpString("Sim Stopped"); +} + + +void SimulateTagLowFrequencyA(int len, int gap) +{ + //Dbprintf("LEN %d || Gap %d",len, gap); + uint8_t *buf = (uint8_t *)BigBuf; FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); // new izsh toggle mode! // 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. FpgaSetupSsc(); + SpinDelay(5); - // Configure output and enable pin that is connected to the FPGA (for modulating) - // AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; // (PIO_PER) PIO Enable Register - // AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; // (PIO_OER) Output Enable Register - // AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; // (PIO_ODR) Output Disable Register - - AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0; + AT91C_BASE_SSC->SSC_THR = 0x00; + int i = 0; while(!BUTTON_PRESS()) { WDT_HIT(); + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + + if ( buf[i] > 0 ) + AT91C_BASE_SSC->SSC_THR = 0x43; + else + AT91C_BASE_SSC->SSC_THR = 0x00; - // PIO_PDSR = Pin Data Status Register - // GPIO_SSC_CLK = SSC Transmit Clock - // wait ssp_clk == high - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - if(BUTTON_PRESS()) { - DbpString("Stopped at 0"); - return; - } - WDT_HIT(); - } - - if ( buf[i] > 0 ){ - OPEN_COIL(); - } else { - SHORT_COIL(); - } - - DbpString("Enter Sim3"); - // wait ssp_clk == low - while( (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) ) { - if(BUTTON_PRESS()) { - DbpString("stopped at 1"); - return; + ++i; + LED_A_ON(); + if (i >= len){ + i = 0; } - WDT_HIT(); } - DbpString("Enter Sim4 "); - //SpinDelayUs(512); - - ++i; - if(i == period) { - i = 0; - if (gap) { - SHORT_COIL(); - SpinDelay(gap); - } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + LED_A_OFF(); } } - DbpString("Stopped"); - return; + DbpString("lf simulate stopped"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); } #define DEBUG_FRAME_CONTENTS 1 @@ -529,7 +618,7 @@ void SimulateTagLowFrequencyBidir(int divisor, int t0) } // compose fc/8 fc/10 waveform -static void fc(int c, int *n) { +static void fc(int c, uint16_t *n) { uint8_t *dest = (uint8_t *)BigBuf; int idx; @@ -577,9 +666,9 @@ static void fc(int c, int *n) { // prepare a waveform pattern in the buffer based on the ID given then // simulate a HID tag until the button is pressed -void CmdHIDsimTAG(int hi, int lo, int ledcontrol) +void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) { - int n=0, i=0; + uint16_t n=0, i=0; /* HID tag bitstream format The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits @@ -666,7 +755,7 @@ size_t fsk_demod(uint8_t * dest, size_t size) } -size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, uint8_t maxConsequtiveBits ) +size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, uint8_t maxConsequtiveBits, uint8_t invert ) { uint8_t lastval=dest[0]; uint32_t idx=0; @@ -680,7 +769,7 @@ size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint continue; } //if lastval was 1, we have a 1->0 crossing - if ( dest[idx-1] ) { + if ( dest[idx-1]==1 ) { n=(n+1) / h2l_crossing_value; } else {// 0->1 crossing n=(n+1) / l2h_crossing_value; @@ -689,7 +778,11 @@ size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint if(n < maxConsequtiveBits) { - memset(dest+numBits, dest[idx-1] , n); + if ( invert==0) + memset(dest+numBits, dest[idx-1] , n); + else + memset(dest+numBits, dest[idx-1]^1 , n); + numBits += n; } n=0; @@ -702,10 +795,10 @@ size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint // loop to capture raw HID waveform then FSK demodulate the TAG ID from it void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = (uint8_t *)BigBuf; + uint8_t *dest = get_bigbufptr_recvrespbuf(); size_t size=0,idx=0; //, found=0; - uint32_t hi2=0, hi=0, lo=0; + uint32_t hi2=0, hi=0, lo=0; // Configure to go in 125Khz listen mode LFSetupFPGAForADC(0, true); @@ -716,17 +809,15 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) if (ledcontrol) LED_A_ON(); DoAcquisition125k_internal(-1,true); - size = sizeof(BigBuf); // FSK demodulator - size = fsk_demod(dest, size); + size = fsk_demod(dest, FREE_BUFFER_SIZE); // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns // 1->0 : fc/8 in sets of 6 // 0->1 : fc/10 in sets of 5 - size = aggregate_bits(dest,size, 6,5,5); - - WDT_HIT(); + // do not invert + size = aggregate_bits(dest,size, 6,5,5,0); // final loop, go over previously decoded manchester data and decode into usable tag ID // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 @@ -743,7 +834,7 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { // Keep going until next frame marker (or error) // Shift in a bit. Start by shifting high registers - hi2=(hi2<<1)|(hi>>31); + hi2=(hi2<<1)|(hi>>31); hi=(hi<<1)|(lo>>31); //Then, shift in a 0 or one into low if (dest[idx] && !dest[idx+1]) // 1 0 @@ -758,25 +849,23 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) // Hopefully, we read a tag and hit upon the next frame marker if(idx + sizeof(frame_marker_mask) < size) { - if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { - if (hi2 != 0){ - Dbprintf("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { + if (hi2 != 0){ + Dbprintf("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + } + else { + Dbprintf("TAG ID: %x%08x (%d)", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + } } - else { - Dbprintf("TAG ID: %x%08x (%d)", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - } - } - } // reset hi2 = hi = lo = 0; numshifts = 0; - }else - { + } else { idx++; } } @@ -801,63 +890,72 @@ uint32_t bytebits_to_byte(uint8_t* src, int numbits) void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = (uint8_t *)BigBuf; - + uint8_t *dest = get_bigbufptr_recvrespbuf(); + size_t size=0, idx=0; uint32_t code=0, code2=0; - + uint8_t isFinish = 0; + // Configure to go in 125Khz listen mode LFSetupFPGAForADC(0, true); - while(!BUTTON_PRESS()) { + while(!BUTTON_PRESS() & !isFinish) { + WDT_HIT(); + if (ledcontrol) LED_A_ON(); DoAcquisition125k_internal(-1,true); - size = sizeof(BigBuf); // FSK demodulator - size = fsk_demod(dest, size); + size = fsk_demod(dest, FREE_BUFFER_SIZE); // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns // 1->0 : fc/8 in sets of 7 // 0->1 : fc/10 in sets of 6 - size = aggregate_bits(dest, size, 7,6,13); + size = aggregate_bits(dest, size, 7,6,13,1); //13 max Consecutive should be ok as most 0s in row should be 10 for init seq - invert bits - WDT_HIT(); - + //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 + uint8_t mask[] = {0,0,0,0,0,0,0,0,0,1}; - for( idx=0; idx < size - 64; idx++) { - - if ( memcmp(dest + idx, mask, sizeof(mask)) ) continue; - - Dbprintf("%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]); - Dbprintf("%d%d%d%d%d%d%d%d",dest[idx+8], dest[idx+9], dest[idx+10],dest[idx+11],dest[idx+12],dest[idx+13],dest[idx+14],dest[idx+15]); - Dbprintf("%d%d%d%d%d%d%d%d",dest[idx+16],dest[idx+17],dest[idx+18],dest[idx+19],dest[idx+20],dest[idx+21],dest[idx+22],dest[idx+23]); - Dbprintf("%d%d%d%d%d%d%d%d",dest[idx+24],dest[idx+25],dest[idx+26],dest[idx+27],dest[idx+28],dest[idx+29],dest[idx+30],dest[idx+31]); - Dbprintf("%d%d%d%d%d%d%d%d",dest[idx+32],dest[idx+33],dest[idx+34],dest[idx+35],dest[idx+36],dest[idx+37],dest[idx+38],dest[idx+39]); - Dbprintf("%d%d%d%d%d%d%d%d",dest[idx+40],dest[idx+41],dest[idx+42],dest[idx+43],dest[idx+44],dest[idx+45],dest[idx+46],dest[idx+47]); - Dbprintf("%d%d%d%d%d%d%d%d",dest[idx+48],dest[idx+49],dest[idx+50],dest[idx+51],dest[idx+52],dest[idx+53],dest[idx+54],dest[idx+55]); - Dbprintf("%d%d%d%d%d%d%d%d",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); + for( idx=0; idx < (size - 64); idx++) { + if ( memcmp(dest + idx, mask, sizeof(mask))==0) { + //frame marker found + 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); + short version = bytebits_to_byte(dest+idx+28,8); //14,4 + char facilitycode = bytebits_to_byte(dest+idx+19,8) ; + uint16_t number = (bytebits_to_byte(dest+idx+37,8)<<8)|(bytebits_to_byte(dest+idx+46,8)); //36,9 + + Dbprintf("XSF(%02d)%02x:%d (%08x%08x)",version,facilitycode,number,code,code2); - short version = bytebits_to_byte(dest+idx+14,4); - char unknown = bytebits_to_byte(dest+idx+19,8) ; - uint16_t number = bytebits_to_byte(dest+idx+36,9); - - Dbprintf("XSF(%02d)%02x:%d (%08x%08x)",version,unknown,number,code,code2); - if (ledcontrol) LED_D_OFF(); - - // if we're only looking for one tag - if (findone){ - LED_A_OFF(); - return; + // if we're only looking for one tag + if (findone){ + if (ledcontrol) LED_A_OFF(); + isFinish = 1; + break; + } + } } - } - WDT_HIT(); + WDT_HIT(); } DbpString("Stopped"); if (ledcontrol) LED_A_OFF(); @@ -994,7 +1092,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod // Read one card block in page 0 void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) { - uint8_t *dest = mifare_get_bigbufptr(); + uint8_t *dest = get_bigbufptr_recvrespbuf(); uint16_t bufferlength = T55xx_SAMPLES_SIZE; uint32_t i = 0; @@ -1030,6 +1128,7 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { AT91C_BASE_SSC->SSC_THR = 0x43; + //AT91C_BASE_SSC->SSC_THR = 0xff; LED_D_ON(); } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { @@ -1047,9 +1146,9 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) // Read card traceability data (page 1) void T55xxReadTrace(void){ - uint8_t *dest = mifare_get_bigbufptr(); + uint8_t *dest = get_bigbufptr_recvrespbuf(); uint16_t bufferlength = T55xx_SAMPLES_SIZE; - int i=0; + uint32_t i = 0; // Clear destination buffer before sending the command 0x80 = average memset(dest, 0x80, bufferlength); @@ -1808,7 +1907,7 @@ void EM4xLogin(uint32_t Password) { void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { - uint8_t *dest = mifare_get_bigbufptr(); + uint8_t *dest = get_bigbufptr_recvrespbuf(); uint16_t bufferlength = 12000; uint32_t i = 0; diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 4f3556b2..519ea2b0 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -505,7 +505,7 @@ void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) } // Return 1 if the nonce is invalid else return 0 -int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { +int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t * parity) { return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; @@ -532,7 +532,8 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat uint16_t davg; static uint16_t dmin, dmax; uint8_t uid[10]; - uint32_t cuid, nt1, nt2, nttmp, nttest, par, ks1; + uint32_t cuid, nt1, nt2, nttmp, nttest, ks1; + uint8_t par[1]; uint32_t target_nt[2], target_ks[2]; uint8_t par_array[4]; @@ -540,7 +541,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint32_t auth1_time, auth2_time; static uint16_t delta_time; @@ -561,7 +562,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat WDT_HIT(); davg = dmax = 0; - dmin = 2000; + dmin = 2000; delta_time = 0; for (rtr = 0; rtr < 17; rtr++) { @@ -597,7 +598,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat continue; }; - nttmp = prng_successor(nt1, 140); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 + nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 for (i = 141; i < 1200; i++) { nttmp = prng_successor(nttmp, 1); if (nttmp == nt2) {break;} @@ -666,19 +667,18 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // nested authentication auth2_time = auth1_time + delta_time; - len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, &par, &auth2_time); + len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time); if (len != 4) { if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); continue; }; nt2 = bytes_to_num(receivedAnswer, 4); - if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par); + if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par[0]); // Parity validity check for (j = 0; j < 4; j++) { - par_array[j] = (oddparity(receivedAnswer[j]) != ((par & 0x08) >> 3)); - par = par << 1; + par_array[j] = (oddparity(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); } ncount = 0; @@ -713,10 +713,6 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - byte_t buf[4 + 4 * 4]; memcpy(buf, &cuid, 4); memcpy(buf+4, &target_nt[0], 4); @@ -947,7 +943,8 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai uint32_t cuid; memset(uid, 0x00, 10); - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; if (workFlags & 0x08) { // clear trace @@ -982,14 +979,14 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // reset chip if (needWipe){ - ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + ReaderTransmitBitsPar(wupC1,7,0, NULL); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wipeC, sizeof(wipeC), NULL); - if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); break; }; @@ -1002,20 +999,20 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // write block if (workFlags & 0x02) { - ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + ReaderTransmitBitsPar(wupC1,7,0, NULL); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { + if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); break; }; @@ -1024,7 +1021,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai AppendCrc14443a(d_block, 16); ReaderTransmit(d_block, sizeof(d_block), NULL); - if ((ReaderReceive(receivedAnswer) != 1) || (receivedAnswer[0] != 0x0a)) { + if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); break; }; @@ -1072,7 +1069,8 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai uint32_t cuid = 0; memset(data, 0x00, 18); - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; if (workFlags & 0x08) { // clear trace @@ -1094,20 +1092,20 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai while (true) { if (workFlags & 0x02) { ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } // read block - if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, NULL) != 18)) { + if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error"); break; }; diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 60c941eb..4a580371 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -2,9 +2,10 @@ #define MAX_APPLICATION_COUNT 28 #define MAX_FILE_COUNT 16 -#define MAX_FRAME_SIZE 60 +#define MAX_DESFIRE_FRAME_SIZE 60 #define NOT_YET_AUTHENTICATED 255 -#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) +#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; @@ -58,7 +59,7 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){ */ uint8_t flags = arg0; size_t datalen = arg1; - uint8_t resp[RECV_RES_SIZE]; + uint8_t resp[RECEIVE_SIZE]; memset(resp,0,sizeof(resp)); if (MF_DBGLEVEL >= 4) { @@ -191,7 +192,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain //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* bigbuffer = mifare_get_bigbufptr(); + //uint8_t* bigbuffer = get_bigbufptr_recvrespbuf(); uint8_t resp[256] = {0x00}; uint8_t IV[16] = {0x00}; @@ -309,6 +310,9 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ size_t wrappedLen = 0; uint8_t wCmd[USB_CMD_DATA_SIZE] = {0}; + uint8_t *resp = ((uint8_t *)BigBuf) + RECV_RESP_OFFSET; + uint8_t *resp_par = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; + wrappedLen = CreateAPDU( cmd, cmd_len, wCmd); if (MF_DBGLEVEL >= 4) { @@ -316,7 +320,7 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ } ReaderTransmit( wCmd, wrappedLen, NULL); - status = ReaderReceive(dataout); + status = ReaderReceive(resp, resp_par); if( status == 0x00){ if (MF_DBGLEVEL >= 4) { @@ -327,12 +331,14 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ // 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 (status >= 4 // PCB+CID+CRC = 4 bytes - && ((dataout[0] & 0xC0) == 0 // I-Block - || (dataout[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 - && (dataout[0] & 0x01) == pcb_blocknum) // equal block numbers + && ((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 } + // copy response to + dataout = resp; return status; } diff --git a/armsrc/mifaresniff.c b/armsrc/mifaresniff.c index 3e5570f9..fed12772 100644 --- a/armsrc/mifaresniff.c +++ b/armsrc/mifaresniff.c @@ -37,7 +37,7 @@ bool MfSniffEnd(void){ return FALSE; } -bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint32_t parity, uint16_t bitCnt, bool reader) { +bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) { if (reader && (len == 1) && (bitCnt == 7)) { // reset on 7-Bit commands from reader sniffState = SNF_INIT; @@ -114,16 +114,16 @@ bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint32_t parity, ui sniffBuf[11] = sniffSAK; sniffBuf[12] = 0xFF; sniffBuf[13] = 0xFF; - LogTrace(sniffBuf, 14, 0, parity, true); + LogTrace(sniffBuf, 14, 0, 0, NULL, TRUE); } // intentionally no break; case SNF_CARD_CMD:{ - LogTrace(data, len, 0, parity, true); + LogTrace(data, len, 0, 0, NULL, TRUE); sniffState = SNF_CARD_RESP; timerData = GetTickCount(); break; } case SNF_CARD_RESP:{ - LogTrace(data, len, 0, parity, false); + LogTrace(data, len, 0, 0, NULL, FALSE); sniffState = SNF_CARD_CMD; timerData = GetTickCount(); break; diff --git a/armsrc/mifaresniff.h b/armsrc/mifaresniff.h index 3ee64f35..aa2a860f 100644 --- a/armsrc/mifaresniff.h +++ b/armsrc/mifaresniff.h @@ -39,7 +39,7 @@ #define SNF_UID_7 0 bool MfSniffInit(void); -bool RAMFUNC MfSniffLogic(const uint8_t * data, uint16_t len, uint32_t parity, uint16_t bitCnt, bool reader); +bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader); bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs); bool intMfSniffSend(); bool MfSniffEnd(void); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 537720df..d2841497 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -22,17 +22,14 @@ int MF_DBGLEVEL = MF_DBG_ALL; // memory management -uint8_t* mifare_get_bigbufptr(void) { - return (((uint8_t *)BigBuf) + MIFARE_BUFF_OFFSET); // was 3560 - tied to other size changes +uint8_t* get_bigbufptr_recvrespbuf(void) { + return (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); } -uint8_t* eml_get_bigbufptr_sendbuf(void) { +uint8_t* get_bigbufptr_recvcmdbuf(void) { return (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); } -uint8_t* eml_get_bigbufptr_recbuf(void) { - return (((uint8_t *)BigBuf) + MIFARE_BUFF_OFFSET); -} -uint8_t* eml_get_bigbufptr_cardmem(void) { - return (((uint8_t *)BigBuf) + CARD_MEMORY); +uint8_t* get_bigbufptr_emlcardmem(void) { + return (((uint8_t *)BigBuf) + CARD_MEMORY_OFFSET); } // crypto1 helpers @@ -53,15 +50,17 @@ void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len){ return; } -void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, int len, uint32_t *par) { +void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) { uint8_t bt = 0; int i; - uint32_t mltpl = 1 << (len - 1); // for len=18 it=0x20000 - *par = 0; + par[0] = 0; + for (i = 0; i < len; i++) { bt = data[i]; data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i]; - *par = (*par >> 1) | ( ((filter(pcs->odd) ^ oddparity(bt)) & 0x01) * mltpl ); + if((i&0x0007) == 0) + par[i>>3] = 0; + par[i>>3] |= (((filter(pcs->odd) ^ oddparity(bt)) & 0x01)<<(7-(i&0x0007))); } return; } @@ -77,19 +76,20 @@ uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { } // send commands -int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing) +int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) { - return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, NULL, timing); + return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, answer_parity, timing); } -int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *timing) +int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) { - uint8_t dcmd[8]; - dcmd[0] = cmd; - memcpy(dcmd+1,data,5); + uint8_t dcmd[8]; + dcmd[0] = cmd; + memcpy(dcmd+1,data,5); + AppendCrc14443a(dcmd, 6); ReaderTransmit(dcmd, sizeof(dcmd), NULL); - int len = ReaderReceive(answer); + int len = ReaderReceive(answer, answer_parity); if(!len) { if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); return 2; @@ -97,7 +97,7 @@ int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint return len; } -int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint32_t *timing) +int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) { uint8_t dcmd[19]; int len; @@ -106,10 +106,10 @@ int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uin AppendCrc14443a(dcmd, 17); ReaderTransmit(dcmd, sizeof(dcmd), timing); - len = ReaderReceive(answer); + len = ReaderReceive(answer, answer_parity); if(!len) { if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); - len = ReaderReceive(answer); + len = ReaderReceive(answer,answer_parity); } if(len==1) { if (MF_DBGLEVEL >= 1) Dbprintf("NAK - Authentication failed."); @@ -118,11 +118,11 @@ int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uin return len; } -int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing) +int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) { uint8_t dcmd[4], ecmd[4]; - uint32_t pos, par, res; - + uint16_t pos, res; + uint8_t par[1]; // 1 Byte parity is enough here dcmd[0] = cmd; dcmd[1] = data; AppendCrc14443a(dcmd, 2); @@ -130,11 +130,11 @@ int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cm memcpy(ecmd, dcmd, sizeof(dcmd)); if (crypted) { - par = 0; + par[0] = 0; for (pos = 0; pos < 4; pos++) { ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos]; - par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(dcmd[pos])) & 0x01) * 0x08 ); + par[0] |= (((filter(pcs->odd) ^ oddparity(dcmd[pos])) & 0x01) << (7-pos)); } ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing); @@ -143,9 +143,9 @@ int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cm ReaderTransmit(dcmd, sizeof(dcmd), timing); } - int len = ReaderReceivePar(answer, &par); + int len = ReaderReceive(answer, par); - if (parptr) *parptr = par; + if (answer_parity) *answer_parity = par[0]; if (crypted == CRYPT_ALL) { if (len == 1) { @@ -167,33 +167,35 @@ int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cm } // mifare commands -int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested) +int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested) { return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL); } -int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing) +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) { // variables int len; uint32_t pos; uint8_t tmp4[4]; - byte_t par = 0; - byte_t ar[4]; + uint8_t par[1] = {0x00}; + byte_t nr[4]; uint32_t nt, ntpp; // Supplied tag nonce uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; // Transmit MIFARE_CLASSIC_AUTH - len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, timing); - if (MF_DBGLEVEL >= 4) Dbprintf("rand nonce len: %x", len); + len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing); + if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); if (len != 4) return 1; - ar[0] = 0x55; - ar[1] = 0x41; - ar[2] = 0x49; - ar[3] = 0x92; + // "random" reader nonce: + nr[0] = 0x55; + nr[1] = 0x41; + nr[2] = 0x49; + nr[3] = 0x92; // Save the tag nonce (nt) nt = bytes_to_num(receivedAnswer, 4); @@ -221,12 +223,12 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN if (ntptr) *ntptr = nt; - par = 0; // Generate (encrypted) nr+parity by loading it into the cipher (Nr) + par[0] = 0; for (pos = 0; pos < 4; pos++) { - mf_nr_ar[pos] = crypto1_byte(pcs, ar[pos], 0) ^ ar[pos]; - par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(ar[pos])) & 0x01) * 0x80 ); + mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos]; + par[0] |= (((filter(pcs->odd) ^ oddparity(nr[pos])) & 0x01) << (7-pos)); } // Skip 32 bits in pseudo random generator @@ -237,14 +239,14 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN { nt = prng_successor(nt,8); mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff); - par = (par >> 1)| ( ((filter(pcs->odd) ^ oddparity(nt & 0xff)) & 0x01) * 0x80 ); + par[0] |= (((filter(pcs->odd) ^ oddparity(nt & 0xff)) & 0x01) << (7-pos)); } // Transmit reader nonce and reader answer ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); - // Receive 4 bit answer - len = ReaderReceive(receivedAnswer); + // Receive 4 byte tag answer + len = ReaderReceive(receivedAnswer, receivedAnswerPar); if (!len) { if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); @@ -268,10 +270,11 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo int len; uint8_t bt[2]; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, NULL); + len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; @@ -294,12 +297,13 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo int mifare_ultra_auth1(uint32_t uid, uint8_t *blockData){ // variables - int len; + uint16_t len; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, receivedAnswer,NULL); + len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, receivedAnswer,receivedAnswerPar ,NULL); if (len == 1) { if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; @@ -310,7 +314,7 @@ int mifare_ultra_auth1(uint32_t uid, uint8_t *blockData){ receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], receivedAnswer[10]); memcpy(blockData, receivedAnswer, 11); - return 0; + return 0; } //else something went wrong??? return 1; @@ -318,13 +322,13 @@ int mifare_ultra_auth1(uint32_t uid, uint8_t *blockData){ int mifare_ultra_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ // variables - int len; - - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint16_t len; + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, key, receivedAnswer,NULL); + len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, key, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; @@ -344,13 +348,15 @@ int mifare_ultra_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) { // variables - int len; + uint16_t len; uint8_t bt[2]; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; + // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer,NULL); + len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; @@ -375,16 +381,17 @@ int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { // variables - int len, i; + uint16_t len, i; uint32_t pos; - uint32_t par = 0; + uint8_t par[3] = {0x00}; byte_t res; uint8_t d_block[18], d_block_enc[18]; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; // command MIFARE_CLASSIC_WRITEBLOCK - len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, NULL); + len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); @@ -395,17 +402,16 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl AppendCrc14443a(d_block, 16); // crypto - par = 0; for (pos = 0; pos < 18; pos++) { d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; - par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(d_block[pos])) & 0x01) * 0x20000 ); + par[pos>>3] |= (((filter(pcs->odd) ^ oddparity(d_block[pos])) & 0x01) << (7 - (pos&0x0007))); } ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); // Receive the response - len = ReaderReceive(receivedAnswer); + len = ReaderReceive(receivedAnswer, receivedAnswerPar); res = 0; for (i = 0; i < 4; i++) @@ -421,72 +427,70 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) { - // variables - int len; - uint32_t par = 0; - - uint8_t d_block[18]; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); - - // command MIFARE_CLASSIC_WRITEBLOCK - len = mifare_sendcmd_short(NULL, 1, 0xA0, blockNo, receivedAnswer,NULL); + // variables + uint16_t len; + uint8_t par[3] = {0}; // enough for 18 parity bits + + uint8_t d_block[18]; + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; + + // command MIFARE_CLASSIC_WRITEBLOCK + len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); - if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]); - return 1; - } + if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]); + return 1; + } memset(d_block,'\0',18); memcpy(d_block, blockData, 16); - AppendCrc14443a(d_block, 16); + AppendCrc14443a(d_block, 16); ReaderTransmitPar(d_block, sizeof(d_block), par, NULL); - - // Receive the response - len = ReaderReceive(receivedAnswer); + + // Receive the response + len = ReaderReceive(receivedAnswer, receivedAnswerPar); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len); - return 2; - } + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len); + return 2; + } - return 0; + return 0; } int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) { - // variables - int len; - //uint32_t par = 0; + uint16_t len; + + uint8_t d_block[8]; + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - uint8_t d_block[8]; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); - - // command MIFARE_CLASSIC_WRITEBLOCK + // command MIFARE_CLASSIC_WRITEBLOCK memset(d_block,'\0',8); d_block[0]= blockNo; memcpy(d_block+1,blockData,4); AppendCrc14443a(d_block, 6); //i know the data send here is correct - len = mifare_sendcmd_short_special(NULL, 1, 0xA2, d_block, receivedAnswer,NULL); + len = mifare_sendcmd_short_special(NULL, 1, 0xA2, d_block, receivedAnswer, receivedAnswerPar, NULL); - if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0],len); - return 1; - } - return 0; + if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0],len); + return 1; + } + return 0; } int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) { - // variables - int len; - - // Mifare HALT - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint16_t len; + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - len = mifare_sendcmd_short(pcs, pcs == NULL ? 0:1, 0x50, 0x00, receivedAnswer, NULL); + len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { if (MF_DBGLEVEL >= 1) Dbprintf("halt error. response len: %x", len); return 1; @@ -497,13 +501,11 @@ int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) int mifare_ultra_halt(uint32_t uid) { - // variables - int len; - - // Mifare HALT - uint8_t* receivedAnswer = mifare_get_bigbufptr(); + uint16_t len; + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - len = mifare_sendcmd_short(NULL, 1, 0x50, 0x00, receivedAnswer, NULL); + len = mifare_sendcmd_short(NULL, true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { if (MF_DBGLEVEL >= 1) Dbprintf("halt error. response len: %x", len); return 1; @@ -535,25 +537,22 @@ uint8_t FirstBlockOfSector(uint8_t sectorNo) // work with emulator memory void emlSetMem(uint8_t *data, int blockNum, int blocksCount) { - uint8_t* emCARD = eml_get_bigbufptr_cardmem(); - + uint8_t* emCARD = get_bigbufptr_emlcardmem(); memcpy(emCARD + blockNum * 16, data, blocksCount * 16); } void emlGetMem(uint8_t *data, int blockNum, int blocksCount) { - uint8_t* emCARD = eml_get_bigbufptr_cardmem(); - + uint8_t* emCARD = get_bigbufptr_emlcardmem(); memcpy(data, emCARD + blockNum * 16, blocksCount * 16); } void emlGetMemBt(uint8_t *data, int bytePtr, int byteCount) { - uint8_t* emCARD = eml_get_bigbufptr_cardmem(); - + uint8_t* emCARD = get_bigbufptr_emlcardmem(); memcpy(data, emCARD + bytePtr, byteCount); } int emlCheckValBl(int blockNum) { - uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + uint8_t* emCARD = get_bigbufptr_emlcardmem(); uint8_t* data = emCARD + blockNum * 16; if ((data[0] != (data[4] ^ 0xff)) || (data[0] != data[8]) || @@ -568,7 +567,7 @@ int emlCheckValBl(int blockNum) { } int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) { - uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + uint8_t* emCARD = get_bigbufptr_emlcardmem(); uint8_t* data = emCARD + blockNum * 16; if (emlCheckValBl(blockNum)) { @@ -576,13 +575,12 @@ int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) { } memcpy(blReg, data, 4); - *blBlock = data[12]; - + *blBlock = data[12]; return 0; } int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) { - uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + uint8_t* emCARD = get_bigbufptr_emlcardmem(); uint8_t* data = emCARD + blockNum * 16; memcpy(data + 0, &blReg, 4); @@ -600,7 +598,7 @@ int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) { uint64_t emlGetKey(int sectorNum, int keyType) { uint8_t key[6]; - uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + uint8_t* emCARD = get_bigbufptr_emlcardmem(); memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); return bytes_to_num(key, 6); @@ -611,9 +609,9 @@ void emlClearMem(void) { const uint8_t trailer[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x80, 0x69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const uint8_t uid[] = {0xe6, 0x84, 0x87, 0xf3, 0x16, 0x88, 0x04, 0x00, 0x46, 0x8e, 0x45, 0x55, 0x4d, 0x70, 0x41, 0x04}; - uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + uint8_t* emCARD = get_bigbufptr_emlcardmem(); - memset(emCARD, 0, CARD_MEMORY_LEN); + memset(emCARD, 0, CARD_MEMORY_SIZE); // fill sectors trailer data for(b = 3; b < 256; b<127?(b+=4):(b+=16)) { diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index bd313699..12064829 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -53,16 +53,15 @@ extern int MF_DBGLEVEL; #define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); //functions +uint8_t* mifare_get_bigbufptr(void); +int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); +int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing); + +int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing); +int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); -int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing); -int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint8_t *timing); -int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint32_t *timing); -int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing); - -int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \ - uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested); -int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, \ - uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing); +int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested); +int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing); int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_ultra_auth1(uint32_t cuid, uint8_t *blockData); int mifare_ultra_auth2(uint32_t cuid, uint8_t *key, uint8_t *blockData); @@ -75,13 +74,13 @@ int mifare_ultra_halt(uint32_t uid); // crypto functions void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len); -void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, int len, uint32_t *par); +void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par); uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data); // memory management -uint8_t* mifare_get_bigbufptr(void); -uint8_t* eml_get_bigbufptr_sendbuf(void); -uint8_t* eml_get_bigbufptr_recbuf(void); +uint8_t* get_bigbufptr_recvrespbuf(void); +uint8_t* get_bigbufptr_recvcmdbuf(void); +uint8_t* get_bigbufptr_emlcardmem(void); // Mifare memory structure uint8_t NumBlocksPerSector(uint8_t sectorNo); diff --git a/armsrc/util.c b/armsrc/util.c index b1ef6ea0..0558fb94 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -85,15 +85,6 @@ int32_t le24toh (uint8_t data[3]) return (data[2] << 16) | (data[1] << 8) | data[0]; } -//added here for parity calulations -uint8_t oddparity(uint8_t bt) -{ - uint16_t v = bt; - v ^= v >> 4; - v &= 0xF; - return ((0x9669 >> v) & 1); -} - void LEDsoff() { LED_A_OFF(); diff --git a/armsrc/util.h b/armsrc/util.h index 80ed9b54..c6503395 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -35,8 +35,6 @@ uint64_t bytes_to_num(uint8_t* src, size_t len); void rol(uint8_t *data, const size_t len); void lsl (uint8_t *data, size_t len); int32_t le24toh (uint8_t data[3]); -//added parity generation function here -uint8_t oddparity(uint8_t bt); void SpinDelay(int ms); void SpinDelayUs(int us); diff --git a/client/cmddata.c b/client/cmddata.c index b4752b1f..a1a0d484 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -461,7 +461,7 @@ int CmdSamples(const char *Cmd) int n = strtol(Cmd, NULL, 0); if (n == 0) - n = 512; + n = 16000; if (n > sizeof(got)) n = sizeof(got); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 391908e7..d1d440ee 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -44,8 +44,8 @@ int CmdHF14AList(const char *Cmd) ShowWaitCycles = true; } - uint8_t got[TRACE_BUFFER_SIZE]; - GetFromBigBuf(got,sizeof(got),0); + uint8_t trace[TRACE_BUFFER_SIZE]; + GetFromBigBuf(trace,TRACE_BUFFER_SIZE,0); WaitForResponse(CMD_ACK,NULL); PrintAndLog("Recorded Activity"); @@ -56,122 +56,98 @@ int CmdHF14AList(const char *Cmd) PrintAndLog(" Start | End | Src | Data"); PrintAndLog("-----------|-----------|-----|--------"); - int i = 0; - uint32_t first_timestamp = 0; + uint16_t tracepos = 0; + uint16_t duration; + uint16_t data_len; + uint16_t parity_len; + bool isResponse; uint32_t timestamp; - uint32_t EndOfTransmissionTimestamp = 0; + uint32_t first_timestamp; + uint32_t EndOfTransmissionTimestamp; for (;;) { - if(i >= TRACE_BUFFER_SIZE) { - break; - } - - bool isResponse; - timestamp = *((uint32_t *)(got+i)); - if (timestamp & 0x80000000) { - timestamp &= 0x7fffffff; - isResponse = true; - } else { - isResponse = false; - } - - if(i==0) { + + if( tracepos >= TRACE_BUFFER_SIZE) break; + + timestamp = *((uint32_t *)(trace + tracepos)); + if(tracepos == 0) { first_timestamp = timestamp; } - - int parityBits = *((uint32_t *)(got+i+4)); + tracepos += 4; + duration = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + data_len = *((uint16_t *)(trace + tracepos)); + tracepos += 2; - int len = got[i+8]; - - if (len > 100) { - break; - } - if (i + len >= TRACE_BUFFER_SIZE) { - break; + if (data_len & 0x8000) { + data_len &= 0x7fff; + isResponse = true; + } else { + isResponse = false; } - uint8_t *frame = (got+i+9); + parity_len = (data_len-1)/8 + 1; + + + if (tracepos + data_len + parity_len >= TRACE_BUFFER_SIZE) { break; } + + uint8_t *frame = trace + tracepos; + tracepos += data_len; + uint8_t *parityBytes = trace + tracepos; + tracepos += parity_len; // Break and stick with current result if buffer was not completely full - if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break; + if (timestamp == 0x44444444) break; char line[1000] = ""; int j; - if (len) { - for (j = 0; j < len; j++) { - int oddparity = 0x01; - int k; + for (j = 0; j < data_len; j++) { + int oddparity = 0x01; + int k; - for (k=0;k<8;k++) { - oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); - } - - //if((parityBits >> (len - j - 1)) & 0x01) { - if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } else { - sprintf(line+(j*4), "%02x ", frame[j]); - } + for (k=0;k<8;k++) { + oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); } - } else { - if (ShowWaitCycles) { - uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff; - sprintf(line, "fdt (Frame Delay Time): %d", (next_timestamp - timestamp)); + + uint8_t parityBits = parityBytes[j>>3]; + if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + sprintf(line+(j*4), "%02x! ", frame[j]); + } else { + sprintf(line+(j*4), "%02x ", frame[j]); } } - - char *crc; - crc = ""; - if (len > 2) { + + char crc[6] = ""; + if (data_len > 2) { uint8_t b1, b2; - for (j = 0; j < (len - 1); j++) { - // gives problems... search for the reason.. - /*if(frame[j] == 0xAA) { - switch(frame[j+1]) { - case 0x01: - crc = "[1] Two drops close after each other"; - break; - case 0x02: - crc = "[2] Potential SOC with a drop in second half of bitperiod"; - break; - case 0x03: - crc = "[3] Segment Z after segment X is not possible"; - break; - case 0x04: - crc = "[4] Parity bit of a fully received byte was wrong"; - break; - default: - crc = "[?] Unknown error"; - break; - } - break; - }*/ + ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); + if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { + sprintf(crc, (isResponse & (data_len < 6)) ? "" : " !crc"); + } else { + sprintf(crc, ""); } - - if (strlen(crc)==0) { - ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2); - if (b1 != frame[len-2] || b2 != frame[len-1]) { - crc = (isResponse & (len < 6)) ? "" : " !crc"; - } else { - crc = ""; - } - } - } else { - crc = ""; // SHORT - } - - i += (len + 9); - - EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff; - if (!ShowWaitCycles) i += 9; + EndOfTransmissionTimestamp = timestamp + duration; PrintAndLog(" %9d | %9d | %s | %s %s", (timestamp - first_timestamp), (EndOfTransmissionTimestamp - first_timestamp), - (len?(isResponse ? "Tag" : "Rdr"):" "), - line, crc); - + (isResponse ? "Tag" : "Rdr"), + line, + crc); + + bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; + if (ShowWaitCycles && !isResponse && next_isResponse) { + uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); + if (next_timestamp != 0x44444444) { + PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", + (EndOfTransmissionTimestamp - first_timestamp), + (next_timestamp - first_timestamp), + " ", + (next_timestamp - EndOfTransmissionTimestamp)); + } + } + } } return 0; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 7bbf26b2..370b36e9 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -302,7 +302,7 @@ int CmdHFiClassSnoop(const char *Cmd) SendCommand(&c); return 0; } - +#define NUM_CSNS 15 int CmdHFiClassSim(const char *Cmd) { uint8_t simType = 0; @@ -339,20 +339,27 @@ int CmdHFiClassSim(const char *Cmd) if(simType == 2) { - UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,63}}; + UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,NUM_CSNS}}; UsbCommand resp = {0}; - uint8_t csns[64] = { - 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 , - 0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 , - 0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 , - 0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 , - 0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 , - 0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 , - 0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 , - 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 }; - - memcpy(c.d.asBytes, csns, 64); + uint8_t csns[8*NUM_CSNS] = { + 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 }; + + memcpy(c.d.asBytes, csns, 8*NUM_CSNS); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK, &resp, -1)) { @@ -361,9 +368,9 @@ int CmdHFiClassSim(const char *Cmd) } uint8_t num_mac_responses = resp.arg[1]; - PrintAndLog("Mac responses: %d MACs obtained (should be 8)", num_mac_responses); + PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses, NUM_CSNS); - size_t datalen = 8*24; + size_t datalen = NUM_CSNS*24; /* * Now, time to dump to file. We'll use this format: * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>.... @@ -377,7 +384,7 @@ int CmdHFiClassSim(const char *Cmd) void* dump = malloc(datalen); memset(dump,0,datalen);//<-- Need zeroes for the CC-field uint8_t i = 0; - for(i = 0 ; i < 8 ; i++) + for(i = 0 ; i < NUM_CSNS ; i++) { memcpy(dump+i*24, csns+i*8,8); //CSN //8 zero bytes here... diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 54d0f4f1..c28563e2 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -2020,7 +2020,6 @@ int CmdHF14AMfSniff(const char *Cmd){ uint8_t atqa[2]; uint8_t sak; bool isTag; - uint32_t parity; uint8_t buf[3000]; uint8_t * bufPtr = buf; memset(buf, 0x00, 3000); @@ -2087,14 +2086,19 @@ int CmdHF14AMfSniff(const char *Cmd){ printf(">\n"); PrintAndLog("received trace len: %d packages: %d", blockLen, pckNum); num = 0; - while (bufPtr - buf + 9 < blockLen) { - isTag = bufPtr[3] & 0x80 ? true:false; - bufPtr += 4; - parity = *((uint32_t *)(bufPtr)); - bufPtr += 4; - len = bufPtr[0]; - bufPtr++; - if ((len == 14) && (bufPtr[0] == 0xff) && (bufPtr[1] == 0xff)) { + while (bufPtr - buf < blockLen) { + bufPtr += 6; + len = *((uint16_t *)bufPtr); + + if(len & 0x8000) { + isTag = true; + len &= 0x7fff; + } else { + isTag = false; + } + bufPtr += 2; + if ((len == 14) && (bufPtr[0] == 0xff) && (bufPtr[1] == 0xff) && (bufPtr[12] == 0xff) && (bufPtr[13] == 0xff)) { + memcpy(uid, bufPtr + 2, 7); memcpy(atqa, bufPtr + 2 + 7, 2); uid_len = (atqa[0] & 0xC0) == 0x40 ? 7 : 4; @@ -2116,9 +2120,10 @@ int CmdHF14AMfSniff(const char *Cmd){ if (wantLogToFile) AddLogHex(logHexFileName, isTag ? "TAG: ":"RDR: ", bufPtr, len); if (wantDecrypt) - mfTraceDecode(bufPtr, len, parity, wantSaveToEmlFile); + mfTraceDecode(bufPtr, len, wantSaveToEmlFile); } bufPtr += len; + bufPtr += ((len-1)/8+1); // ignore parity num++; } } diff --git a/client/cmdlf.c b/client/cmdlf.c index da74f97f..132a4c5f 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -268,7 +268,7 @@ int CmdIndalaDemod(const char *Cmd) PrintAndLog("UID=%s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7); } - // Checking UID against next occurences + // Checking UID against next occurrences for (; i + uidlen <= rawbit;) { int failed = 0; for (bit = 0; bit < uidlen; bit++) { @@ -282,7 +282,7 @@ int CmdIndalaDemod(const char *Cmd) } times += 1; } - PrintAndLog("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen); + PrintAndLog("Occurrences: %d (expected %d)", times, (rawbit - start) / uidlen); // Remodulating for tag cloning GraphTraceLen = 32*uidlen; @@ -390,7 +390,8 @@ static void ChkBitstream(const char *str) int CmdLFSim(const char *Cmd) { - int i; + int i,j; + static int gap; sscanf(Cmd, "%i", &gap); @@ -398,10 +399,10 @@ int CmdLFSim(const char *Cmd) /* convert to bitstream if necessary */ ChkBitstream(Cmd); - PrintAndLog("Sending [%d bytes]", GraphTraceLen); + 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}}; - int j; + for (j = 0; j < USB_CMD_DATA_SIZE; j++) { c.d.asBytes[j] = GraphBuffer[i+j]; } @@ -569,7 +570,7 @@ static command_t CommandTable[] = {"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, 1, " ['l']-- Clone Indala to T55x7 (UID in HEX)(option 'l' for 224 UID"}, + {"indalaclone", CmdIndalaClone, 0, " ['l']-- Clone Indala to T55x7 (UID in HEX)(option 'l' for 224 UID"}, {"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"}, diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 8c6461df..c5f57d55 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -202,9 +202,9 @@ int CmdEM410xSim(const char *Cmd) uint8_t uid[5] = {0x00}; if (cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: lf em4x sim "); + PrintAndLog("Usage: lf em4x 410xsim "); PrintAndLog(""); - PrintAndLog(" sample: lf em4x sim 0F0368568B"); + PrintAndLog(" sample: lf em4x 410xsim 0F0368568B"); return 0; } @@ -258,14 +258,9 @@ int CmdEM410xSim(const char *Cmd) AppendGraph(0, clock, parity[3]); /* stop bit */ - AppendGraph(0, clock, 0); + AppendGraph(1, clock, 0); - //CmdManchesterMod("64"); - - /* booyah! */ - RepaintGraphWindow(); - - CmdLFSim(""); + CmdLFSim("240"); //240 start_gap. return 0; } diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 9dd11f18..ce21ddc8 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -39,9 +39,12 @@ int CmdHIDDemod(const char *Cmd) int CmdHIDDemodFSK(const char *Cmd) { - UsbCommand c={CMD_HID_DEMOD_FSK}; - SendCommand(&c); - return 0; + int findone = 0; + if(Cmd[0]=='1') findone=1; + UsbCommand c = {CMD_HID_DEMOD_FSK}; + c.arg[0]=findone; + SendCommand(&c); + return 0; } int CmdHIDSim(const char *Cmd) @@ -103,9 +106,9 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"demod", CmdHIDDemod, 1, "Demodulate HID Prox Card II (not optimal)"}, - {"fskdemod", CmdHIDDemodFSK, 1, "Realtime HID FSK demodulator"}, - {"sim", CmdHIDSim, 1, " -- HID tag simulator"}, - {"clone", CmdHIDClone, 1, " ['l'] -- Clone HID to T55x7 (tag must be in antenna)(option 'l' for 84bit ID)"}, + {"fskdemod", CmdHIDDemodFSK, 0, "['1'] Realtime HID FSK demodulator (option '1' for one tag only)"}, + {"sim", CmdHIDSim, 0, " -- HID tag simulator"}, + {"clone", CmdHIDClone, 0, " ['l'] -- Clone HID to T55x7 (tag must be in antenna)(option 'l' for 84bit ID)"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 9a228b2b..6d1cb87d 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -39,9 +39,21 @@ int CmdLFHitagList(const char *Cmd) int i = 0; int prev = -1; + int len = strlen(Cmd); - char filename[256]; + char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf = NULL; + + if (len > FILE_PATH_SIZE) + len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); + + if (strlen(filename) > 0) { + if ((pf = fopen(filename,"wb")) == NULL) { + PrintAndLog("Error: Could not open file [%s]",filename); + return 1; + } + } for (;;) { @@ -116,8 +128,8 @@ int CmdLFHitagList(const char *Cmd) } if (pf) { - PrintAndLog("Recorded activity succesfully written to file: %s", filename); fclose(pf); + PrintAndLog("Recorded activity succesfully written to file: %s", filename); } return 0; @@ -135,9 +147,7 @@ int CmdLFHitagSim(const char *Cmd) { char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf; bool tag_mem_supplied; - int len = 0; - - len = strlen(Cmd); + int len = strlen(Cmd); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd, len); @@ -148,7 +158,7 @@ int CmdLFHitagSim(const char *Cmd) { } tag_mem_supplied = true; if (fread(c.d.asBytes,48,1,pf) == 0) { - PrintAndLog("Error: File reading error"); + PrintAndLog("Error: File reading error"); return 1; } fclose(pf); @@ -234,11 +244,11 @@ int CmdLFHitagReader(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"list", CmdLFHitagList, 1, "List Hitag trace history"}, + {"list", CmdLFHitagList, 1, " List Hitag trace history"}, {"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"}, - {"sim", CmdLFHitagSim, 1, "Simulate Hitag transponder"}, + {"sim", CmdLFHitagSim, 1, " Simulate Hitag transponder"}, {"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; int CmdLFHitag(const char *Cmd) diff --git a/client/cmdlfio.c b/client/cmdlfio.c index 919fa442..78d8fa21 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -16,9 +16,13 @@ static int CmdHelp(const char *Cmd); int CmdIODemodFSK(const char *Cmd) { - UsbCommand c={CMD_IO_DEMOD_FSK}; - SendCommand(&c); - return 0; + int findone = 0; + if (Cmd[0] =='1') findone = 1; + + UsbCommand c={CMD_IO_DEMOD_FSK}; + c.arg[0] = findone; + SendCommand(&c); + return 0; } int CmdIOProxDemod(const char *Cmd){ @@ -64,8 +68,8 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"demod", CmdIOProxDemod, 1, "Demodulate Stream"}, - {"fskdemod", CmdIODemodFSK, 1, "Demodulate ioProx Tag"}, - {"clone", CmdIOClone, 1, "Clone ioProx Tag"}, + {"fskdemod", CmdIODemodFSK, 0, "['1'] Realtime IO FSK demodulator (option '1' for one tag only)"}, + {"clone", CmdIOClone, 0, "Clone ioProx Tag"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 513eb0ef..78d90e7c 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -46,18 +46,17 @@ int CmdReadBlk(const char *Cmd) SendCommand(&c); WaitForResponse(CMD_ACK, NULL); -// uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; + uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - // GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. - // WaitForResponseTimeout(CMD_ACK,NULL, 1500); + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); - // for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - // GraphBuffer[j] = (int)data[j]; - // } - // GraphTraceLen = LF_TRACE_BUFF_SIZE; - CmdSamples("12000"); + for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { + GraphBuffer[j] = (int)data[j]; + } + GraphTraceLen = LF_TRACE_BUFF_SIZE; ManchesterDemod(block); - // RepaintGraphWindow(); + RepaintGraphWindow(); return 0; } @@ -321,7 +320,7 @@ int CmdDump(const char *Cmd){ return 0; } } - + for ( int i = 0; i <8; ++i){ memset(s,0,sizeof(s)); if ( hasPwd ) { @@ -352,6 +351,7 @@ int ManchesterDemod(int blockNum){ if (!HasGraphData()) return 0; uint8_t sizebyte = 32; + // the value 5 was selected during empirical studies of the decoded data. Some signal noise to skip. uint8_t offset = 5; uint32_t blockData; uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; diff --git a/client/cmdmain.c b/client/cmdmain.c index d84d96ef..0641f9c8 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -198,10 +198,9 @@ void UsbCommandReceived(UsbCommand *UC) switch(UC->cmd) { // First check if we are handling a debug message case CMD_DEBUG_PRINT_STRING: { - char s[USB_CMD_DATA_SIZE+1]; + char s[USB_CMD_DATA_SIZE+1] = {0x00}; size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); memcpy(s,UC->d.asBytes,len); - s[len] = 0x00; PrintAndLog("#db# %s ", s); return; } break; diff --git a/client/flash.c b/client/flash.c index 60c04adc..7976d410 100644 --- a/client/flash.c +++ b/client/flash.c @@ -275,8 +275,7 @@ static int get_proxmark_state(uint32_t *state) { UsbCommand c; c.cmd = CMD_DEVICE_INFO; -// SendCommand_(&c); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; ReceiveCommand(&resp); @@ -390,7 +389,6 @@ int flash_start_flashing(int enable_bl_writes,char *serial_port_name) c.arg[2] = 0; } SendCommand(&c); -// SendCommand_(&c); return wait_for_ack(); } else { fprintf(stderr, "Note: Your bootloader does not understand the new START_FLASH command\n"); @@ -406,25 +404,11 @@ static int write_block(uint32_t address, uint8_t *data, uint32_t length) memset(block_buf, 0xFF, BLOCK_SIZE); memcpy(block_buf, data, length); - UsbCommand c; -/* - c.cmd = {CMD_SETUP_WRITE}; - for (int i = 0; i < 240; i += 48) { - memcpy(c.d.asBytes, block_buf + i, 48); - c.arg[0] = i / 4; - SendCommand(&c); -// SendCommand_(&c); - if (wait_for_ack() < 0) { - return -1; - } - } -*/ + UsbCommand c; c.cmd = CMD_FINISH_WRITE; c.arg[0] = address; -// memcpy(c.d.asBytes, block_buf+240, 16); -// SendCommand_(&c); memcpy(c.d.asBytes, block_buf, length); - SendCommand(&c); + SendCommand(&c); return wait_for_ack(); } @@ -485,8 +469,7 @@ void flash_free(flash_file_t *ctx) // just reset the unit int flash_stop_flashing(void) { UsbCommand c = {CMD_HARDWARE_RESET}; -// SendCommand_(&c); - SendCommand(&c); - msleep(100); - return 0; + SendCommand(&c); + msleep(100); + return 0; } diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index 6d990171..deab3137 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -56,7 +56,7 @@ int fileExists(const char *filename) { int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen) { - int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5); + int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+10); char * fileName = malloc(size); memset(fileName,0,size); @@ -70,14 +70,14 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si /* We should have a valid filename now, e.g. dumpdata-3.bin */ /*Opening file for writing in binary mode*/ - FILE *fileHandle=fopen(fileName,"wb"); - if(!fileHandle) { - prnlog("Failed to write to file '%s'", fileName); + FILE *fh=fopen(fileName,"wb"); + if(!fh) { + PrintAndLog("Failed to write to file '%s'", fileName); return 1; } - fwrite(data, 1, datalen, fileHandle); - fclose(fileHandle); - prnlog("Saved data to '%s'", fileName); + fwrite(data, 1, datalen, fh); + fclose(fh); + PrintAndLog("Saved data to '%s'", fileName); free(fileName); return 0; @@ -87,7 +87,7 @@ int loadFile(const char *fileName, void* data, size_t datalen) { FILE *filehandle = fopen(fileName, "rb"); if(!filehandle) { - prnlog("Failed to read from file '%s'", fileName); + PrintAndLog("Failed to read from file '%s'", fileName); return 1; } fread(data,datalen,1,filehandle); diff --git a/client/mifarehost.c b/client/mifarehost.c index 358799cb..88745195 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -231,7 +231,7 @@ int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { // "MAGIC" CARD -int mfCSetUID(uint8_t *uid, uint8_t *oldUID, int wantWipe) { +int mfCSetUID(uint8_t *uid, uint8_t *oldUID, bool wantWipe) { uint8_t block0[16]; memset(block0, 0, 16); memcpy(block0, uid, 4); @@ -244,7 +244,7 @@ int mfCSetUID(uint8_t *uid, uint8_t *oldUID, int wantWipe) { return mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER); } -int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, int wantWipe, uint8_t params) { +int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params) { uint8_t isOK = 0; UsbCommand c = {CMD_MIFARE_EML_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}}; @@ -303,12 +303,9 @@ uint32_t ks3; uint32_t uid; // serial number uint32_t nt; // tag challenge -uint32_t nt_par; uint32_t nr_enc; // encrypted reader challenge uint32_t ar_enc; // encrypted reader response -uint32_t nr_ar_par; uint32_t at_enc; // encrypted tag response -uint32_t at_par; int isTraceCardEmpty(void) { return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0)); @@ -415,7 +412,7 @@ void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool i } -int mfTraceDecode(uint8_t *data_src, int len, uint32_t parity, bool wantSaveToEmlFile) { +int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { uint8_t data[64]; if (traceState == TRACE_ERROR) return 1; @@ -516,9 +513,7 @@ int mfTraceDecode(uint8_t *data_src, int len, uint32_t parity, bool wantSaveToEm case TRACE_AUTH1: if (len == 4) { traceState = TRACE_AUTH2; - nt = bytes_to_num(data, 4); - nt_par = parity; return 0; } else { traceState = TRACE_ERROR; @@ -532,7 +527,6 @@ int mfTraceDecode(uint8_t *data_src, int len, uint32_t parity, bool wantSaveToEm nr_enc = bytes_to_num(data, 4); ar_enc = bytes_to_num(data + 4, 4); - nr_ar_par = parity; return 0; } else { traceState = TRACE_ERROR; @@ -545,7 +539,6 @@ int mfTraceDecode(uint8_t *data_src, int len, uint32_t parity, bool wantSaveToEm traceState = TRACE_IDLE; at_enc = bytes_to_num(data, 4); - at_par = parity; // decode key here) ks2 = ar_enc ^ prng_successor(nt, 64); diff --git a/client/mifarehost.h b/client/mifarehost.h index f21b9139..3e946cd9 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -55,12 +55,12 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * key int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); -int mfCSetUID(uint8_t *uid, uint8_t *oldUID, int wantWipe); -int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, int wantWipe, uint8_t params); +int mfCSetUID(uint8_t *uid, uint8_t *oldUID, bool wantWipe); +int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params); int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile); -int mfTraceDecode(uint8_t *data_src, int len, uint32_t parity, bool wantSaveToEmlFile); +int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile); int isTraceCardEmpty(void); int isBlockEmpty(int blockN); From d3499d369d191057fea1335c4e50e907c6a9369f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Dec 2014 22:26:16 +0100 Subject: [PATCH 45/78] minor fixes regaring the newly released patches from the pm3 community plus removed old comments in cmdmain.c --- armsrc/appmain.c | 23 ++---- armsrc/iso14443a.c | 78 +++++++++---------- client/cmddata.c | 56 +++++++++++--- client/cmdhf14a.c | 172 +++++++++++++++++++++++++++--------------- client/cmdhfmfu.c | 28 +++---- client/cmdhw.c | 18 +---- client/cmdmain.c | 181 +++++++++++---------------------------------- 7 files changed, 256 insertions(+), 300 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 2ee234fb..c3cf3999 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -169,13 +169,11 @@ int AvgAdc(int ch) // was static - merlok void MeasureAntennaTuning(void) { - uint8_t *dest = (uint8_t *)BigBuf + FREE_BUFFER_OFFSET; + uint8_t LF_Results[256]; int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0 int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV LED_B_ON(); - DbpString("Measuring antenna characteristics, please wait..."); - memset(dest,0,FREE_BUFFER_SIZE); /* * Sweeps the useful LF range of the proxmark from @@ -188,7 +186,7 @@ void MeasureAntennaTuning(void) FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - for (i=255; i>19; i--) { + for (i=255; i>=19; i--) { WDT_HIT(); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); SpinDelay(20); @@ -198,15 +196,17 @@ void MeasureAntennaTuning(void) if (i==95) vLf125 = adcval; // voltage at 125Khz if (i==89) vLf134 = adcval; // voltage at 134Khz - dest[i] = adcval>>8; // scale int to fit in byte for graphing purposes - if(dest[i] > peak) { + LF_Results[i] = adcval>>8; // scale int to fit in byte for graphing purposes + if(LF_Results[i] > peak) { peakv = adcval; - peak = dest[i]; + peak = LF_Results[i]; peakf = i; //ptr = i; } } + for (i=18; i >= 0; i--) LF_Results[i] = 0; + LED_A_ON(); // Let the FPGA drive the high-frequency antenna around 13.56 MHz. FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -216,14 +216,7 @@ void MeasureAntennaTuning(void) // can measure voltages up to 33000 mV vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10; -// c.cmd = CMD_MEASURED_ANTENNA_TUNING; -// c.arg[0] = (vLf125 << 0) | (vLf134 << 16); -// c.arg[1] = vHf; -// c.arg[2] = peakf | (peakv << 16); - - DbpString("Measuring complete, sending report back to host"); - cmd_send(CMD_MEASURED_ANTENNA_TUNING,vLf125|(vLf134<<16),vHf,peakf|(peakv<<16),0,0); -// UsbSendPacket((uint8_t *)&c, sizeof(c)); + 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(); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index aed6a1fe..7dfa53e7 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1714,7 +1714,7 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) * fills the uid pointer unless NULL * fills resp_data unless NULL */ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { - uint8_t halt[] = { 0x50 }; // HALT + //uint8_t halt[] = { 0x50 }; // HALT uint8_t wupa[] = { 0x52 }; // WAKE-UP //uint8_t reqa[] = { 0x26 }; // REQUEST A uint8_t sel_all[] = { 0x93,0x20 }; @@ -1725,30 +1725,29 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u byte_t uid_resp[4]; size_t uid_resp_len; - - uint8_t sak = 0x04; // cascade uid - int cascade_level = 0; - int len; + uint8_t sak = 0x04; // cascade uid + int cascade_level = 0; + int len; - ReaderTransmit(halt,sizeof(halt), NULL); + // test for the SKYLANDERS TOY. + //ReaderTransmit(halt,sizeof(halt), NULL); - // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitBitsPar(wupa,7,0, NULL); + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field + ReaderTransmitBitsPar(wupa,7,0, NULL); - // Receive the ATQA - if(!ReaderReceive(resp, resp_par)) return 0; - // Dbprintf("atqa: %02x %02x",resp[0],resp[1]); + // Receive the ATQA + if(!ReaderReceive(resp, resp_par)) return 0; + + if(p_hi14a_card) { + memcpy(p_hi14a_card->atqa, resp, 2); + p_hi14a_card->uidlen = 0; + memset(p_hi14a_card->uid,0,10); + } - if(p_hi14a_card) { - memcpy(p_hi14a_card->atqa, resp, 2); - p_hi14a_card->uidlen = 0; - memset(p_hi14a_card->uid,0,10); - } - - // clear uid - if (uid_ptr) { - memset(uid_ptr,0,10); - } + // clear uid + if (uid_ptr) { + memset(uid_ptr,0,10); + } // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in // which case we need to make a cascade 2 request and select - this is a long UID @@ -1794,7 +1793,6 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u } uid_resp_len = 4; - // calculate crypto UID. Always use last 4 Bytes. if(cuid_ptr) { *cuid_ptr = bytes_to_num(uid_resp, 4); @@ -1811,17 +1809,11 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u if (!ReaderReceive(resp, resp_par)) return 0; sak = resp[0]; - //Dbprintf("SAK: %02x",resp[0]); - // Test if more parts of the uid are comming + // Test if more parts of the uid are coming if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: // http://www.nxp.com/documents/application_note/AN10927.pdf - // This was earlier: - //memcpy(uid_resp, uid_resp + 1, 3); - // But memcpy should not be used for overlapping arrays, - // and memmove appears to not be available in the arm build. - // Therefore: uid_resp[0] = uid_resp[1]; uid_resp[1] = uid_resp[2]; uid_resp[2] = uid_resp[3]; @@ -1844,24 +1836,24 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u p_hi14a_card->ats_len = 0; } - if( (sak & 0x20) == 0) { - return 2; // non iso14443a compliant tag - } + if( (sak & 0x20) == 0) { + return 2; // non iso14443a compliant tag + } - // Request for answer to select - AppendCrc14443a(rats, 2); - ReaderTransmit(rats, sizeof(rats), NULL); + // Request for answer to select + AppendCrc14443a(rats, 2); + ReaderTransmit(rats, sizeof(rats), NULL); - if (!(len = ReaderReceive(resp,resp_par))) return 0; + if (!(len = ReaderReceive(resp, resp_par))) return 2; - if(p_hi14a_card) { - memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); - p_hi14a_card->ats_len = len; - } + if(p_hi14a_card) { + memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); + p_hi14a_card->ats_len = len; + } - // reset the PCB block number - iso14_pcb_blocknum = 0; - return 1; + // reset the PCB block number + iso14_pcb_blocknum = 0; + return 1; } void iso14443a_setup(uint8_t fpga_minor_mode) { diff --git a/client/cmddata.c b/client/cmddata.c index a1a0d484..0ba04b79 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -477,20 +477,52 @@ int CmdSamples(const char *Cmd) } int CmdTuneSamples(const char *Cmd) { - int cnt = 0; - int n = 255; - uint8_t got[255] = {0x00}; + int timeout = 0; + printf("\nMeasuring antenna characteristics, please wait..."); - PrintAndLog("Reading %d samples\n", n); - GetFromBigBuf(got,n,7256); // armsrc/apps.h: #define FREE_BUFFER_OFFSET 7256 - WaitForResponse(CMD_ACK,NULL); - for (int j = 0; j < n; j++) { - GraphBuffer[cnt++] = ((int)got[j]) - 128; - } + UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING}; + SendCommand(&c); + + UsbCommand resp; + while(!WaitForResponseTimeout(CMD_MEASURED_ANTENNA_TUNING,&resp,1000)) { + timeout++; + printf("."); + if (timeout > 7) { + PrintAndLog("\nNo response from Proxmark. Aborting..."); + return 1; + } + } + + int peakv, peakf; + int vLf125, vLf134, vHf; + vLf125 = resp.arg[0] & 0xffff; + vLf134 = resp.arg[0] >> 16; + vHf = resp.arg[1] & 0xffff;; + peakf = resp.arg[2] & 0xffff; + peakv = resp.arg[2] >> 16; + PrintAndLog(""); + PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0); + PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0); + PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1)); + PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0); + if (peakv<2000) + PrintAndLog("# Your LF antenna is unusable."); + else if (peakv<10000) + PrintAndLog("# Your LF antenna is marginal."); + if (vHf<2000) + PrintAndLog("# Your HF antenna is unusable."); + else if (vHf<5000) + PrintAndLog("# Your HF antenna is marginal."); + + for (int i = 0; i < 256; i++) { + GraphBuffer[i] = resp.d.asBytes[i] - 128; + } - PrintAndLog("Done! Divisor 89 is 134khz, 95 is 125khz.\n"); - GraphTraceLen = n; - RepaintGraphWindow(); + PrintAndLog("Done! Divisor 89 is 134khz, 95 is 125khz.\n"); + PrintAndLog("\n"); + GraphTraceLen = 256; + ShowGraphWindow(); + return 0; } diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index d1d440ee..46720d44 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -44,8 +44,11 @@ int CmdHF14AList(const char *Cmd) ShowWaitCycles = true; } - uint8_t trace[TRACE_BUFFER_SIZE]; - GetFromBigBuf(trace,TRACE_BUFFER_SIZE,0); +// for the time being. Need better Bigbuf handling. +#define TRACE_SIZE 3000 + + uint8_t trace[TRACE_SIZE]; + GetFromBigBuf(trace, TRACE_SIZE, 0); WaitForResponse(CMD_ACK,NULL); PrintAndLog("Recorded Activity"); @@ -67,7 +70,9 @@ int CmdHF14AList(const char *Cmd) for (;;) { - if( tracepos >= TRACE_BUFFER_SIZE) break; + if(tracepos >= TRACE_SIZE) { + break; + } timestamp = *((uint32_t *)(trace + tracepos)); if(tracepos == 0) { @@ -88,8 +93,9 @@ int CmdHF14AList(const char *Cmd) parity_len = (data_len-1)/8 + 1; - - if (tracepos + data_len + parity_len >= TRACE_BUFFER_SIZE) { break; } + if (tracepos + data_len + parity_len >= TRACE_SIZE) { + break; + } uint8_t *frame = trace + tracepos; tracepos += data_len; @@ -126,6 +132,7 @@ int CmdHF14AList(const char *Cmd) } else { sprintf(crc, ""); } + } EndOfTransmissionTimestamp = timestamp + duration; @@ -137,6 +144,7 @@ int CmdHF14AList(const char *Cmd) crc); bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; + if (ShowWaitCycles && !isResponse && next_isResponse) { uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); if (next_timestamp != 0x44444444) { @@ -147,8 +155,9 @@ int CmdHF14AList(const char *Cmd) (next_timestamp - EndOfTransmissionTimestamp)); } } - } + } + return 0; } @@ -159,26 +168,30 @@ void iso14a_set_timeout(uint32_t timeout) { int CmdHF14AReader(const char *Cmd) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; + //UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT , 0, 0}}; SendCommand(&c); UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes; + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - if(resp.arg[0] == 0) { + uint64_t 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"); return 0; } - PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]); - PrintAndLog(" UID : %s", sprint_hex(card->uid, card->uidlen)); - PrintAndLog(" SAK : %02x [%d]", card->sak, resp.arg[0]); + PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); - switch (card->sak) { + switch (card.sak) { case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break; - case 0x01: PrintAndLog("TYPE : NXP TNP3xxx Activision Game Appliance"); break; + case 0x01: PrintAndLog("TYPE : NXP TNP3xxx Activision Game Appliance"); break; case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break; case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break; case 0x09: PrintAndLog("TYPE : NXP MIFARE Mini 0.3k"); break; @@ -193,67 +206,107 @@ int CmdHF14AReader(const char *Cmd) case 0x98: PrintAndLog("TYPE : Gemplus MPCOS"); break; default: ; } - if(resp.arg[0] == 1) { + + + // 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 + c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT; + c.arg[1] = 2; + c.arg[2] = 0; + memcpy(c.d.asBytes, rats, 2); + SendCommand(&c); + WaitForResponse(CMD_ACK,&resp); + + memcpy(&card.ats, resp.d.asBytes, resp.arg[0]); + card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes + } + + // disconnect + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); + + + if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes bool ta1 = 0, tb1 = 0, tc1 = 0; int pos; - PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len)); - if (card->ats_len > 0) { - PrintAndLog(" - TL : length is %d bytes", card->ats[0]); + if (select_status == 2) { + PrintAndLog("SAK incorrectly claims that card doesn't support RATS"); } - if (card->ats_len > 1) { - ta1 = (card->ats[1] & 0x10) == 0x10; - tb1 = (card->ats[1] & 0x20) == 0x20; - tc1 = (card->ats[1] & 0x40) == 0x40; + PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len)); + PrintAndLog(" - TL : length is %d bytes", card.ats[0]); + if (card.ats[0] != card.ats_len - 2) { + PrintAndLog("ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); + } + + if (card.ats[0] > 1) { // there is a format byte (T0) + ta1 = (card.ats[1] & 0x10) == 0x10; + tb1 = (card.ats[1] & 0x20) == 0x20; + tc1 = (card.ats[1] & 0x40) == 0x40; + int16_t fsci = card.ats[1] & 0x0f; PrintAndLog(" - T0 : TA1 is%s present, TB1 is%s present, " - "TC1 is%s present, FSCI is %d", + "TC1 is%s present, FSCI is %d (FSC = %ld)", (ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"), - (card->ats[1] & 0x0f)); + fsci, + fsci < 5 ? (fsci - 2) * 8 : + fsci < 8 ? (fsci - 3) * 32 : + fsci == 8 ? 256 : + -1 + ); } pos = 2; - if (ta1 && card->ats_len > pos) { + if (ta1) { char dr[16], ds[16]; dr[0] = ds[0] = '\0'; - if (card->ats[pos] & 0x10) strcat(ds, "2, "); - if (card->ats[pos] & 0x20) strcat(ds, "4, "); - if (card->ats[pos] & 0x40) strcat(ds, "8, "); - if (card->ats[pos] & 0x01) strcat(dr, "2, "); - if (card->ats[pos] & 0x02) strcat(dr, "4, "); - if (card->ats[pos] & 0x04) strcat(dr, "8, "); + if (card.ats[pos] & 0x10) strcat(ds, "2, "); + if (card.ats[pos] & 0x20) strcat(ds, "4, "); + if (card.ats[pos] & 0x40) strcat(ds, "8, "); + if (card.ats[pos] & 0x01) strcat(dr, "2, "); + if (card.ats[pos] & 0x02) strcat(dr, "4, "); + if (card.ats[pos] & 0x04) strcat(dr, "8, "); if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; PrintAndLog(" - TA1 : different divisors are%s supported, " "DR: [%s], DS: [%s]", - (card->ats[pos] & 0x80 ? " NOT" : ""), dr, ds); + (card.ats[pos] & 0x80 ? " NOT" : ""), dr, ds); pos++; } - if (tb1 && card->ats_len > pos) { - PrintAndLog(" - TB1 : SFGI = %d, FWI = %d", - (card->ats[pos] & 0x08), - (card->ats[pos] & 0x80) >> 4); + if (tb1) { + uint32_t sfgi = card.ats[pos] & 0x0F; + uint32_t fwi = card.ats[pos] >> 4; + PrintAndLog(" - TB1 : SFGI = %d (SFGT = %s%ld/fc), FWI = %d (FWT = %ld/fc)", + (sfgi), + sfgi ? "" : "(not needed) ", + sfgi ? (1 << 12) << sfgi : 0, + fwi, + (1 << 12) << fwi + ); pos++; } - if (tc1 && card->ats_len > pos) { + if (tc1) { PrintAndLog(" - TC1 : NAD is%s supported, CID is%s supported", - (card->ats[pos] & 0x01) ? "" : " NOT", - (card->ats[pos] & 0x02) ? "" : " NOT"); + (card.ats[pos] & 0x01) ? "" : " NOT", + (card.ats[pos] & 0x02) ? "" : " NOT"); pos++; } - if (card->ats_len > pos) { + if (card.ats[0] > pos) { char *tip = ""; - if (card->ats_len - pos > 7) { - if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + if (card.ats[0] - pos >= 7) { + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { tip = "-> MIFARE Plus X 2K or 4K"; - } else if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { tip = "-> MIFARE Plus S 2K or 4K"; } } - PrintAndLog(" - HB : %s%s", sprint_hex(card->ats + pos, card->ats_len - pos - 2), tip); - if (card->ats[pos] == 0xC1) { + PrintAndLog(" - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); + if (card.ats[pos] == 0xC1) { PrintAndLog(" c1 -> Mifare or (multiple) virtual cards of various type"); PrintAndLog(" %02x -> Length is %d bytes", - card->ats[pos + 1], card->ats[pos + 1]); - switch (card->ats[pos + 2] & 0xf0) { + card.ats[pos + 1], card.ats[pos + 1]); + switch (card.ats[pos + 2] & 0xf0) { case 0x10: PrintAndLog(" 1x -> MIFARE DESFire"); break; @@ -261,7 +314,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" 2x -> MIFARE Plus"); break; } - switch (card->ats[pos + 2] & 0x0f) { + switch (card.ats[pos + 2] & 0x0f) { case 0x00: PrintAndLog(" x0 -> <1 kByte"); break; @@ -278,7 +331,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" x0 -> 8 kByte"); break; } - switch (card->ats[pos + 3] & 0xf0) { + switch (card.ats[pos + 3] & 0xf0) { case 0x00: PrintAndLog(" 0x -> Engineering sample"); break; @@ -286,7 +339,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" 2x -> Released"); break; } - switch (card->ats[pos + 3] & 0x0f) { + switch (card.ats[pos + 3] & 0x0f) { case 0x00: PrintAndLog(" x0 -> Generation 1"); break; @@ -297,7 +350,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" x2 -> Generation 3"); break; } - switch (card->ats[pos + 4] & 0x0f) { + switch (card.ats[pos + 4] & 0x0f) { case 0x00: PrintAndLog(" x0 -> Only VCSL supported"); break; @@ -311,10 +364,10 @@ int CmdHF14AReader(const char *Cmd) } } } else { - PrintAndLog("proprietary non iso14443a-4 card found, RATS not supported"); + PrintAndLog("proprietary non iso14443-4 card found, RATS not supported"); } - return resp.arg[0]; + return select_status; } // Collect ISO14443 Type A UIDs @@ -336,20 +389,17 @@ int CmdHF14ACUIDs(const char *Cmd) UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - uint8_t *uid = resp.d.asBytes; - iso14a_card_select_t *card = (iso14a_card_select_t *)(uid + 12); + iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes; // check if command failed if (resp.arg[0] == 0) { PrintAndLog("Card select failed."); } else { - // check if UID is 4 bytes - if ((card->atqa[1] & 0xC0) == 0) { - PrintAndLog("%02X%02X%02X%02X", - *uid, *(uid + 1), *(uid + 2), *(uid + 3)); - } else { - PrintAndLog("UID longer than 4 bytes"); + char uid_string[20]; + for (uint16_t i = 0; i < card->uidlen; i++) { + sprintf(&uid_string[2*i], "%02X", card->uid[i]); } + PrintAndLog("%s", uid_string); } } PrintAndLog("End: %u", time(NULL)); diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index afe54bb4..52b7ad14 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -158,10 +158,11 @@ int CmdHF14AMfURdBl(const char *Cmd){ if (isOK) PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4)); else - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); + PrintAndLog("isOk:%02x", isOK); } + else { + PrintAndLog("Command execute timeout"); + } return 0; } @@ -171,7 +172,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ int CmdHF14AMfURdCard(const char *Cmd){ int i; uint8_t BlockNo = 0; - int Pages=16; + int pages=16; uint8_t *lockbytes_t=NULL; uint8_t lockbytes[2]={0x00}; bool bit[16]={0x00}; @@ -191,7 +192,7 @@ int CmdHF14AMfURdCard(const char *Cmd){ PrintAndLog("Dumping Ultralight Card Data..."); } PrintAndLog("Attempting to Read Ultralight... "); - UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo, Pages}}; + UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo, pages}}; SendCommand(&c); UsbCommand resp; @@ -231,7 +232,7 @@ int CmdHF14AMfURdCard(const char *Cmd){ PrintAndLog(" OneTimePad :%s ", sprint_hex(data + 3*4, 4)); PrintAndLog(""); - for (i = 0; i < Pages; i++) { + for (i = 0; i < pages; i++) { switch(i){ case 2: //process lock bytes @@ -634,7 +635,7 @@ int CmdHF14AMfUCRdCard(const char *Cmd){ if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { isOK = resp.arg[0] & 0xff; data = resp.d.asBytes; - //Pages=sizeof(data)/sizeof(data[0]); + PrintAndLog("isOk:%02x", isOK); if (isOK) for (i = 0; i < Pages; i++) { @@ -833,7 +834,7 @@ int CmdHF14AMfUCDump(const char *Cmd){ return 1; } PrintAndLog("Dumping Ultralight C Card Data..."); - PrintAndLog("Attempting to Read Ultralight C... "); + PrintAndLog("Attempting to Read Ultralight C... "); UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; SendCommand(&c); UsbCommand resp; @@ -1130,14 +1131,14 @@ int CmdHF14AMfUCWrBl(const char *Cmd){ //------------------------------------ static command_t CommandTable[] = { - {"help", CmdHelp, 1,"This help"}, + {"help", CmdHelp, 1,"This help"}, {"dbg", CmdHF14AMfDbg, 0,"Set default debug mode"}, - {"urdbl", CmdHF14AMfURdBl, 0,"Read MIFARE Ultralight block"}, - {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, + {"urdbl", CmdHF14AMfURdBl, 0,"Read MIFARE Ultralight block"}, + {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, {"udump", CmdHF14AMfUDump, 0,"Dump MIFARE Ultralight tag to binary file"}, {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, - {"ucrdbl", CmdHF14AMfUCRdBl, 0,"Read MIFARE Ultralight C block"}, - {"ucrdcard",CmdHF14AMfUCRdCard, 0,"Read MIFARE Ultralight C Card"}, + {"ucrdbl", CmdHF14AMfUCRdBl, 0,"Read MIFARE Ultralight C block"}, + {"ucrdcard",CmdHF14AMfUCRdCard, 0,"Read MIFARE Ultralight C Card"}, {"ucdump", CmdHF14AMfUCDump, 0,"Dump MIFARE Ultralight C tag to binary file"}, {"ucwrbl", CmdHF14AMfUCWrBl, 0,"Write MIFARE Ultralight C block"}, {"auth", CmdHF14AMfucAuth, 0,"Ultralight C Authentication"}, @@ -1145,7 +1146,6 @@ static command_t CommandTable[] = }; int CmdHFMFUltra(const char *Cmd){ - // flush WaitForResponseTimeout(CMD_ACK,NULL,100); CmdsParse(CommandTable, Cmd); return 0; diff --git a/client/cmdhw.c b/client/cmdhw.c index 28cd01ba..642f63c5 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -391,23 +391,7 @@ int CmdSetMux(const char *Cmd) int CmdTune(const char *Cmd) { - UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING}; - SendCommand(&c); - - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hw tune

"); - PrintAndLog(""); - PrintAndLog(" sample: hw tune"); - PrintAndLog(" hw tune p"); - return 0; - } - - if ( cmdp == 'p' || cmdp == 'P'){ - ShowGraphWindow(); - CmdTuneSamples(""); - } - return 0; + return CmdTuneSamples(Cmd); } int CmdVersion(const char *Cmd) diff --git a/client/cmdmain.c b/client/cmdmain.c index 0641f9c8..b3f04e10 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -26,15 +26,8 @@ #include "util.h" #include "cmdscript.h" -int delta125[2]; -int delta134[2]; -int deltahf[2]; -int deltaReset = 0; unsigned int current_command = CMD_UNKNOWN; -//unsigned int received_command = CMD_UNKNOWN; -//UsbCommand current_response; -//UsbCommand current_response_user; static int CmdHelp(const char *Cmd); static int CmdQuit(const char *Cmd); @@ -49,14 +42,14 @@ static int cmd_tail;//Starts as 0 static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help. Use ' 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"}, + {"help", CmdHelp, 1, "This help. Use ' 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} }; @@ -138,29 +131,25 @@ int getCommand(UsbCommand* response) */ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) { - UsbCommand resp; + UsbCommand resp; - if (response == NULL) { + if (response == NULL) + response = &resp; - response = &resp; - } - // Wait until the command is received - for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { + // Wait until the command is received + for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { - while(getCommand(response)) - { - if(response->cmd == cmd){ - //We got what we expected - return true; - } - - } - msleep(10); // XXX ugh - if (dm_seconds == 200) { // Two seconds elapsed - PrintAndLog("Waiting for a response from the proxmark..."); - PrintAndLog("Don't forget to cancel its operation first by pressing on the button"); - } + while(getCommand(response)) { + if(response->cmd == cmd){ + return true; + } + } + msleep(10); // XXX ugh + if (dm_seconds == 200) { // Two seconds elapsed + PrintAndLog("Waiting for a response from the proxmark..."); + PrintAndLog("Don't forget to cancel its operation first by pressing on the button"); + } } return false; } @@ -183,114 +172,30 @@ void CommandReceived(char *Cmd) { //----------------------------------------------------------------------------- void UsbCommandReceived(UsbCommand *UC) { - /* - // Debug - printf("UsbCommand length[len=%zd]\n",sizeof(UsbCommand)); - printf(" cmd[len=%zd]: %"llx"\n",sizeof(UC->cmd),UC->cmd); - printf(" arg0[len=%zd]: %"llx"\n",sizeof(UC->arg[0]),UC->arg[0]); - printf(" arg1[len=%zd]: %"llx"\n",sizeof(UC->arg[1]),UC->arg[1]); - printf(" arg2[len=%zd]: %"llx"\n",sizeof(UC->arg[2]),UC->arg[2]); - printf(" data[len=%zd]: %02x%02x%02x...\n",sizeof(UC->d.asBytes),UC->d.asBytes[0],UC->d.asBytes[1],UC->d.asBytes[2]); - */ + switch(UC->cmd) { + // First check if we are handling a debug message + case CMD_DEBUG_PRINT_STRING: { + char s[USB_CMD_DATA_SIZE+1] = {0x00}; + size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); + memcpy(s,UC->d.asBytes,len); + PrintAndLog("#db# %s ", s); + return; + } break; - // printf("%s(%x) current cmd = %x\n", __FUNCTION__, c->cmd, current_command); - // If we recognize a response, return to avoid further processing - switch(UC->cmd) { - // First check if we are handling a debug message - case CMD_DEBUG_PRINT_STRING: { - char s[USB_CMD_DATA_SIZE+1] = {0x00}; - size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); - memcpy(s,UC->d.asBytes,len); - PrintAndLog("#db# %s ", s); - return; - } break; + case CMD_DEBUG_PRINT_INTEGERS: { + PrintAndLog("#db# %08x, %08x, %08x \r\n", UC->arg[0], UC->arg[1], UC->arg[2]); + return; + } break; + + case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: { + sample_buf_len += UC->arg[1]; + memcpy(sample_buf+(UC->arg[0]),UC->d.asBytes,UC->arg[1]); + } break; - case CMD_DEBUG_PRINT_INTEGERS: { - PrintAndLog("#db# %08x, %08x, %08x \r\n", UC->arg[0], UC->arg[1], UC->arg[2]); - return; - } break; - - case CMD_MEASURED_ANTENNA_TUNING: { - int peakv, peakf; - int vLf125, vLf134, vHf; - vLf125 = UC->arg[0] & 0xffff; - vLf134 = UC->arg[0] >> 16; - vHf = UC->arg[1] & 0xffff;; - peakf = UC->arg[2] & 0xffff; - peakv = UC->arg[2] >> 16; - - //Reset delta trigger every 3:d time - - if ( deltaReset == 4){ - delta125[0] = vLf125; - delta134[0] = vLf134; - deltahf[0] = vHf; - } else if ( deltaReset == 2){ - delta125[1] = vLf125; - delta134[1] = vLf134; - deltahf[1] = vHf; + default: + break; } - - if ( deltaReset == 0){ - - } - - PrintAndLog(""); - PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0); - PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0); - PrintAndLog("# LF optimal: %5.2f V @ %9.2f kHz", peakv/1000.0, 12000.0/(peakf+1)); - PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0); - if (peakv<2000) - PrintAndLog("# Your LF antenna is unusable."); - else if (peakv<10000) - PrintAndLog("# Your LF antenna is marginal."); - if (vHf<2000) - PrintAndLog("# Your HF antenna is unusable."); - else if (vHf<5000) - PrintAndLog("# Your HF antenna is marginal."); - } - - deltaReset = (deltaReset == 0) ? 4 : deltaReset>>1; - break; - - case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: { -// printf("received samples: "); -// print_hex(UC->d.asBytes,512); - sample_buf_len += UC->arg[1]; -// printf("samples: %zd offset: %d\n",sample_buf_len,UC->arg[0]); - memcpy(sample_buf+(UC->arg[0]),UC->d.asBytes,UC->arg[1]); - } break; - - -// case CMD_ACK: { -// PrintAndLog("Receive ACK\n"); -// } break; - - default: { - // Maybe it's a response - /* - switch(current_command) { - case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: { - if (UC->cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { - PrintAndLog("unrecognized command %08x\n", UC->cmd); - break; - } -// int i; - PrintAndLog("received samples %d\n",UC->arg[0]); - memcpy(sample_buf+UC->arg[0],UC->d.asBytes,48); - sample_buf_len += 48; -// for(i=0; i<48; i++) sample_buf[i] = UC->d.asBytes[i]; - //received_command = UC->cmd; - } break; - - default: { - } break; - }*/ - } - break; - } storeCommand(UC); - } From f5ed4d12de19dcf59a3d5ecdcd9f75f5c747dd3e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Dec 2014 13:46:02 +0100 Subject: [PATCH 46/78] ADD: started with adding a LF AWID26 write function. not done yet. ADD: latest pwpiwi & holiman changes. --- armsrc/epa.c | 100 +++---------- armsrc/hitag2.c | 2 +- armsrc/iclass.c | 12 +- armsrc/iso14443.c | 3 +- armsrc/iso14443a.c | 22 +-- armsrc/lfops.c | 79 +++++++++-- armsrc/mifarecmd.c | 44 +++--- armsrc/mifaredesfire.c | 22 +-- armsrc/mifareutil.c | 9 +- client/Makefile | 1 + client/cmdhf14a.c | 93 ++++++------- client/cmdhfepa.c | 5 +- client/cmdhficlass.c | 44 ++++-- client/cmdhfmf.c | 262 ++--------------------------------- client/cmdlf.c | 2 + client/cmdlfawid26.c | 102 ++++++++++++++ client/cmdlfawid26.h | 16 +++ client/loclass/elite_crack.c | 14 +- 18 files changed, 368 insertions(+), 464 deletions(-) create mode 100644 client/cmdlfawid26.c create mode 100644 client/cmdlfawid26.h diff --git a/armsrc/epa.c b/armsrc/epa.c index a3c6669e..0bbd2dd7 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -108,9 +108,9 @@ size_t EPA_Parse_CardAccess(uint8_t *data, if (data[index] == 0x31 || data[index] == 0x30) { // enter the set (skip tag + length) index += 2; - // extended length + // check for extended length if ((data[index - 1] & 0x80) != 0) { - index += (data[index] & 0x7F); + index += (data[index-1] & 0x7F); } } // OID @@ -423,89 +423,31 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) //----------------------------------------------------------------------------- int EPA_Setup() { - // return code - //int return_code = 0; - - // card UID - //uint8_t uid[10] = {0x00}; - + + int return_code = 0; + uint8_t uid[10]; + uint8_t pps_response[3]; + uint8_t pps_response_par[1]; + iso14a_card_select_t card_select_info; + // power up the field iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - iso14a_clear_trace(); - iso14a_set_tracing(TRUE); + iso14a_set_timeout(10500); - // card select information - byte_t cardbuf[USB_CMD_DATA_SIZE]; - memset(cardbuf,0,USB_CMD_DATA_SIZE); - iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; - // select the card - // if (!iso14443a_select_card(uid, &card_info, NULL)) { - // Dbprintf("Epa: Can't select card"); - // return -1; - // } - - uint8_t wupa[] = { 0x26 }; // 0x26 - REQA 0x52 - WAKE-UP - uint8_t sel_all[] = { 0x93,0x20 }; - uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - uint8_t rats[] = { 0xE0,0x81,0x00,0x00 }; // FSD=256, FSDI=8, CID=1 - - uint8_t *resp = ((uint8_t *)BigBuf) + RECV_RESP_OFFSET; - uint8_t *resp_par = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; - - byte_t uid_resp[4]; - size_t uid_resp_len = 4; + return_code = iso14443a_select_card(uid, &card_select_info, NULL); + if (return_code != 1) { + Dbprintf("Epa: Can't select card"); + return 1; + } - uint8_t sak = 0x04; // cascade uid - int len; - - // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitBitsPar(wupa,7,0, NULL); - - // Receive the ATQA - if(!ReaderReceive(resp, resp_par)) return -1; - - // SELECT_ALL - ReaderTransmit(sel_all,sizeof(sel_all), NULL); - if (!ReaderReceive(resp, resp_par)) return -1; - - // uid response from tag - memcpy(uid_resp,resp,uid_resp_len); - - // Construct SELECT UID command - // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) - memcpy(sel_uid+2,uid_resp,4); // the UID - sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC - AppendCrc14443a(sel_uid,7); // calculate and add CRC - ReaderTransmit(sel_uid,sizeof(sel_uid), NULL); - - // Receive the SAK - if (!ReaderReceive(resp, resp_par)) return -1; - sak = resp[0]; - - // Request for answer to select - AppendCrc14443a(rats, 2); - ReaderTransmit(rats, sizeof(rats), NULL); - - if ( !(len = ReaderReceive(resp, resp_par) )) return -1; - - // populate the collected data. - memcpy( card->uid, uid_resp, uid_resp_len); - card->uidlen += uid_resp_len; - card->sak = sak; - card->ats_len = len; - memcpy(card->ats, resp, sizeof(card->ats)); - - // send the PPS request - // ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); - // uint8_t pps_response[3]; - // uint8_t pps_response_par[1]; - // return_code = ReaderReceive(pps_response,pps_response_par); - // if (return_code != 3 || pps_response[0] != 0xD0) { - // return return_code == 0 ? 2 : return_code; - // } + ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); + return_code = ReaderReceive(pps_response, pps_response_par); + if (return_code != 3 || pps_response[0] != 0xD0) { + return return_code == 0 ? 2 : return_code; + } - return -1; + return 0; } \ No newline at end of file diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 33cc3b7f..dc4c4232 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -1158,7 +1158,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { case RHT2F_CRYPTO: { DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); + memcpy(key,htd->crypto.key,6); // 4 or 6 ?? Dbhexdump(6,key,false); blocknr = 0; bQuiet = false; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index f53f3041..74705b49 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -549,7 +549,7 @@ static RAMFUNC int ManchesterDecoding(int v) // Tag response does not need to be a complete byte! if(Demod.len > 0 || Demod.bitCount > 0) { if(Demod.bitCount > 1) { // was > 0, do not interpret last closing bit, is part of EOF - Demod.shiftReg >>= (9 - Demod.bitCount); // rright align data + Demod.shiftReg >>= (9 - Demod.bitCount); // right align data Demod.output[Demod.len] = Demod.shiftReg & 0xff; Demod.len++; } @@ -1145,7 +1145,8 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader respsize = 0; if (breakAfterMacReceived){ // 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("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], @@ -1264,8 +1265,8 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int FpgaSetupSsc(); if (wait) - if(*wait < 10) - *wait = 10; + { + if(*wait < 10) *wait = 10; for(c = 0; c < *wait;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { @@ -1279,6 +1280,9 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int WDT_HIT(); } + } + + uint8_t sendbyte; bool firstpart = TRUE; c = 0; diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c index 28ab54d6..775c583a 100644 --- a/armsrc/iso14443.c +++ b/armsrc/iso14443.c @@ -293,8 +293,7 @@ static int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen) // 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); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); // Now run a `software UART' on the stream of incoming samples. diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 7dfa53e7..d8edc209 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -310,10 +310,11 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) if (Uart.state == STATE_UNSYNCD) { // not yet synced if (Uart.highCnt < 7) { // wait for a stable unmodulated signal - if (Uart.twoBits == 0xffff) + if (Uart.twoBits == 0xffff) { Uart.highCnt++; - else + } else { Uart.highCnt = 0; + } } else { Uart.syncBit = 0xFFFF; // not set // look for 00xx1111 (the start bit) @@ -1602,8 +1603,7 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity, uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity) { - if (!tracing) return true; - + if (tracing) { // we cannot exactly measure the end and start of a received command from reader. However we know that the delay from // end of the received command to start of the tag's (simulated by us) answer is n*128+20 or n*128+84 resp. // with n >= 9. The start of the tags answer can be measured and therefore the end of the received command be calculated: @@ -1614,8 +1614,10 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start reader_StartTime = reader_EndTime - reader_modlen; if (!LogTrace(reader_data, reader_len, reader_StartTime, reader_EndTime, reader_Parity, TRUE)) { return FALSE; - } else - return(!LogTrace(tag_data, tag_len, tag_StartTime, tag_EndTime, tag_Parity, FALSE)); + } else return(!LogTrace(tag_data, tag_len, tag_StartTime, tag_EndTime, tag_Parity, FALSE)); + } else { + return TRUE; + } } //----------------------------------------------------------------------------- @@ -1703,7 +1705,6 @@ int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t *parit int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) { if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, 0)) return FALSE; - if (tracing) { LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, FALSE); } @@ -1714,7 +1715,7 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) * fills the uid pointer unless NULL * fills resp_data unless NULL */ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { - //uint8_t halt[] = { 0x50 }; // HALT + //uint8_t halt[] = { 0x50, 0x00, 0x57, 0xCD }; // HALT uint8_t wupa[] = { 0x52 }; // WAKE-UP //uint8_t reqa[] = { 0x26 }; // REQUEST A uint8_t sel_all[] = { 0x93,0x20 }; @@ -1731,6 +1732,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u // test for the SKYLANDERS TOY. //ReaderTransmit(halt,sizeof(halt), NULL); + //len = ReaderReceive(resp, resp_par); // Broadcast for a card, WUPA (0x52) will force response from all cards in the field ReaderTransmitBitsPar(wupa,7,0, NULL); @@ -1808,7 +1810,6 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u // Receive the SAK if (!ReaderReceive(resp, resp_par)) return 0; sak = resp[0]; - // Test if more parts of the uid are coming if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { @@ -1844,7 +1845,8 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); - if (!(len = ReaderReceive(resp, resp_par))) return 2; + len = ReaderReceive(resp, resp_par); + if(!len) return 0; if(p_hi14a_card) { memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 15af6d65..fa0516c9 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -769,7 +769,7 @@ size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint continue; } //if lastval was 1, we have a 1->0 crossing - if ( dest[idx-1]==1 ) { + if ( dest[idx-1] ) { n=(n+1) / h2l_crossing_value; } else {// 0->1 crossing n=(n+1) / l2h_crossing_value; @@ -814,11 +814,13 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) size = fsk_demod(dest, FREE_BUFFER_SIZE); // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns - // 1->0 : fc/8 in sets of 6 - // 0->1 : fc/10 in sets of 5 + // 1->0 : fc/8 in sets of 6 (RF/50 / 8 = 6.25) + // 0->1 : fc/10 in sets of 5 (RF/50 / 10= 5) // do not invert size = aggregate_bits(dest,size, 6,5,5,0); + WDT_HIT(); + // final loop, go over previously decoded manchester data and decode into usable tag ID // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 uint8_t frame_marker_mask[] = {1,1,1,0,0,0}; @@ -851,17 +853,64 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) { - if (hi2 != 0){ + if (hi2 != 0){ //extra large HID tags Dbprintf("TAG ID: %x%08x%08x (%d)", (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); } - else { - Dbprintf("TAG ID: %x%08x (%d)", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + else { //standard HID tags <38 bits + //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd + uint8_t bitlen = 0; + uint32_t fc = 0; + uint32_t cardnum = 0; + if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used + uint32_t lo2=0; + lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit + uint8_t idx3 = 1; + while(lo2>1){ //find last bit set to 1 (format len bit) + lo2=lo2>>1; + idx3++; + } + bitlen =idx3+19; + fc =0; + cardnum=0; + if(bitlen==26){ + cardnum = (lo>>1)&0xFFFF; + fc = (lo>>17)&0xFF; + } + if(bitlen==37){ + cardnum = (lo>>1)&0x7FFFF; + fc = ((hi&0xF)<<12)|(lo>>20); + } + if(bitlen==34){ + cardnum = (lo>>1)&0xFFFF; + fc= ((hi&1)<<15)|(lo>>17); + } + if(bitlen==35){ + cardnum = (lo>>1)&0xFFFFF; + fc = ((hi&1)<<11)|(lo>>21); + } + } + else { //if bit 38 is not set then 37 bit format is used + bitlen= 37; + fc =0; + cardnum=0; + if(bitlen==37){ + cardnum = (lo>>1)&0x7FFFF; + fc = ((hi&0xF)<<12)|(lo>>20); + } + } + //Dbprintf("TAG ID: %x%08x (%d)", + // (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, + (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); + } + if (findone){ + if (ledcontrol) LED_A_OFF(); + return; } } } - // reset hi2 = hi = lo = 0; numshifts = 0; @@ -890,8 +939,7 @@ uint32_t bytebits_to_byte(uint8_t* src, int numbits) void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = get_bigbufptr_recvrespbuf(); - + uint8_t *dest = (uint8_t *)BigBuf; size_t size=0, idx=0; uint32_t code=0, code2=0; uint8_t isFinish = 0; @@ -906,13 +954,13 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) if (ledcontrol) LED_A_ON(); DoAcquisition125k_internal(-1,true); + size = sizeof(BigBuf); // FSK demodulator - size = fsk_demod(dest, FREE_BUFFER_SIZE); - + size = fsk_demod(dest, size); // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns - // 1->0 : fc/8 in sets of 7 - // 0->1 : fc/10 in sets of 6 + // 1->0 : fc/8 in sets of 7 (RF/64 / 8 = 8) + // 0->1 : fc/10 in sets of 6 (RF/64 / 10 = 6.4) size = aggregate_bits(dest, size, 7,6,13,1); //13 max Consecutive should be ok as most 0s in row should be 10 for init seq - invert bits //Index map @@ -1601,9 +1649,12 @@ int DemodPCF7931(uint8_t **outBlocks) { block_done = 0; half_switch = 0; } + if(i < GraphTraceLen) + { if (GraphBuffer[i-1] > GraphBuffer[i]) dir=0; else dir = 1; } + } if(bitidx==255) bitidx=0; warnings = 0; diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 519ea2b0..b9b8098a 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -20,7 +20,7 @@ #include "../common/crc.h" //----------------------------------------------------------------------------- -// Select, Authenticaate, Read an MIFARE tag. +// Select, Authenticate, Read a MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) @@ -267,25 +267,25 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) void MifareUReadCard(uint8_t arg0, int arg1, uint8_t *datain) { - // params - uint8_t sectorNo = arg0; - int Pages=arg1; + // params + uint8_t sectorNo = arg0; + int Pages=arg1; int count_Pages=0; - // variables - byte_t isOK = 0; - byte_t dataoutbuf[44 * 4]; - uint8_t uid[10]; - uint32_t cuid; + // variables + byte_t isOK = 0; + byte_t dataoutbuf[176]; + uint8_t uid[10]; + uint32_t cuid; - // clear trace - iso14a_clear_trace(); + // clear trace + iso14a_clear_trace(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - Dbprintf("Pages %d",Pages); + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + Dbprintf("Pages %d",Pages); while (true) { if(!iso14443a_select_card(uid, NULL, &cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); @@ -307,8 +307,8 @@ void MifareUReadCard(uint8_t arg0, int arg1, uint8_t *datain) isOK = 1; break; } - Dbprintf("Pages read %d",count_Pages); - if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); + Dbprintf("Pages read %d",count_Pages); + if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); LED_B_ON(); if (Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); @@ -316,9 +316,9 @@ void MifareUReadCard(uint8_t arg0, int arg1, uint8_t *datain) if (Pages==44 && count_Pages>16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,176); LED_B_OFF(); - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } @@ -792,7 +792,6 @@ void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6); LED_B_OFF(); - // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); @@ -1127,7 +1126,6 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_B_OFF(); if ((workFlags & 0x10) || (!isOK)) { - // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 4a580371..0d8de438 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -78,9 +78,9 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){ } int len = DesfireAPDU(datain, datalen, resp); - if (MF_DBGLEVEL >= 4) { - print_result("ERR <--: ", resp, len); - } + if (MF_DBGLEVEL >= 4) { + print_result("ERR <--: ", resp, len); + } if ( !len ) { OnError(); @@ -124,7 +124,7 @@ void MifareDesfireGetInformation(){ // card select - information iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; byte_t isOK = iso14443a_select_card(NULL, card, NULL); - if (isOK != 1) { + if ( isOK == 0) { if (MF_DBGLEVEL >= 1) { Dbprintf("Can't select card"); } @@ -306,7 +306,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain // dataout = pointer to response data array int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ - uint32_t status = 0; + size_t len = 0; size_t wrappedLen = 0; uint8_t wCmd[USB_CMD_DATA_SIZE] = {0}; @@ -320,9 +320,9 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ } ReaderTransmit( wCmd, wrappedLen, NULL); - status = ReaderReceive(resp, resp_par); + len = ReaderReceive(resp, resp_par); - if( status == 0x00){ + if( len == 0x00 ){ if (MF_DBGLEVEL >= 4) { Dbprintf("fukked"); } @@ -330,16 +330,16 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ } // 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 (status >= 4 // PCB+CID+CRC = 4 bytes + 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 } - // copy response to - dataout = resp; - return status; + + memcpy(dataout, resp, len); + return len; } // CreateAPDU diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index d2841497..dcea901d 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -85,8 +85,11 @@ int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint { uint8_t dcmd[8]; dcmd[0] = cmd; - memcpy(dcmd+1,data,5); - + dcmd[1] = data[0]; + dcmd[2] = data[1]; + dcmd[3] = data[2]; + dcmd[4] = data[3]; + dcmd[5] = data[4]; AppendCrc14443a(dcmd, 6); ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer, answer_parity); @@ -383,7 +386,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl // variables uint16_t len, i; uint32_t pos; - uint8_t par[3] = {0x00}; + uint8_t par[3] = {0}; // enough for 18 Bytes to send byte_t res; uint8_t d_block[18], d_block_enc[18]; diff --git a/client/Makefile b/client/Makefile index 2d52e3df..7ef23fa6 100644 --- a/client/Makefile +++ b/client/Makefile @@ -83,6 +83,7 @@ CMDSRCS = nonce2key/crapto1.c\ cmdhfdes.c \ cmdhw.c \ cmdlf.c \ + cmdlfawid26.c \ cmdlfio.c \ cmdlfhid.c \ cmdlfem4x.c \ diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 46720d44..97d102be 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -40,9 +40,7 @@ int CmdHF14AList(const char *Cmd) return 0; } - if (param == 'f') { - ShowWaitCycles = true; - } + ShowWaitCycles = (param == 'f'); // for the time being. Need better Bigbuf handling. #define TRACE_SIZE 3000 @@ -56,8 +54,8 @@ int CmdHF14AList(const char *Cmd) PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data"); - PrintAndLog("-----------|-----------|-----|--------"); + PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC "); + PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------"); uint16_t tracepos = 0; uint16_t duration; @@ -70,44 +68,40 @@ int CmdHF14AList(const char *Cmd) for (;;) { - if(tracepos >= TRACE_SIZE) { - break; - } + if(tracepos >= TRACE_SIZE) break; timestamp = *((uint32_t *)(trace + tracepos)); + + // Break and stick with current result if buffer was not completely full + if (timestamp == 0x44444444) break; + if(tracepos == 0) { first_timestamp = timestamp; } + tracepos += 4; duration = *((uint16_t *)(trace + tracepos)); tracepos += 2; data_len = *((uint16_t *)(trace + tracepos)); tracepos += 2; + isResponse = false; if (data_len & 0x8000) { data_len &= 0x7fff; isResponse = true; - } else { - isResponse = false; } - + parity_len = (data_len-1)/8 + 1; - - if (tracepos + data_len + parity_len >= TRACE_SIZE) { - break; - } + + if (tracepos + data_len + parity_len >= TRACE_SIZE) break; uint8_t *frame = trace + tracepos; tracepos += data_len; uint8_t *parityBytes = trace + tracepos; tracepos += parity_len; - - // Break and stick with current result if buffer was not completely full - if (timestamp == 0x44444444) break; - - char line[1000] = ""; - int j; - for (j = 0; j < data_len; j++) { + + char line[16][110]; + for (int j = 0; j < data_len; j++) { int oddparity = 0x01; int k; @@ -117,47 +111,53 @@ int CmdHF14AList(const char *Cmd) uint8_t parityBits = parityBytes[j>>3]; if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); + sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]); } else { - sprintf(line+(j*4), "%02x ", frame[j]); + sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]); } } - - char crc[6] = ""; + + char crc[5] = {0x00}; if (data_len > 2) { uint8_t b1, b2; ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - sprintf(crc, (isResponse & (data_len < 6)) ? "" : " !crc"); - } else { - sprintf(crc, ""); - } + sprintf(crc, (isResponse & (data_len < 6)) ? "" : "!crc"); + } } EndOfTransmissionTimestamp = timestamp + duration; - - PrintAndLog(" %9d | %9d | %s | %s %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (isResponse ? "Tag" : "Rdr"), - line, - crc); + int num_lines = (data_len - 1)/16 + 1; + + for (int j = 0; j < num_lines; j++) { + if (j == 0) { + PrintAndLog(" %9d | %9d | %s | %-64s| %s", + (timestamp - first_timestamp), + (EndOfTransmissionTimestamp - first_timestamp), + (isResponse ? "Tag" : "Rdr"), + line[j], + (j == num_lines-1)?crc:"" + ); + } else { + PrintAndLog(" | | | %-64s| %s", + line[j], + (j == num_lines-1)?crc:""); + } + } bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; if (ShowWaitCycles && !isResponse && next_isResponse) { uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); if (next_timestamp != 0x44444444) { - PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", - (EndOfTransmissionTimestamp - first_timestamp), - (next_timestamp - first_timestamp), - " ", - (next_timestamp - EndOfTransmissionTimestamp)); - } + PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", + (EndOfTransmissionTimestamp - first_timestamp), + (next_timestamp - first_timestamp), + " ", + (next_timestamp - EndOfTransmissionTimestamp)); } - + } } - return 0; } @@ -168,8 +168,7 @@ void iso14a_set_timeout(uint32_t timeout) { int CmdHF14AReader(const char *Cmd) { - //UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT , 0, 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; SendCommand(&c); UsbCommand resp; diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index c893da76..ecdb311c 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -54,10 +54,10 @@ int CmdHFEPACollectPACENonces(const char *Cmd) size_t nonce_length = resp.arg[1]; char *nonce = (char *) malloc(2 * nonce_length + 1); for(int j = 0; j < nonce_length; j++) { - snprintf(nonce + (2 * j), 3, "%02X", resp.d.asBytes[j]); + snprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]); } // print nonce - PrintAndLog("Length: %d, Nonce: %s",resp.arg[1], nonce); + PrintAndLog("Length: %d, Nonce: %s", nonce_length, nonce); } if (i < n - 1) { sleep(d); @@ -68,7 +68,6 @@ int CmdHFEPACollectPACENonces(const char *Cmd) return 1; } -// UI-related stuff // UI-related stuff static const command_t CommandTable[] = diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 370b36e9..e033422a 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -342,6 +342,17 @@ int CmdHFiClassSim(const char *Cmd) UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,NUM_CSNS}}; UsbCommand resp = {0}; + /*uint8_t csns[8 * NUM_CSNS] = { + 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 , + 0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 , + 0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 , + 0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 , + 0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 , + 0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 , + 0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 , + 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 }; +*/ + uint8_t csns[8*NUM_CSNS] = { 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, @@ -501,17 +512,31 @@ int CmdHFiClassReader_Dump(const char *Cmd) } + UsbCommand resp; + uint8_t key_sel[8] = {0}; + uint8_t key_sel_p[8] = { 0 }; + + //HACK -- Below is for testing without access to a tag + uint8_t fake_dummy_test = false; + if(fake_dummy_test) + { + uint8_t xdata[16] = {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0, //CSN from http://www.proxmark.org/forum/viewtopic.php?pid=11230#p11230 + 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // Just a random CC. Would be good to add a real testcase here + memcpy(resp.d.asBytes,xdata, 16); + resp.arg[0] = 2; + } + + //End hack + UsbCommand c = {CMD_READER_ICLASS, {0}}; c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE; - + if(!fake_dummy_test) SendCommand(&c); - UsbCommand resp; - uint8_t key_sel[8] = {0x00}; - uint8_t key_sel_p[8] = {0x00}; - - if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { + + + if (fake_dummy_test || WaitForResponseTimeout(CMD_ACK,&resp,4500)) { uint8_t isOK = resp.arg[0] & 0xff; uint8_t * data = resp.d.asBytes; @@ -528,7 +553,6 @@ int CmdHFiClassReader_Dump(const char *Cmd) { if(elite) { - //Get the key index (hash1) uint8_t key_index[8] = {0}; @@ -536,6 +560,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) printvar("hash1", key_index,8); for(i = 0; i < 8 ; i++) key_sel[i] = keytable[key_index[i]] & 0xFF; + PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:"); printvar("k_sel", key_sel,8); //Permute from iclass format to standard format permutekey_rev(key_sel,key_sel_p); @@ -552,8 +577,11 @@ int CmdHFiClassReader_Dump(const char *Cmd) used_key = KEY; } + + PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:"); printvar("Used key",used_key,8); diversifyKey(CSN,used_key, div_key); + PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):"); printvar("Div key", div_key, 8); printvar("CC_NR:",CCNR,12); doMAC(CCNR,12,div_key, MAC); @@ -561,7 +589,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) UsbCommand d = {CMD_READER_ICLASS_REPLAY, {readerType}}; memcpy(d.d.asBytes, MAC, 4); - SendCommand(&d); + if(!fake_dummy_test) SendCommand(&d); }else{ PrintAndLog("Failed to obtain CC! Aborting"); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index c28563e2..748e9c45 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -34,7 +34,7 @@ start: SendCommand(&c); //flush queue - while (ukbhit()) getchar(); + while (ukbhit()) getchar(); // wait cycle while (true) { @@ -66,19 +66,19 @@ start: if (isOK != 1) return 1; // execute original function from util nonce2key - if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) - { + if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) { isOK = 2; PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); } else { printf("------------------------------------------------------------------\n"); - PrintAndLog("Key found:%012"llx" \n", r_key); + PrintAndLog("Key found :%012"llx" \n", r_key); num_to_bytes(r_key, 6, keyBlock); isOK = mfCheckKeys(0, 0, 1, keyBlock, &r_key); } + if (!isOK) - PrintAndLog("Found valid key:%012"llx, r_key); + PrintAndLog("Found valid key :%012"llx, r_key); else { if (isOK != 2) PrintAndLog("Found invalid key. "); @@ -87,6 +87,7 @@ start: goto start; } + PrintAndLog(""); return 0; } @@ -139,117 +140,6 @@ int CmdHF14AMfWrBl(const char *Cmd) return 0; } -/* dublett finns i CMDHFMFU.C -int CmdHF14AMfUWrBl(const char *Cmd) -{ - uint8_t blockNo = 0; - bool chinese_card=0; - uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - UsbCommand resp; - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf mf uwrbl "); - PrintAndLog(" sample: hf mf uwrbl 0 01020304"); - return 0; - } - - blockNo = param_get8(Cmd, 0); - if (param_gethex(Cmd, 1, bldata, 8)) { - PrintAndLog("Block data must include 8 HEX symbols"); - return 1; - } - - if (strchr(Cmd,'w') != 0) { - chinese_card=1; - } - - switch(blockNo){ - case 0: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 1: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 2: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(c.d.asBytes, bldata, 4); - SendCommand(&c); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 3: - PrintAndLog("--specialblock no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - break; - default: - PrintAndLog("--block no:%d", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(e.d.asBytes,bldata, 4); - SendCommand(&e); - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - break; - } - return 0; -} -*/ int CmdHF14AMfRdBl(const char *Cmd) { uint8_t blockNo = 0; @@ -298,133 +188,6 @@ int CmdHF14AMfRdBl(const char *Cmd) return 0; } -/* dublett finns i CMDHFMFU.C -int CmdHF14AMfURdBl(const char *Cmd) -{ - uint8_t blockNo = 0; - - if (strlen(Cmd)<1) { - PrintAndLog("Usage: hf mf urdbl "); - PrintAndLog(" sample: hf mf urdbl 0"); - return 0; - } - - blockNo = param_get8(Cmd, 0); - PrintAndLog("--block no:%d", blockNo); - - UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; - 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, 4)); - else - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - - return 0; -} -*/ - -/* dublett finns i CMDHFMFU.C -int CmdHF14AMfURdCard(const char *Cmd) -{ - int i; - uint8_t sectorNo = 0; - uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0,0}; - bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - uint8_t isOK = 0; - uint8_t * data = NULL; - - if (sectorNo > 15) { - PrintAndLog("Sector number must be less than 16"); - return 1; - } - PrintAndLog("Attempting to Read Ultralight... "); - - UsbCommand c = {CMD_MIFAREU_READCARD, {sectorNo}}; - SendCommand(&c); - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - isOK = resp.arg[0] & 0xff; - data = resp.d.asBytes; - - PrintAndLog("isOk:%02x", isOK); - if (isOK) - for (i = 0; i < 16; i++) { - switch(i){ - case 2: - //process lock bytes - lockbytes_t=data+(i*4); - lockbytes[0]=lockbytes_t[2]; - lockbytes[1]=lockbytes_t[3]; - for(int j=0; j<16; j++){ - bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); - } - //PrintAndLog("LB %02x %02x", lockbytes[0],lockbytes[1]); - //PrintAndLog("LB2b %02x %02x %02x %02x %02x %02x %02x %02x",bit[8],bit[9],bit[10],bit[11],bit[12],bit[13],bit[14],bit[15]); - PrintAndLog("Block %3d:%s ", i,sprint_hex(data + i * 4, 4)); - break; - case 3: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); - break; - case 4: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); - break; - case 5: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); - break; - case 6: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); - break; - case 7: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); - break; - case 8: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); - break; - case 9: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); - break; - case 10: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); - break; - case 11: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); - break; - case 12: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); - break; - case 13: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); - break; - case 14: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); - break; - case 15: - PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); - break; - default: - PrintAndLog("Block %3d:%s ", i,sprint_hex(data + i * 4, 4)); - break; - } - } - } else { - PrintAndLog("Command execute timeout"); - } - return 0; -} -*/ - int CmdHF14AMfRdSc(const char *Cmd) { int i; @@ -482,7 +245,6 @@ int CmdHF14AMfRdSc(const char *Cmd) return 0; } - uint8_t FirstBlockOfSector(uint8_t sectorNo) { if (sectorNo < 32) { @@ -492,7 +254,6 @@ uint8_t FirstBlockOfSector(uint8_t sectorNo) } } - uint8_t NumBlocksPerSector(uint8_t sectorNo) { if (sectorNo < 32) { @@ -502,7 +263,6 @@ uint8_t NumBlocksPerSector(uint8_t sectorNo) } } - int CmdHF14AMfDump(const char *Cmd) { uint8_t sectorNo, blockNo; @@ -677,7 +437,6 @@ int CmdHF14AMfDump(const char *Cmd) return 0; } - int CmdHF14AMfRestore(const char *Cmd) { uint8_t sectorNo,blockNo; @@ -744,6 +503,7 @@ int CmdHF14AMfRestore(const char *Cmd) if (fread(bldata, 1, 16, fdump) == 0) { PrintAndLog("File reading error (dumpdata.bin)."); + fclose(fdump); return 2; } @@ -778,11 +538,9 @@ int CmdHF14AMfRestore(const char *Cmd) } fclose(fdump); - return 0; } - int CmdHF14AMfNested(const char *Cmd) { int i, j, res, iterations; @@ -1028,7 +786,6 @@ int CmdHF14AMfNested(const char *Cmd) return 0; } - int CmdHF14AMfChk(const char *Cmd) { if (strlen(Cmd)<3) { @@ -1256,11 +1013,10 @@ int CmdHF14AMfChk(const char *Cmd) } free(keyBlock); - + PrintAndLog(""); return 0; } - int CmdHF14AMf1kSim(const char *Cmd) { uint8_t uid[7] = {0, 0, 0, 0, 0, 0, 0}; @@ -1326,7 +1082,6 @@ int CmdHF14AMf1kSim(const char *Cmd) return 0; } - int CmdHF14AMfDbg(const char *Cmd) { int dbgMode = param_get32ex(Cmd, 0, 0, 10); @@ -1374,7 +1129,6 @@ int CmdHF14AMfEGet(const char *Cmd) return 0; } - int CmdHF14AMfEClear(const char *Cmd) { if (param_getchar(Cmd, 0) == 'h') { diff --git a/client/cmdlf.c b/client/cmdlf.c index 132a4c5f..2f55cd22 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -20,6 +20,7 @@ #include "cmdmain.h" #include "cmddata.h" #include "cmdlf.h" +#include "cmdlfawid26.h" #include "cmdlfhid.h" #include "cmdlfti.h" #include "cmdlfem4x.h" @@ -580,6 +581,7 @@ static command_t CommandTable[] = {"simman", CmdLFSimManchester, 0, " [GAP] Simulate arbitrary Manchester LF tag"}, {"snoop", CmdLFSnoop, 0, "['l'|'h'|] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"}, + {"avid", CmdLFAWID26, 1, "{ AWID26 tags }"}, {"em4x", CmdLFEM4X, 1, "{ EM4X tags }"}, {"hid", CmdLFHID, 1, "{ HID tags }"}, {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders }"}, diff --git a/client/cmdlfawid26.c b/client/cmdlfawid26.c new file mode 100644 index 00000000..63b35fdd --- /dev/null +++ b/client/cmdlfawid26.c @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------------- +// +// 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 +#include +#include +#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 write []"); + PrintAndLog(" [], "); + PrintAndLog(""); + PrintAndLog(" sample: lf awid26 write 26 2233"); + PrintAndLog(" : lf awid26 write 26 15 2233"); + return 0; + } + + //sscanf(Cmd, "%d %d", &facilitycode, &cardno); + + // char block0 = "00107060"; + // char block1 = "00107060"; + // char block2 = "00107060"; + // char block3 = "00107060"; + + + + // PrintAndLog("Writing block %d with data %08X", Block, Data); + return 0; +} + +// 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, 0, " -- clone to a 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 index 00000000..c0facf51 --- /dev/null +++ b/client/cmdlfawid26.h @@ -0,0 +1,16 @@ +//----------------------------------------------------------------------------- +// +// 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); +#endif diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index a2bd6647..3801d662 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -151,9 +151,9 @@ void hash1(uint8_t csn[] , uint8_t k[]) k[0] = csn[0]^csn[1]^csn[2]^csn[3]^csn[4]^csn[5]^csn[6]^csn[7]; k[1] = csn[0]+csn[1]+csn[2]+csn[3]+csn[4]+csn[5]+csn[6]+csn[7]; k[2] = rr(swap( csn[2]+k[1] )); - k[3] = rr(swap( csn[3]+k[0] )); - k[4] = ~rr(swap( csn[4]+k[2] ))+1; - k[5] = ~rr(swap( csn[5]+k[3] ))+1; + k[3] = rl(swap( csn[3]+k[0] )); + k[4] = ~rr( csn[4]+k[2] )+1; + k[5] = ~rl( csn[5]+k[3] )+1; k[6] = rr( csn[6]+(k[4]^0x3c) ); k[7] = rl( csn[7]+(k[5]^0xc3) ); int i; @@ -563,9 +563,13 @@ int bruteforceFile(const char *filename, uint16_t keytable[]) fseek(f, 0, SEEK_SET); uint8_t *dump = malloc(fsize); - fread(dump, fsize, 1, f); - fclose(f); + size_t bytes_read = fread(dump, fsize, 1, f); + fclose(f); + if (bytes_read < fsize) + { + prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize ); + } return bruteforceDump(dump,fsize,keytable); } /** From b216af9a24fb5691ec47e6e961e0a61a343a16d7 Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Fri, 19 Dec 2014 12:13:18 -0800 Subject: [PATCH 47/78] Fixed build environment --- client/Makefile | 4 ++-- client/loclass/fileutils.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/Makefile b/client/Makefile index 2d52e3df..689bba3e 100644 --- a/client/Makefile +++ b/client/Makefile @@ -13,13 +13,13 @@ CXX=g++ VPATH = ../common OBJDIR = obj -LDLIBS = -L/mingw/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lm -lreadline -lpthread -lcrypto -lgdi32 +LDLIBS = -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lm -lreadline -lpthread -lcrypto LDFLAGS = $(COMMON_FLAGS) CFLAGS = -std=c99 -I. -I../include -I../common -I/mingw/include -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 $(ICE_FLAGS) LUAPLATFORM = generic ifneq (,$(findstring MINGW,$(platform))) -CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -I$(QTDIR)/include/QtWidgets -I/mingw/include +CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -I$(QTDIR)/include/QtWidgets QTLDLIBS = -L$(QTDIR)/lib -lQt5Core -lQt5Gui -lQt5Widgets MOC = $(QTDIR)/bin/moc LUAPLATFORM = mingw diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index 6d990171..c8d56ce3 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -49,8 +49,8 @@ * @return */ int fileExists(const char *filename) { - struct _stat fileStat; - int result = _stat(filename, &fileStat); + struct stat st; + int result = stat(filename, &st); return result == 0; } From de9b66bc361b638b54c99eaec3d21dad9b04438d Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Fri, 19 Dec 2014 12:15:04 -0800 Subject: [PATCH 48/78] Added file demonstrating a singleDES AUTH operation using 'hf 14a raw' command --- client/loclass/blaine.c | 165 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 client/loclass/blaine.c diff --git a/client/loclass/blaine.c b/client/loclass/blaine.c new file mode 100644 index 00000000..9f642fa9 --- /dev/null +++ b/client/loclass/blaine.c @@ -0,0 +1,165 @@ +#include +#include +#include "des.h" + +int main(int argc, const char* argv[]) { + des_context ctx; + + unsigned char key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + printf("Key: "); + for (int i = 0; i < 8; i++) { + printf("%02x ", key[i]); + } + printf("\n\n"); + + // This is the challange sent from PICC + unsigned char ek0RandB[8] = {0x4f, 0xb1, 0xed, 0x2e, 0x11, 0x37, 0xd5, 0x1a}; + + if (argc == 8 + 1) { + for (int i = 0 + 1; i < 8 + 1; i++) { + ek0RandB[i - 1] = strtol(argv[i], NULL, 16); + } + } + + printf("ek0RandB (Challange): "); + for (int i = 0; i < 8; i++) { + printf("%02x ", ek0RandB[i]); + } + printf("\n\n"); + + unsigned char RandB[8]; + unsigned char RandBP[8]; + unsigned char ek0RandBP[8]; + + // TODO: Make this randomly generated + unsigned char RandA[8] = {0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + unsigned char ek0RandA[8]; + + unsigned char sessionKey[8]; + + des_setkey_dec(&ctx, key); + + //Decrypt RandB from PICC + des_crypt_ecb(&ctx, ek0RandB, RandB); + + printf("RandB: "); + for (int i = 0; i < 8; i++) { + printf("%02x ", RandB[i]); + } + printf("\n"); + + //Shift RandB left by 8 bits to produce RandB’ + for (int x = 0; x < 7; x++) { + RandBP[x] = RandB[x + 1]; + } + RandBP[7] = RandB[0]; + + printf("RandB’: "); + for (int i = 0; i < 8; i++) { + printf("%02x ", RandBP[i]); + } + printf("\n"); + + //Print RandA + printf("RandA: "); + for (int i = 0; i < 8; i++) { + printf("%02x ", RandA[i]); + } + printf("\n\n"); + + //Encrypt RandA into ek0RandA + des_crypt_ecb(&ctx, RandA, ek0RandA); + + printf("ek0RandA: "); + for (int i = 0; i < 8; i++) { + printf("%02x ", ek0RandA[i]); + } + printf("\n"); + + //Encrypt ( ek0RandA XOR RandB' ) for CBC Mode chaining + for (int i = 0; i < 8; i++) { + ek0RandBP[i] = RandBP[i] ^ ek0RandA[i]; + } + + des_crypt_ecb(&ctx, ek0RandBP, ek0RandBP); + + printf("ek0(RandB' XOR ek0RandA): "); + for (int i = 0; i < 8; i++) { + printf("%02x ", ek0RandBP[i]); + } + printf("\n\n"); + + //Varibles used in checking for proper reply from PICC + unsigned char RandAP[8]; + unsigned char ek0RandAP[8]; + + //Shift RandA left by 8 bits to produce RandA’ + for (int x = 0; x < 7; x++) { + RandAP[x] = RandA[x + 1]; + } + RandAP[7] = RandA[0]; + + //Encrypt RandA' to check PICC's response. + des_crypt_ecb(&ctx, RandAP, ek0RandAP); + + printf("ek0RandA' (Expected reply): "); + for (int i = 0; i < 8; i++) { + printf("%02x ", ek0RandAP[i]); + } + printf("\n"); + + //Create session key + sessionKey[0] = RandA[0]; + sessionKey[1] = RandA[1]; + sessionKey[2] = RandA[2]; + sessionKey[3] = RandA[3]; + sessionKey[4] = RandB[0]; + sessionKey[5] = RandB[1]; + sessionKey[6] = RandB[2]; + sessionKey[7] = RandB[3]; + + printf("Session Key: "); + for (int i = 0; i < 8; i++) { + printf("%02x ", sessionKey[i]); + } + printf("\n"); + + return 1; +} + +/* + Recorded Activity + + Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer + All times are in carrier periods (1/13.56Mhz) + + Start | End | Src | Data + -----------|-----------|-----|-------- + 0 | 992 | Rdr | 52 + 2228 | 4596 | Tag | 44 03 + 1836032 | 1838496 | Rdr | 93 20 + 1839668 | 1845492 | Tag | 88 04 6e 22 c0 + 3806976 | 3817440 | Rdr | 93 70 88 04 6e 22 c0 dc b8 + 3818676 | 3822196 | Tag | 24 d8 36 + 5815808 | 5818272 | Rdr | 95 20 + 5819444 | 5825268 | Tag | 72 63 34 80 a5 + 7757824 | 7768288 | Rdr | 95 70 72 63 34 80 a5 a7 a5 + 7769524 | 7773108 | Tag | 20 fc 70 + 9715072 | 9719840 | Rdr | e0 80 31 73 + 9721012 | 9730292 | Tag | 06 75 77 81 02 80 02 f0 + 12074624 | 12080480 | Rdr | 02 0a 00 dc ed + 12111924 | 12125812 | Tag | 02 af 4f b1 ed 2e 11 37 d5 1a bf 55 + 229214720 | 229237856 | Rdr | 03 af f3 56 83 43 79 d1 65 cd 6c 6d 17 e8 14 6e 52 eb 6d 2b + 229268916 | 229282804 | Tag | 03 00 0d 9f 27 9b a5 d8 72 60 f3 6f +*/ + +/* + hf 14a raw -p -a -b 7 52 + hf 14a raw -p 93 20 + hf 14a raw -p -c 93 70 88 04 6e 22 c0 + hf 14a raw -p 95 20 + hf 14a raw -p -c 95 70 72 63 34 80 a5 + hf 14a raw -p e0 80 31 73 + hf 14a raw -p -c 02 0a 00 + hf 14a raw -p -c 03 af ... +*/ \ No newline at end of file From b6f41bfdfefaf5619853d8fb26e8e3c3dc425ad0 Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Fri, 19 Dec 2014 12:15:45 -0800 Subject: [PATCH 49/78] Successfully decrypted RandB from PICC challenge --- armsrc/mifaredesfire.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 60c941eb..fef3e691 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -1,4 +1,5 @@ #include "mifaredesfire.h" +#include "des.h" #define MAX_APPLICATION_COUNT 28 #define MAX_FILE_COUNT 16 @@ -186,7 +187,7 @@ 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_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}; @@ -216,10 +217,31 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain // des, nyckel 0, switch (mode){ - case 1: - // if ( SendDesfireCommand(AUTHENTICATE, &keyno, resp) > 0 ){ - // // fick nonce från kortet - // } + case 1:{ + uint8_t keybytes[8]; + if (datain[1] == 0xff){ + memcpy(keybytes,null_key_data8,8); + } else{ + memcpy(keybytes, datain+1, datalen); + } + + cmd[0] = AUTHENTICATE; + cmd[1] = 0x00; //keynumber + len = DesfireAPDU(cmd, 2, resp); + if ( !len ) { + if (MF_DBGLEVEL >= 1) { + DbpString("Authentication failed. Card timeout."); + } + OnError(); + return; + } + + memcpy( encRndB, resp+3, 8); + + des_dec(&decRndB, &encRndB, &keybytes); + Dbprintf("RandB: %02x%02x%02x%02x%02x%02x%02x%02x",decRndB[0],decRndB[1],decRndB[2],decRndB[3],decRndB[4],decRndB[5],decRndB[6],decRndB[7]); + + } break; case 2: //SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp); From 0127902ee6bf5b7e7611a0d6daba4c136cd1caa0 Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Fri, 19 Dec 2014 19:36:19 -0800 Subject: [PATCH 50/78] Calculates response to PICC challenge --- armsrc/mifaredesfire.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index fef3e691..b1a6b3fb 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -239,7 +239,30 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain memcpy( encRndB, resp+3, 8); des_dec(&decRndB, &encRndB, &keybytes); - Dbprintf("RandB: %02x%02x%02x%02x%02x%02x%02x%02x",decRndB[0],decRndB[1],decRndB[2],decRndB[3],decRndB[4],decRndB[5],decRndB[6],decRndB[7]); + Dbprintf("RndB: %02x%02x%02x%02x%02x%02x%02x%02x",decRndB[0],decRndB[1],decRndB[2],decRndB[3],decRndB[4],decRndB[5],decRndB[6],decRndB[7]); + rol(decRndB,8); + Dbprintf("RndB': %02x%02x%02x%02x%02x%02x%02x%02x",decRndB[0],decRndB[1],decRndB[2],decRndB[3],decRndB[4],decRndB[5],decRndB[6],decRndB[7]); + + uint8_t decRndA[8] = {0x00}; + uint8_t encRndA[8] = {0x00}; + + des_dec(&encRndA, &decRndA, &keybytes); + Dbprintf("RndA: %02x%02x%02x%02x%02x%02x%02x%02x",decRndA[0],decRndA[1],decRndA[2],decRndA[3],decRndA[4],decRndA[5],decRndA[6],decRndA[7]); + Dbprintf("ek0RandA: %02x%02x%02x%02x%02x%02x%02x%02x",encRndA[0],encRndA[1],encRndA[2],encRndA[3],encRndA[4],encRndA[5],encRndA[6],encRndA[7]); + + memcpy(both, encRndA, 8); + + for (int x = 0; x < 8; x++) { + decRndB[x] = decRndB[x] ^ encRndA[x]; + + } + + des_dec(&encRndB, &decRndB, &keybytes); + + memcpy(both + 8, encRndB, 8); + Dbprintf("both: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",both[0],both[1],both[2],both[3],both[4],both[5],both[6],both[7],both[8],both[9],both[10],both[11],both[12],both[13],both[14],both[15]); + + // TODO: Send response } break; From 1051dee04a1cdba922e7a91acadfb7b44d244e7e Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Fri, 19 Dec 2014 19:44:32 -0800 Subject: [PATCH 51/78] Challenge is now sent to PICC --- armsrc/mifaredesfire.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index b1a6b3fb..c56d8bc0 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -262,7 +262,19 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain memcpy(both + 8, encRndB, 8); Dbprintf("both: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",both[0],both[1],both[2],both[3],both[4],both[5],both[6],both[7],both[8],both[9],both[10],both[11],both[12],both[13],both[14],both[15]); - // TODO: Send response + cmd[0] = ADDITIONAL_FRAME; + memcpy(cmd+1, both, 16 ); + + len = DesfireAPDU(cmd, 17, resp); + if ( !len ) { + if (MF_DBGLEVEL >= 1) { + DbpString("Authentication failed. Card timeout."); + } + OnError(); + return; + } + + // TODO: Check returned RandA' } break; From a07a448220f85c4e27a9b50f412d376474ea4f69 Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Fri, 19 Dec 2014 20:38:25 -0800 Subject: [PATCH 52/78] Removed unneeded verbosity and checked for a 0x00 response from PICC after challenge response --- armsrc/mifaredesfire.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index c56d8bc0..66fe00bd 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -239,16 +239,12 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain memcpy( encRndB, resp+3, 8); des_dec(&decRndB, &encRndB, &keybytes); - Dbprintf("RndB: %02x%02x%02x%02x%02x%02x%02x%02x",decRndB[0],decRndB[1],decRndB[2],decRndB[3],decRndB[4],decRndB[5],decRndB[6],decRndB[7]); rol(decRndB,8); - Dbprintf("RndB': %02x%02x%02x%02x%02x%02x%02x%02x",decRndB[0],decRndB[1],decRndB[2],decRndB[3],decRndB[4],decRndB[5],decRndB[6],decRndB[7]); uint8_t decRndA[8] = {0x00}; uint8_t encRndA[8] = {0x00}; des_dec(&encRndA, &decRndA, &keybytes); - Dbprintf("RndA: %02x%02x%02x%02x%02x%02x%02x%02x",decRndA[0],decRndA[1],decRndA[2],decRndA[3],decRndA[4],decRndA[5],decRndA[6],decRndA[7]); - Dbprintf("ek0RandA: %02x%02x%02x%02x%02x%02x%02x%02x",encRndA[0],encRndA[1],encRndA[2],encRndA[3],encRndA[4],encRndA[5],encRndA[6],encRndA[7]); memcpy(both, encRndA, 8); @@ -260,7 +256,6 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain des_dec(&encRndB, &decRndB, &keybytes); memcpy(both + 8, encRndB, 8); - Dbprintf("both: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",both[0],both[1],both[2],both[3],both[4],both[5],both[6],both[7],both[8],both[9],both[10],both[11],both[12],both[13],both[14],both[15]); cmd[0] = ADDITIONAL_FRAME; memcpy(cmd+1, both, 16 ); @@ -274,7 +269,15 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain return; } - // TODO: Check returned RandA' + if ( resp[2] == 0x00 ){ + // TODO: Create session key. + } else { + DbpString("Authetication failed."); + OnError(); + return; + } + + // TOD: Optionally, confirm ek0RndA' = RndA' to varify PICC } break; From 65348213652320c30ff5dce04374ac58c86b9acc Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Fri, 19 Dec 2014 21:37:06 -0800 Subject: [PATCH 53/78] Accept key number from command line --- armsrc/mifaredesfire.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 66fe00bd..d46d2931 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -226,7 +226,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain } cmd[0] = AUTHENTICATE; - cmd[1] = 0x00; //keynumber + cmd[1] = keyno; //keynumber len = DesfireAPDU(cmd, 2, resp); if ( !len ) { if (MF_DBGLEVEL >= 1) { @@ -236,6 +236,13 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain return; } + if ( resp[2] == 0xaf ){ + } else { + DbpString("Authetication failed. Invalid key number."); + OnError(); + return; + } + memcpy( encRndB, resp+3, 8); des_dec(&decRndB, &encRndB, &keybytes); @@ -277,7 +284,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain return; } - // TOD: Optionally, confirm ek0RndA' = RndA' to varify PICC + // TODO: Optionally, confirm ek0RndA' = RndA' to varify PICC } break; From 085b0e2ea97ae0a8427cce867428b32c79d40f9d Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Sat, 20 Dec 2014 00:10:59 -0800 Subject: [PATCH 54/78] Create session key --- armsrc/mifaredesfire.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index d46d2931..85e31751 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -219,12 +219,19 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain switch (mode){ case 1:{ uint8_t keybytes[8]; + 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); @@ -245,13 +252,15 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain memcpy( encRndB, resp+3, 8); - des_dec(&decRndB, &encRndB, &keybytes); + des_dec(&decRndB, &encRndB, key->data); + memcpy(RndB, decRndB, 8); rol(decRndB,8); uint8_t decRndA[8] = {0x00}; + memcpy(RndA, decRndA, 8); uint8_t encRndA[8] = {0x00}; - des_dec(&encRndA, &decRndA, &keybytes); + des_dec(&encRndA, &decRndA, key->data); memcpy(both, encRndA, 8); @@ -260,7 +269,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain } - des_dec(&encRndB, &decRndB, &keybytes); + des_dec(&encRndB, &decRndB, key->data); memcpy(both + 8, encRndB, 8); @@ -277,14 +286,29 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain } if ( resp[2] == 0x00 ){ - // TODO: Create session key. + + struct desfire_key sessionKey = {0}; + desfirekey_t skey = &sessionKey; + Desfire_session_key_new( RndA, RndB , key, skey ); + print_result("SESSION : ", skey->data, 8); + } else { DbpString("Authetication failed."); OnError(); return; } - // TODO: Optionally, confirm ek0RndA' = RndA' to varify PICC + 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(); + return; + } + } + } break; From 3c05723ee224b72138884c150b78c4c45ae841ba Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Sat, 20 Dec 2014 17:18:26 -0800 Subject: [PATCH 55/78] Limit to single-DES operation and return session key to client. --- armsrc/mifaredesfire.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 85e31751..42ae48ca 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -218,6 +218,8 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain // des, nyckel 0, switch (mode){ case 1:{ + if (algo == 1) { + uint8_t keybytes[8]; uint8_t RndA[8] = {0x00}; uint8_t RndB[8] = {0x00}; @@ -256,6 +258,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain 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}; @@ -290,7 +293,8 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain struct desfire_key sessionKey = {0}; desfirekey_t skey = &sessionKey; Desfire_session_key_new( RndA, RndB , key, skey ); - print_result("SESSION : ", skey->data, 8); + //print_result("SESSION : ", skey->data, 8); + cmd_send(CMD_ACK,1,0,0,skey->data,8); } else { DbpString("Authetication failed."); @@ -310,6 +314,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain } + } } break; case 2: From 6a1aa12df0e5ed2f49b7b5810734b3b391cf8fc5 Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Sat, 20 Dec 2014 19:15:48 -0800 Subject: [PATCH 56/78] Called the OnSuccess() method for whatever reason that's there. --- armsrc/mifaredesfire.c | 1 + 1 file changed, 1 insertion(+) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 42ae48ca..0a3fdc34 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -294,6 +294,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain desfirekey_t skey = &sessionKey; Desfire_session_key_new( RndA, RndB , key, skey ); //print_result("SESSION : ", skey->data, 8); + OnSuccess(); cmd_send(CMD_ACK,1,0,0,skey->data,8); } else { From 06732632308cb40fba0cde7ad87bf455a2d42e50 Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Sat, 20 Dec 2014 19:25:31 -0800 Subject: [PATCH 57/78] code to check RndA' from PICC was unreachable --- armsrc/mifaredesfire.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 0a3fdc34..e5a2289b 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -294,6 +294,18 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain 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(); + return; + } + } + OnSuccess(); cmd_send(CMD_ACK,1,0,0,skey->data,8); @@ -303,18 +315,6 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain return; } - 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(); - return; - } - } - - } } break; From 4e2e4bcf9b4399d8de4e7291298a9be5b0f9ef5d Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Sun, 21 Dec 2014 22:59:24 -0800 Subject: [PATCH 58/78] Tested by changing the master key from the default to a custom value --- armsrc/mifaredesfire.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index e5a2289b..13262991 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -306,6 +306,52 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain } } + /* + //Change the selected key to a new value. + + cmd[0] = 0xc4; + cmd[1] = keyno; + + uint8_t first,second; + + uint8_t newKey[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; + + 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); + + for (int x = 0; x < 8; x++) { + buff2[x] = buff2[x] ^ buff1[x]; + } + des_dec(&buff2, &buff2, skey->data); + + for (int x = 0; x < 8; x++) { + buff3[x] = buff3[x] ^ buff2[x]; + } + des_dec(&buff3, &buff3, skey->data); + + memcpy(cmd+2,buff1,8); + memcpy(cmd+10,buff2,8); + 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); From f56bd0174ab251eee0363be50dea0f2f18f33a03 Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Sun, 21 Dec 2014 23:41:15 -0800 Subject: [PATCH 59/78] Remove unrelated file --- client/loclass/blaine.c | 165 ---------------------------------------- 1 file changed, 165 deletions(-) delete mode 100644 client/loclass/blaine.c diff --git a/client/loclass/blaine.c b/client/loclass/blaine.c deleted file mode 100644 index 9f642fa9..00000000 --- a/client/loclass/blaine.c +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include -#include "des.h" - -int main(int argc, const char* argv[]) { - des_context ctx; - - unsigned char key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - printf("Key: "); - for (int i = 0; i < 8; i++) { - printf("%02x ", key[i]); - } - printf("\n\n"); - - // This is the challange sent from PICC - unsigned char ek0RandB[8] = {0x4f, 0xb1, 0xed, 0x2e, 0x11, 0x37, 0xd5, 0x1a}; - - if (argc == 8 + 1) { - for (int i = 0 + 1; i < 8 + 1; i++) { - ek0RandB[i - 1] = strtol(argv[i], NULL, 16); - } - } - - printf("ek0RandB (Challange): "); - for (int i = 0; i < 8; i++) { - printf("%02x ", ek0RandB[i]); - } - printf("\n\n"); - - unsigned char RandB[8]; - unsigned char RandBP[8]; - unsigned char ek0RandBP[8]; - - // TODO: Make this randomly generated - unsigned char RandA[8] = {0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - unsigned char ek0RandA[8]; - - unsigned char sessionKey[8]; - - des_setkey_dec(&ctx, key); - - //Decrypt RandB from PICC - des_crypt_ecb(&ctx, ek0RandB, RandB); - - printf("RandB: "); - for (int i = 0; i < 8; i++) { - printf("%02x ", RandB[i]); - } - printf("\n"); - - //Shift RandB left by 8 bits to produce RandB’ - for (int x = 0; x < 7; x++) { - RandBP[x] = RandB[x + 1]; - } - RandBP[7] = RandB[0]; - - printf("RandB’: "); - for (int i = 0; i < 8; i++) { - printf("%02x ", RandBP[i]); - } - printf("\n"); - - //Print RandA - printf("RandA: "); - for (int i = 0; i < 8; i++) { - printf("%02x ", RandA[i]); - } - printf("\n\n"); - - //Encrypt RandA into ek0RandA - des_crypt_ecb(&ctx, RandA, ek0RandA); - - printf("ek0RandA: "); - for (int i = 0; i < 8; i++) { - printf("%02x ", ek0RandA[i]); - } - printf("\n"); - - //Encrypt ( ek0RandA XOR RandB' ) for CBC Mode chaining - for (int i = 0; i < 8; i++) { - ek0RandBP[i] = RandBP[i] ^ ek0RandA[i]; - } - - des_crypt_ecb(&ctx, ek0RandBP, ek0RandBP); - - printf("ek0(RandB' XOR ek0RandA): "); - for (int i = 0; i < 8; i++) { - printf("%02x ", ek0RandBP[i]); - } - printf("\n\n"); - - //Varibles used in checking for proper reply from PICC - unsigned char RandAP[8]; - unsigned char ek0RandAP[8]; - - //Shift RandA left by 8 bits to produce RandA’ - for (int x = 0; x < 7; x++) { - RandAP[x] = RandA[x + 1]; - } - RandAP[7] = RandA[0]; - - //Encrypt RandA' to check PICC's response. - des_crypt_ecb(&ctx, RandAP, ek0RandAP); - - printf("ek0RandA' (Expected reply): "); - for (int i = 0; i < 8; i++) { - printf("%02x ", ek0RandAP[i]); - } - printf("\n"); - - //Create session key - sessionKey[0] = RandA[0]; - sessionKey[1] = RandA[1]; - sessionKey[2] = RandA[2]; - sessionKey[3] = RandA[3]; - sessionKey[4] = RandB[0]; - sessionKey[5] = RandB[1]; - sessionKey[6] = RandB[2]; - sessionKey[7] = RandB[3]; - - printf("Session Key: "); - for (int i = 0; i < 8; i++) { - printf("%02x ", sessionKey[i]); - } - printf("\n"); - - return 1; -} - -/* - Recorded Activity - - Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer - All times are in carrier periods (1/13.56Mhz) - - Start | End | Src | Data - -----------|-----------|-----|-------- - 0 | 992 | Rdr | 52 - 2228 | 4596 | Tag | 44 03 - 1836032 | 1838496 | Rdr | 93 20 - 1839668 | 1845492 | Tag | 88 04 6e 22 c0 - 3806976 | 3817440 | Rdr | 93 70 88 04 6e 22 c0 dc b8 - 3818676 | 3822196 | Tag | 24 d8 36 - 5815808 | 5818272 | Rdr | 95 20 - 5819444 | 5825268 | Tag | 72 63 34 80 a5 - 7757824 | 7768288 | Rdr | 95 70 72 63 34 80 a5 a7 a5 - 7769524 | 7773108 | Tag | 20 fc 70 - 9715072 | 9719840 | Rdr | e0 80 31 73 - 9721012 | 9730292 | Tag | 06 75 77 81 02 80 02 f0 - 12074624 | 12080480 | Rdr | 02 0a 00 dc ed - 12111924 | 12125812 | Tag | 02 af 4f b1 ed 2e 11 37 d5 1a bf 55 - 229214720 | 229237856 | Rdr | 03 af f3 56 83 43 79 d1 65 cd 6c 6d 17 e8 14 6e 52 eb 6d 2b - 229268916 | 229282804 | Tag | 03 00 0d 9f 27 9b a5 d8 72 60 f3 6f -*/ - -/* - hf 14a raw -p -a -b 7 52 - hf 14a raw -p 93 20 - hf 14a raw -p -c 93 70 88 04 6e 22 c0 - hf 14a raw -p 95 20 - hf 14a raw -p -c 95 70 72 63 34 80 a5 - hf 14a raw -p e0 80 31 73 - hf 14a raw -p -c 02 0a 00 - hf 14a raw -p -c 03 af ... -*/ \ No newline at end of file From 46e14b0f960dcd84fc41df32c74fb3fd89c0ac5c Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Sun, 21 Dec 2014 23:54:29 -0800 Subject: [PATCH 60/78] Minor formatting change --- armsrc/mifaredesfire.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 13262991..b7c1bc5b 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -306,16 +306,15 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain } } - /* //Change the selected key to a new value. - + /* + cmd[0] = 0xc4; cmd[1] = keyno; - uint8_t first,second; - 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}; @@ -324,24 +323,22 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain 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+2,buff1,8); - memcpy(cmd+10,buff2,8); memcpy(cmd+18,buff3,8); // The command always times out on the first attempt, this will retry until a response From 082789c4dff22a567fb81db6faf28ec6dd4a79ae Mon Sep 17 00:00:00 2001 From: Blaine Forbort Date: Mon, 22 Dec 2014 00:21:20 -0800 Subject: [PATCH 61/78] Using defined command code --- armsrc/mifaredesfire.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index b7c1bc5b..acb16c05 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -309,7 +309,7 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain //Change the selected key to a new value. /* - cmd[0] = 0xc4; + 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}; From 3bc3598e880b68870cfcc55fbdda443d77395809 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Dec 2014 15:14:05 +0100 Subject: [PATCH 62/78] added the changes from PM3 master. added some code for the AWID26 --- armsrc/iso14443a.c | 17 ++- client/cmdhf14a.c | 5 + client/cmdhficlass.c | 308 ++++++++++++++----------------------------- client/cmdlf.c | 2 +- client/cmdlfawid26.c | 117 ++++++++++++++-- client/cmdlfawid26.h | 2 + client/cmdlft55xx.c | 3 + client/util.c | 99 ++++++++++++++ client/util.h | 10 ++ 9 files changed, 343 insertions(+), 220 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index d8edc209..269a00c5 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1715,6 +1715,10 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) * fills the uid pointer unless NULL * fills resp_data unless NULL */ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { + + iso14a_set_timeout(10500); // 10ms default 10*105 = + + //uint8_t deselect[] = {0xc2}; //DESELECT //uint8_t halt[] = { 0x50, 0x00, 0x57, 0xCD }; // HALT uint8_t wupa[] = { 0x52 }; // WAKE-UP //uint8_t reqa[] = { 0x26 }; // REQUEST A @@ -1731,8 +1735,8 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u int len; // test for the SKYLANDERS TOY. - //ReaderTransmit(halt,sizeof(halt), NULL); - //len = ReaderReceive(resp, resp_par); + // ReaderTransmit(deselect,sizeof(deselect), NULL); + // len = ReaderReceive(resp, resp_par); // Broadcast for a card, WUPA (0x52) will force response from all cards in the field ReaderTransmitBitsPar(wupa,7,0, NULL); @@ -1836,7 +1840,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u p_hi14a_card->sak = sak; p_hi14a_card->ats_len = 0; } - + if( (sak & 0x20) == 0) { return 2; // non iso14443a compliant tag } @@ -1845,8 +1849,13 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); + len = ReaderReceive(resp, resp_par); - if(!len) return 0; + Dbprintf("RATS Reponse: %d", len); + if(!len) { + Dbprintf("RATS: %02x %02x %02x", resp[0], resp[1], resp[2]); + return 0; + } if(p_hi14a_card) { memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 97d102be..bfa7bfbf 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -181,6 +181,11 @@ int CmdHF14AReader(const char *Cmd) if(select_status == 0) { PrintAndLog("iso14443a card select failed"); + // disconnect + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); return 0; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index e033422a..75c6e2c9 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -43,7 +43,6 @@ int xorbits_8(uint8_t val) int CmdHFiClassList(const char *Cmd) { - bool ShowWaitCycles = false; char param = param_getchar(Cmd, 0); @@ -55,8 +54,11 @@ int CmdHFiClassList(const char *Cmd) return 0; } - uint8_t got[TRACE_BUFFER_SIZE]; - GetFromBigBuf(got,sizeof(got),0); +// for the time being. Need better Bigbuf handling. +#define TRACE_SIZE 3000 + + uint8_t trace[TRACE_SIZE]; + GetFromBigBuf(trace, TRACE_SIZE, 0); WaitForResponse(CMD_ACK,NULL); PrintAndLog("Recorded Activity"); @@ -64,155 +66,58 @@ int CmdHFiClassList(const char *Cmd) PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data"); - PrintAndLog("-----------|-----------|-----|--------"); + PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC "); + PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------"); - int i; - uint32_t first_timestamp = 0; + uint16_t tracepos = 0; + uint16_t duration; + uint16_t data_len; + uint16_t parity_len; + bool isResponse; uint32_t timestamp; - bool tagToReader; - uint32_t parityBits; - uint8_t len; - uint8_t *frame; - uint32_t EndOfTransmissionTimestamp = 0; + uint32_t first_timestamp; + uint32_t EndOfTransmissionTimestamp; + + for (;;) { + if(tracepos >= TRACE_SIZE) { + break; + } - for( i=0; i < TRACE_BUFFER_SIZE;) - { - //First 32 bits contain - // isResponse (1 bit) - // timestamp (remaining) - //Then paritybits - //Then length - timestamp = *((uint32_t *)(got+i)); - parityBits = *((uint32_t *)(got+i+4)); - len = got[i+8]; - frame = (got+i+9); - uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff; - - tagToReader = timestamp & 0x80000000; - timestamp &= 0x7fffffff; - - if(i==0) { + timestamp = *((uint32_t *)(trace + tracepos)); + if(tracepos == 0) { first_timestamp = timestamp; } - // Break and stick with current result idf buffer was not completely full - if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break; - - char line[1000] = ""; - - if(len)//We have some data to display - { - int j,oddparity; - - for(j = 0; j < len ; j++) - { - oddparity = 0x01 ^ xorbits_8(frame[j] & 0xFF); - - if (tagToReader && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } else { - sprintf(line+(j*4), "%02x ", frame[j]); - } - } - }else - { - if (ShowWaitCycles) { - sprintf(line, "fdt (Frame Delay Time): %d", (next_timestamp - timestamp)); - } - } - - char *crc = ""; - - if(len > 2) - { - uint8_t b1, b2; - if(!tagToReader && len == 4) { - // Rough guess that this is a command from the reader - // For iClass the command byte is not part of the CRC - ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2); - } - else { - // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2); - } - - if (b1 != frame[len-2] || b2 != frame[len-1]) { - crc = (tagToReader & (len < 8)) ? "" : " !crc"; - } - } - - i += (len + 9); - EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff; - - // Not implemented for iclass on the ARM-side - //if (!ShowWaitCycles) i += 9; - - PrintAndLog(" %9d | %9d | %s | %s %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (len?(tagToReader ? "Tag" : "Rdr"):" "), - line, crc); - } - return 0; -} - -int CmdHFiClassListOld(const char *Cmd) -{ - uint8_t got[1920]; - GetFromBigBuf(got,sizeof(got),0); - - PrintAndLog("recorded activity:"); - PrintAndLog(" ETU :rssi: who bytes"); - PrintAndLog("---------+----+----+-----------"); - - int i = 0; - int prev = -1; - - for (;;) { - if(i >= 1900) { - break; - } - - bool isResponse; - int timestamp = *((uint32_t *)(got+i)); - if (timestamp & 0x80000000) { - timestamp &= 0x7fffffff; - isResponse = 1; - } else { - isResponse = 0; - } - - - int metric = 0; - - int parityBits = *((uint32_t *)(got+i+4)); - // 4 bytes of additional information... - // maximum of 32 additional parity bit information - // - // TODO: - // at each quarter bit period we can send power level (16 levels) - // or each half bit period in 256 levels. - - - int len = got[i+8]; - - if (len > 100) { - break; - } - if (i + len >= 1900) { - break; - } - - uint8_t *frame = (got+i+9); - // Break and stick with current result if buffer was not completely full - if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; } + if (timestamp == 0x44444444) break; - char line[1000] = ""; - int j; - for (j = 0; j < len; j++) { + tracepos += 4; + duration = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + data_len = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + + if (data_len & 0x8000) { + data_len &= 0x7fff; + isResponse = true; + } else { + isResponse = false; + } + + parity_len = (data_len-1)/8 + 1; + + if (tracepos + data_len + parity_len >= TRACE_SIZE) { + break; + } + + uint8_t *frame = trace + tracepos; + tracepos += data_len; + uint8_t *parityBytes = trace + tracepos; + tracepos += parity_len; + + char line[16][110]; + for (int j = 0; j < data_len; j++) { int oddparity = 0x01; int k; @@ -220,79 +125,68 @@ int CmdHFiClassListOld(const char *Cmd) oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); } - //if((parityBits >> (len - j - 1)) & 0x01) { - if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } - else { - sprintf(line+(j*4), "%02x ", frame[j]); - } - } + uint8_t parityBits = parityBytes[j>>3]; + if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]); + } else { + sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]); + } - char *crc; - crc = ""; - if (len > 2) { + } + + char *crc = ""; + if (data_len > 2) { uint8_t b1, b2; - for (j = 0; j < (len - 1); j++) { - // gives problems... search for the reason.. - /*if(frame[j] == 0xAA) { - switch(frame[j+1]) { - case 0x01: - crc = "[1] Two drops close after each other"; - break; - case 0x02: - crc = "[2] Potential SOC with a drop in second half of bitperiod"; - break; - case 0x03: - crc = "[3] Segment Z after segment X is not possible"; - break; - case 0x04: - crc = "[4] Parity bit of a fully received byte was wrong"; - break; - default: - crc = "[?] Unknown error"; - break; - } - break; - }*/ - } - - if (strlen(crc)==0) { - if(!isResponse && len == 4) { + if(!isResponse && data_len == 4 ) { // Rough guess that this is a command from the reader // For iClass the command byte is not part of the CRC - ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2); + ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2); + if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { + crc = "!crc"; + } } else { // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2); - } - //printf("%1x %1x",(unsigned)b1,(unsigned)b2); - if (b1 != frame[len-2] || b2 != frame[len-1]) { - crc = (isResponse & (len < 8)) ? "" : " !crc"; + ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2); + if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { + crc = "!crc"; + } + } + } + + EndOfTransmissionTimestamp = timestamp + duration; + + int num_lines = (data_len - 1)/16 + 1; + for (int j = 0; j < num_lines; j++) { + if (j == 0) { + PrintAndLog(" %9d | %9d | %s | %-64s| %s", + (timestamp - first_timestamp), + (EndOfTransmissionTimestamp - first_timestamp), + (isResponse ? "Tag" : "Rdr"), + line[j], + (j == num_lines-1)?crc:""); } else { - crc = ""; - } - } - } else { - crc = ""; // SHORT - } + PrintAndLog(" | | | %-64s| %s", + line[j], + (j == num_lines-1)?crc:""); + } + } - char metricString[100]; - if (isResponse) { - sprintf(metricString, "%3d", metric); - } else { - strcpy(metricString, " "); - } - - PrintAndLog(" +%7d: %s: %s %s %s", - (prev < 0 ? 0 : (timestamp - prev)), - metricString, - (isResponse ? "TAG" : " "), line, crc); - - prev = timestamp; - i += (len + 9); - } + bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; + + if (ShowWaitCycles && !isResponse && next_isResponse) { + uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); + if (next_timestamp != 0x44444444) { + PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", + (EndOfTransmissionTimestamp - first_timestamp), + (next_timestamp - first_timestamp), + " ", + (next_timestamp - EndOfTransmissionTimestamp)); + } + } + + } + return 0; } diff --git a/client/cmdlf.c b/client/cmdlf.c index 2f55cd22..faf95ccd 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -581,7 +581,7 @@ static command_t CommandTable[] = {"simman", CmdLFSimManchester, 0, " [GAP] Simulate arbitrary Manchester LF tag"}, {"snoop", CmdLFSnoop, 0, "['l'|'h'|] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"}, - {"avid", CmdLFAWID26, 1, "{ AWID26 tags }"}, + {"awid26", CmdLFAWID26, 1, "{ AWID26 tags }"}, {"em4x", CmdLFEM4X, 1, "{ EM4X tags }"}, {"hid", CmdLFHID, 1, "{ HID tags }"}, {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders }"}, diff --git a/client/cmdlfawid26.c b/client/cmdlfawid26.c index 63b35fdd..0e1fca8e 100644 --- a/client/cmdlfawid26.c +++ b/client/cmdlfawid26.c @@ -12,14 +12,14 @@ #include #include "proxmark3.h" #include "ui.h" -#include "graph.h" +//#include "graph.h" #include "cmdmain.h" #include "cmdparser.h" -#include "cmddata.h" +//#include "cmddata.h" #include "cmdlf.h" #include "cmdlfawid26.h" #include "util.h" -#include "data.h" +//#include "data.h" static int CmdHelp(const char *Cmd); @@ -29,11 +29,10 @@ int CmdClone(const char *Cmd) char cmdp = param_getchar(Cmd, 0); if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: lf awid26 write []"); + PrintAndLog("Usage: lf awid26 clone "); PrintAndLog(" [], "); PrintAndLog(""); - PrintAndLog(" sample: lf awid26 write 26 2233"); - PrintAndLog(" : lf awid26 write 26 15 2233"); + PrintAndLog(" sample: lf awid26 clone 15 2233"); return 0; } @@ -50,6 +49,108 @@ int CmdClone(const char *Cmd) return 0; } + +// convert 96 bit AWID FSK data to 8 digit BCD UID +bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26) +{ + // uint8_t i, tmp[96], tmp1[7]; + // 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] != parity(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] != parity(tmp + 1, EVEN, 12)) + // return false; + // if(tmp[25] != parity(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]= parity(&awid26[i * 4], ODD, 3); + + return false; +} + // int CmdReadTrace(const char *Cmd) // { @@ -84,8 +185,8 @@ int CmdClone(const char *Cmd) static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"clone", CmdClone, 0, " -- clone to a t55xx tag"}, + {"help", CmdHelp, 1, "This help"}, + {"clone", CmdClone, 1, " -- clone AWID26 to t55xx tag"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfawid26.h b/client/cmdlfawid26.h index c0facf51..cb1cd9e2 100644 --- a/client/cmdlfawid26.h +++ b/client/cmdlfawid26.h @@ -13,4 +13,6 @@ int CmdLFAWID26(const char *Cmd); int CmdClone(const char *Cmd); +bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26); +bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd); #endif diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 78d90e7c..6ea9d2d3 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -468,6 +468,9 @@ 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; diff --git a/client/util.c b/client/util.c index 56c4998d..0418dd98 100644 --- a/client/util.c +++ b/client/util.c @@ -292,3 +292,102 @@ int param_getstr(const char *line, int paramnum, char * str) return en - bg + 1; } + +/* +The following methods comes from Rfidler sourcecode. +https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/ +*/ + +// convert hex to sequence of 0/1 bit values +// returns number of bits converted +int hextobinarray(char *target, char *source) +{ + int length, i, count= 0; + char x; + + length = strlen(source); + // process 4 bits (1 hex digit) at a time + while(length--) + { + x= *(source++); + // capitalize + if (x >= 'a' && x <= 'f') + x -= 32; + // convert to numeric value + if (x >= '0' && x <= '9') + x -= '0'; + else if (x >= 'A' && x <= 'F') + x -= 'A' - 10; + else + return 0; + // output + for(i= 0 ; i < 4 ; ++i, ++count) + *(target++)= (x >> (3 - i)) & 1; + } + + return count; +} + +// convert hex to human readable binary string +int hextobinstring(char *target, char *source) +{ + int length; + + if(!(length= hextobinarray(target, source))) + return 0; + binarraytobinstring(target, target, length); + return length; +} + +// 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) +{ + unsigned char i, x; + int j = length; + + if(j % 4) + return 0; + + while(j) + { + for(i= x= 0 ; i < 4 ; ++i) + x += ( source[i] << (3 - i)); + sprintf(target,"%X", x); + ++target; + source += 4; + j -= 4; + } + return length; +} + +// convert binary array to human readable binary +void binarraytobinstring(char *target, char *source, int length) +{ + int i; + + for(i= 0 ; i < length ; ++i) + *(target++)= *(source++) + '0'; + *target= '\0'; +} + +// return parity bit required to match type +uint8_t parity( char *bits, uint8_t type, int length) +{ + int x; + + for(x= 0 ; length > 0 ; --length) + x += bits[length - 1]; + x %= 2; + + return x ^ type; +} + +// add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half +void wiegand_add_parity(char *target, char *source, char length) +{ + *(target++)= parity(source, EVEN, length / 2); + memcpy(target, source, length); + target += length; + *(target)= parity(source + length / 2, ODD, length / 2); +} diff --git a/client/util.h b/client/util.h index 54562a07..10bafba9 100644 --- a/client/util.h +++ b/client/util.h @@ -23,6 +23,10 @@ #ifndef MAX # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#define TRUE 1 +#define FALSE 0 +#define EVEN 0 +#define ODD 1 int ukbhit(void); @@ -48,4 +52,10 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base); int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt); int param_getstr(const char *line, int paramnum, char * str); + int hextobinarray( char *target, char *source); + int hextobinstring( char *target, char *source); + int binarraytohex( char *target, char *source, int length); +void binarraytobinstring(char *target, char *source, int length); +uint8_t parity( char *string, uint8_t type, int length); +void wiegand_add_parity(char *target, char *source, char length); From 1b492a97af74c0cb6c9886bce8b777d6bb50798d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 26 Dec 2014 20:02:59 +0100 Subject: [PATCH 63/78] ADD: marshmellows new lf command and DetectClock. (works great!) FIX: a suggested patch for "hf mf csetuid" (https://github.com/Proxmark/proxmark3/issues/35) FIX: fixed a bug in iso14443a_select_card where the len variable wasnt set, this made desfire/magic cards not work. --- armsrc/iso14443a.c | 36 +-- armsrc/lfops.c | 79 +++-- armsrc/mifarecmd.c | 23 +- armsrc/mifaredesfire.c | 4 +- client/cmddata.c | 640 ++++++++++++++++++++++++++++++++++++++++- client/cmddata.h | 4 + client/cmdhf14a.c | 1 - client/cmdhfmf.c | 15 +- client/cmdlf.c | 3 + client/cmdlfawid26.c | 24 +- client/cmdlfawid26.h | 2 +- client/cmdlfhid.c | 1 + client/cmdlfio.c | 2 +- client/graph.c | 103 +++++-- client/mifarehost.c | 9 +- client/uart.c | 1 + client/util.c | 6 +- client/util.h | 2 +- 18 files changed, 852 insertions(+), 103 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 269a00c5..8399c6f8 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -394,8 +394,12 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) } else if (Uart.len & 0x0007) { // there are some parity bits to store Uart.parityBits <<= (8 - (Uart.len & 0x0007)); // left align remaining parity bits Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them - return TRUE; // we are finished with decoding the raw data sequence } + if ( Uart.len) { + return TRUE; // we are finished with decoding the raw data sequence + } else { + UartReset(); // Nothing receiver - start over + } } if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC UartReset(); @@ -556,6 +560,8 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non } else if (Demod.len & 0x0007) { // there are some parity bits to store Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + } + if (Demod.len) { return TRUE; // we are finished with decoding the raw data sequence } else { // nothing received. Start over DemodReset(); @@ -1627,7 +1633,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) { - uint16_t c; + uint32_t c; // Set FPGA mode to "reader listen mode", no modulation (listen // only, since we are receiving, not transmitting). @@ -1715,8 +1721,6 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) * fills the uid pointer unless NULL * fills resp_data unless NULL */ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { - - iso14a_set_timeout(10500); // 10ms default 10*105 = //uint8_t deselect[] = {0xc2}; //DESELECT //uint8_t halt[] = { 0x50, 0x00, 0x57, 0xCD }; // HALT @@ -1732,7 +1736,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u size_t uid_resp_len; uint8_t sak = 0x04; // cascade uid int cascade_level = 0; - int len; + int len =0; // test for the SKYLANDERS TOY. // ReaderTransmit(deselect,sizeof(deselect), NULL); @@ -1812,7 +1816,11 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u ReaderTransmit(sel_uid,sizeof(sel_uid), NULL); // Receive the SAK - if (!ReaderReceive(resp, resp_par)) return 0; + if (!ReaderReceive(resp, resp_par)){ + return 0; + } + + sak = resp[0]; // Test if more parts of the uid are coming @@ -1840,23 +1848,17 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u p_hi14a_card->sak = sak; p_hi14a_card->ats_len = 0; } - - if( (sak & 0x20) == 0) { - return 2; // non iso14443a compliant tag - } + // non iso14443a compliant tag + if( (sak & 0x20) == 0) return 2; + // Request for answer to select AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); + + if (!(len = ReaderReceive(resp, resp_par))) return 0; - len = ReaderReceive(resp, resp_par); - Dbprintf("RATS Reponse: %d", len); - if(!len) { - Dbprintf("RATS: %02x %02x %02x", resp[0], resp[1], resp[2]); - return 0; - } - if(p_hi14a_card) { memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); p_hi14a_card->ats_len = len; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index fa0516c9..5e01e9b0 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -721,14 +721,28 @@ void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) LED_A_OFF(); } +//translate wave to 11111100000 (1 for each short wave 0 for each long wave) size_t fsk_demod(uint8_t * dest, size_t size) { uint32_t last_transition = 0; uint32_t idx = 1; + uint32_t maxVal=0; + // // we don't care about actual value, only if it's more or less than a + // // threshold essentially we capture zero crossings for later analysis - // we don't care about actual value, only if it's more or less than a - // threshold essentially we capture zero crossings for later analysis - uint8_t threshold_value = 127; + // we do care about the actual value as sometimes near the center of the + // wave we may get static that changes direction of wave for one value + // if our value is too low it might affect the read. and if our tag or + // antenna is weak a setting too high might not see anything. [marshmellow] + if (size<100) return size; + for(idx=1; idx<100; idx++){ + if(maxVal= 2000) return 2000;//something bad happened + return (uint32_t) (f + (float)0.5); +} -size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, uint8_t maxConsequtiveBits, uint8_t invert ) +//translate 11111100000 to 10 +size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert )// uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, { uint8_t lastval=dest[0]; uint32_t idx=0; @@ -769,10 +789,12 @@ size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint continue; } //if lastval was 1, we have a 1->0 crossing - if ( dest[idx-1] ) { - n=(n+1) / h2l_crossing_value; + if ( dest[idx-1]==1 ) { + n=myround((float)(n+1)/((float)(rfLen)/(float)8)); + //n=(n+1) / h2l_crossing_value; } else {// 0->1 crossing - n=(n+1) / l2h_crossing_value; + n=myround((float)(n+1)/((float)(rfLen-2)/(float)10)); + //n=(n+1) / l2h_crossing_value; } if (n == 0) n = 1; @@ -792,7 +814,7 @@ size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t h2l_crossing_value,uint return numBits; } -// loop to capture raw HID waveform then FSK demodulate the TAG ID from it +// loop to get raw HID waveform then FSK demodulate the TAG ID from it void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { uint8_t *dest = get_bigbufptr_recvrespbuf(); @@ -817,7 +839,7 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) // 1->0 : fc/8 in sets of 6 (RF/50 / 8 = 6.25) // 0->1 : fc/10 in sets of 5 (RF/50 / 10= 5) // do not invert - size = aggregate_bits(dest,size, 6,5,5,0); + size = aggregate_bits(dest,size, 50,5,0); //6,5,5,0 WDT_HIT(); @@ -826,8 +848,11 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) uint8_t frame_marker_mask[] = {1,1,1,0,0,0}; int numshifts = 0; idx = 0; + //one scan + uint8_t sameCardCount =0; while( idx + sizeof(frame_marker_mask) < size) { // search for a start of frame marker + if (sameCardCount>2) break; //only up to 2 valid sets of data for the same read of looping card data if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) { // frame marker found idx+=sizeof(frame_marker_mask); @@ -905,6 +930,7 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); } + sameCardCount++; if (findone){ if (ledcontrol) LED_A_OFF(); return; @@ -955,14 +981,24 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) DoAcquisition125k_internal(-1,true); size = sizeof(BigBuf); - + //make sure buffer has data + if (size < 64) return; + //test samples are not just noise + uint8_t testMax=0; + for(idx=0;idx<64;idx++){ + if (testMax170){ + //Dbprintf("testMax: %d",testMax); // FSK demodulator size = fsk_demod(dest, size); // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns // 1->0 : fc/8 in sets of 7 (RF/64 / 8 = 8) // 0->1 : fc/10 in sets of 6 (RF/64 / 10 = 6.4) - size = aggregate_bits(dest, size, 7,6,13,1); //13 max Consecutive should be ok as most 0s in row should be 10 for init seq - invert bits - + size = aggregate_bits(dest, size, 64, 13, 1); //13 max Consecutive should be ok as most 0s in row should be 10 for init seq - invert bits + WDT_HIT(); //Index map //0 10 20 30 40 50 60 //| | | | | | | @@ -972,12 +1008,14 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) // //XSF(version)facility:codeone+codetwo //Handle the data - + uint8_t sameCardCount=0; uint8_t mask[] = {0,0,0,0,0,0,0,0,0,1}; - - for( idx=0; idx < (size - 64); idx++) { + for( idx=0; idx < (size - 74); idx++) { + if (sameCardCount>2) break; if ( memcmp(dest + idx, mask, sizeof(mask))==0) { //frame marker found + if (!dest[idx+8] && dest[idx+17]==1 && dest[idx+26]==1 && dest[idx+35]==1 && dest[idx+44]==1 && dest[idx+53]==1){ + //confirmed proper separator bits found 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]); @@ -989,9 +1027,9 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) } code = bytebits_to_byte(dest+idx,32); code2 = bytebits_to_byte(dest+idx+32,32); - short version = bytebits_to_byte(dest+idx+28,8); //14,4 - char facilitycode = bytebits_to_byte(dest+idx+19,8) ; - uint16_t number = (bytebits_to_byte(dest+idx+37,8)<<8)|(bytebits_to_byte(dest+idx+46,8)); //36,9 + short version = bytebits_to_byte(dest+idx+27,8); //14,4 + uint8_t facilitycode = bytebits_to_byte(dest+idx+19,8) ; + uint16_t number = (bytebits_to_byte(dest+idx+36,8)<<8)|(bytebits_to_byte(dest+idx+45,8)); //36,9 Dbprintf("XSF(%02d)%02x:%d (%08x%08x)",version,facilitycode,number,code,code2); @@ -1000,6 +1038,9 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) if (ledcontrol) LED_A_OFF(); isFinish = 1; break; + } + sameCardCount++; + } } } } @@ -1183,7 +1224,7 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; ++i; LED_D_OFF(); - if (i > bufferlength) break; + if (i >= bufferlength) break; } } diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index b9b8098a..1352215e 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -601,7 +601,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 for (i = 141; i < 1200; i++) { nttmp = prng_successor(nttmp, 1); - if (nttmp == nt2) {break;} + if (nttmp == nt2) break; } if (i != 1200) { @@ -945,8 +945,8 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; + // reset FPGA and LED if (workFlags & 0x08) { - // clear trace iso14a_clear_trace(); iso14a_set_tracing(TRUE); @@ -956,16 +956,18 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_B_OFF(); LED_C_OFF(); - SpinDelay(300); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(100); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + //SpinDelay(300); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + //SpinDelay(100); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); } while (true) { + // get UID from chip if (workFlags & 0x01) { if(!iso14443a_select_card(uid, NULL, &cuid)) { + Dbprintf("ICE"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; @@ -1041,7 +1043,6 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_B_OFF(); if ((workFlags & 0x10) || (!isOK)) { - // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1082,10 +1083,10 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_B_OFF(); LED_C_OFF(); - SpinDelay(300); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(100); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + // SpinDelay(300); + // FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // SpinDelay(100); + // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); } while (true) { diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 0d8de438..56166777 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -32,9 +32,7 @@ bool InitDesfireCard(){ int len = iso14443a_select_card(NULL,card,NULL); if (!len) { - if (MF_DBGLEVEL >= 1) { - Dbprintf("Can't select card"); - } + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); OnError(); return false; } diff --git a/client/cmddata.c b/client/cmddata.c index 0ba04b79..b2c68b97 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -70,6 +70,7 @@ int CmdAmp(const char *Cmd) * Arguments: * c : 0 or 1 */ + //this method is dependant on all highs and lows to be the same(or clipped) this creates issues[marshmellow] it also ignores the clock int Cmdaskdemod(const char *Cmd) { int i; @@ -118,6 +119,274 @@ int Cmdaskdemod(const char *Cmd) return 0; } +void printBitStream(int BitStream[], uint32_t bitLen){ + uint32_t i = 0; + if (bitLen<16) return; + if (bitLen>512) bitLen=512; + for (i = 0; i < (bitLen-16); i+=16) { + PrintAndLog("%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", + BitStream[i], + BitStream[i+1], + BitStream[i+2], + BitStream[i+3], + BitStream[i+4], + BitStream[i+5], + BitStream[i+6], + BitStream[i+7], + BitStream[i+8], + BitStream[i+9], + BitStream[i+10], + BitStream[i+11], + BitStream[i+12], + BitStream[i+13], + BitStream[i+14], + BitStream[i+15]); + } + return; +} +void printBitStream2(uint8_t BitStream[], uint32_t bitLen){ + uint32_t i = 0; + if (bitLen<16) { + PrintAndLog("Too few bits found: %d",bitLen); + return; + } + if (bitLen>512) bitLen=512; + for (i = 0; i < (bitLen-16); i+=16) { + PrintAndLog("%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", + BitStream[i], + BitStream[i+1], + BitStream[i+2], + BitStream[i+3], + BitStream[i+4], + BitStream[i+5], + BitStream[i+6], + BitStream[i+7], + BitStream[i+8], + BitStream[i+9], + BitStream[i+10], + BitStream[i+11], + BitStream[i+12], + BitStream[i+13], + BitStream[i+14], + BitStream[i+15]); + } + return; +} + +//by marshmellow +//takes 1s and 0s and searches for EM410x format - output EM ID +int Em410xDecode(const char *Cmd) +{ + //no arguments needed - built this way in case we want this to be a direct call from "data " cmds in the future + // otherwise could be a void with no arguments + //set defaults + int high=0, low=0; + uint64_t lo=0; //hi=0, + + uint32_t i = 0; + uint32_t initLoopMax = 1000; + if (initLoopMax>GraphTraceLen) initLoopMax=GraphTraceLen; + + for (;i < initLoopMax; ++i) //1000 samples should be plenty to find high and low values + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + if (((high !=1)||(low !=0))){ //allow only 1s and 0s + PrintAndLog("no data found"); + return 0; + } + uint8_t parityTest=0; + // 111111111 bit pattern represent start of frame + int frame_marker_mask[] = {1,1,1,1,1,1,1,1,1}; + uint32_t idx = 0; + uint32_t ii=0; + uint8_t resetCnt = 0; + while( (idx + 64) < GraphTraceLen) { +restart: + // search for a start of frame marker + if ( memcmp(GraphBuffer+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { // frame marker found + idx+=9;//sizeof(frame_marker_mask); + for (i=0; i<10;i++){ + for(ii=0; ii<5; ++ii){ + parityTest += GraphBuffer[(i*5)+ii+idx]; + } + if (parityTest== ((parityTest>>1)<<1)){ + parityTest=0; + for (ii=0; ii<4;++ii){ + //hi = (hi<<1)|(lo>>31); + lo=(lo<<1LL)|(GraphBuffer[(i*5)+ii+idx]); + } + //PrintAndLog("DEBUG: EM parity passed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d,lo: %d",parityTest,i,ii,idx,GraphBuffer[idx+ii+(i*5)-5],GraphBuffer[idx+ii+(i*5)-4],GraphBuffer[idx+ii+(i*5)-3],GraphBuffer[idx+ii+(i*5)-2],GraphBuffer[idx+ii+(i*5)-1],lo); + }else {//parity failed + //PrintAndLog("DEBUG: EM parity failed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d",parityTest,i,ii,idx,GraphBuffer[idx+ii+(i*5)-5],GraphBuffer[idx+ii+(i*5)-4],GraphBuffer[idx+ii+(i*5)-3],GraphBuffer[idx+ii+(i*5)-2],GraphBuffer[idx+ii+(i*5)-1]); + parityTest=0; + idx-=8; + if (resetCnt>5)return 0; + resetCnt++; + goto restart;//continue; + } + } + //skip last 5 bit parity test for simplicity. + + //get Unique ID + uint64_t iii=1; + uint64_t id2lo=0; //id2hi=0, + //for (i=0;i<8;i++){ //for uint32 instead of uint64 + // id2hi=(id2hi<<1)|((hi & (iii<<(i)))>>i); + //} + for (ii=5; ii>0;ii--){ + for (i=0;i<8;i++){ + id2lo=(id2lo<<1LL)|((lo & (iii<<(i+((ii-1)*8))))>>(i+((ii-1)*8))); + } + } + //output em id + PrintAndLog("EM TAG ID : %010llx", lo); + PrintAndLog("Unique TAG ID: %010llx", id2lo); //id2hi, + PrintAndLog("DEZ 8 : %08lld",lo & 0xFFFFFF); + PrintAndLog("DEZ 10 : %010lld",lo & 0xFFFFFF); + PrintAndLog("DEZ 5.5 : %05lld.%05lld",(lo>>16LL) & 0xFFFF,(lo & 0xFFFF)); + PrintAndLog("DEZ 3.5A : %03lld.%05lld",(lo>>32ll),(lo & 0xFFFF)); + PrintAndLog("DEZ 14/IK2 : %014lld",lo); + PrintAndLog("DEZ 15/IK3 : %015lld",id2lo); + PrintAndLog("Other : %05lld_%03lld_%08lld",(lo&0xFFFF),((lo>>16LL) & 0xFF),(lo & 0xFFFFFF)); + return 0; + }else{ + idx++; + } + } + return 0; +} + + +//by marshmellow +//takes 2 arguments - clock and invert both as integers +//prints binary found and saves in graphbuffer for further commands +int Cmdaskmandemod(const char *Cmd) +{ + uint32_t i; + int invert=0; //invert default + int high = 0, low = 0; + int clk=DetectClock(0); //clock default + uint8_t BitStream[MAX_GRAPH_TRACE_LEN] = {0}; + sscanf(Cmd, "%i %i", &clk, &invert); + if (clk<8) clk =64; + if (clk<32) clk=32; + if (invert != 0 && invert != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + uint32_t initLoopMax = 1000; + if (initLoopMax>GraphTraceLen) initLoopMax=GraphTraceLen; + // Detect high and lows + PrintAndLog("Using Clock: %d and invert=%d",clk,invert); + for (i = 0; i < initLoopMax; ++i) //1000 samples should be plenty to find high and low values + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + if ((high < 30) && ((high !=1)||(low !=-1))){ //throw away static - allow 1 and -1 (in case of threshold command first) + PrintAndLog("no data found"); + return 0; + } + //13% fuzz in case highs and lows aren't clipped [marshmellow] + high=(int)(0.75*high); + low=(int)(0.75*low); + + //PrintAndLog("DEBUG - valid high: %d - valid low: %d",high,low); + int lastBit = 0; //set first clock check + uint32_t bitnum = 0; //output counter + uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave + if (clk==32)tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely + uint32_t iii = 0; + uint32_t gLen = GraphTraceLen; + if (gLen > 500) gLen=500; + uint8_t errCnt =0; + uint32_t bestStart = GraphTraceLen; + uint32_t bestErrCnt = (GraphTraceLen/1000); + //PrintAndLog("DEBUG - lastbit - %d",lastBit); + //loop to find first wave that works + for (iii=0; iii < gLen; ++iii){ + if ((GraphBuffer[iii]>=high)||(GraphBuffer[iii]<=low)){ + lastBit=iii-clk; + //loop through to see if this start location works + for (i = iii; i < GraphTraceLen; ++i) { + if ((GraphBuffer[i] >= high) && ((i-lastBit)>(clk-tol))){ + lastBit+=clk; + BitStream[bitnum] = invert; + bitnum++; + } else if ((GraphBuffer[i] <= low) && ((i-lastBit)>(clk-tol))){ + //low found and we are expecting a bar + lastBit+=clk; + BitStream[bitnum] = 1-invert; + bitnum++; + } else { + //mid value found or no bar supposed to be here + if ((i-lastBit)>(clk+tol)){ + //should have hit a high or low based on clock!! + + + //debug + //PrintAndLog("DEBUG - no wave in expected area - location: %d, expected: %d-%d, lastBit: %d - resetting search",i,(lastBit+(clk-((int)(tol)))),(lastBit+(clk+((int)(tol)))),lastBit); + if (bitnum > 0){ + BitStream[bitnum]=77; + bitnum++; + } + + + errCnt++; + lastBit+=clk;//skip over until hit too many errors + if (errCnt>((GraphTraceLen/1000))){ //allow 1 error for every 1000 samples else start over + errCnt=0; + bitnum=0;//start over + break; + } + } + } + } + //we got more than 64 good bits and not all errors + if ((bitnum > (64+errCnt)) && (errCnt<(GraphTraceLen/1000))) { + //possible good read + if (errCnt==0) break; //great read - finish + if (bestStart == iii) break; //if current run == bestErrCnt run (after exhausted testing) then finish + if (errCnt=gLen){ //exhausted test + //if there was a ok test go back to that one and re-run the best run (then dump after that run) + if (bestErrCnt < (GraphTraceLen/1000)) iii=bestStart; + } + } + if (bitnum>16){ + + PrintAndLog("Data start pos:%d, lastBit:%d, stop pos:%d, numBits:%d",iii,lastBit,i,bitnum); + //move BitStream back to GraphBuffer + ClearGraph(0); + for (i=0; i < bitnum; ++i){ + GraphBuffer[i]=BitStream[i]; + } + GraphTraceLen=bitnum; + RepaintGraphWindow(); + //output + if (errCnt>0){ + PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); + } + PrintAndLog("ASK decoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + printBitStream2(BitStream,bitnum); + Em410xDecode(Cmd); + } + return 0; +} + int CmdAutoCorr(const char *Cmd) { static int CorrelBuffer[MAX_GRAPH_TRACE_LEN]; @@ -263,7 +532,370 @@ int CmdDetectClockRate(const char *Cmd) return 0; } -int CmdFSKdemod(const char *Cmd) +//by marshmellow +//demod GraphBuffer wave to 0s and 1s for each wave - 0s for short waves 1s for long waves +size_t fsk_wave_demod(int size) +{ + uint32_t last_transition = 0; + uint32_t idx = 1; + uint32_t maxVal = 0; + // we don't care about actual value, only if it's more or less than a + // threshold essentially we capture zero crossings for later analysis + for(idx=1; idx1 transition + if (GraphBuffer[idx-1] < GraphBuffer[idx]) { // 0 -> 1 transition + if (idx-last_transition<6){ + // do nothing with extra garbage (shouldn't be any) noise tolerance? + } else if(idx-last_transition < 9) { + GraphBuffer[numBits]=1; + // Other fsk demods reverse this making the short waves 1 and long waves 0 + // this is really backwards... smaller waves will typically be 0 and larger 1 [marshmellow] + // but will leave as is and invert when needed later + } else{ + GraphBuffer[numBits]=0; + } + last_transition = idx; + numBits++; + // PrintAndLog("numbits %d",numBits); + } + } + return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 +} +uint32_t myround(float f) +{ + if (f >= UINT_MAX) return UINT_MAX; + return (uint32_t) (f + (float)0.5); +} + +//by marshmellow (from holiman's base) +//translate 11111100000 to 10 +size_t aggregate_bits(int size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert) //,uint8_t l2h_crossing_value +{ + int lastval=GraphBuffer[0]; + uint32_t idx=0; + size_t numBits=0; + uint32_t n=1; + uint32_t n2=0; + for( idx=1; idx < size; idx++) { + + if (GraphBuffer[idx]==lastval) { + n++; + continue; + } + // if lastval was 1, we have a 1->0 crossing + if ( GraphBuffer[idx-1]==1 ) { + n=myround((float)(n+1)/((float)(rfLen)/(float)8)); //-2 noise tolerance + + // n=(n+1) / h2l_crossing_value; + //truncating could get us into trouble + //now we will try with actual clock (RF/64 or RF/50) variable instead + //then devide with float casting then truncate after more acurate division + //and round to nearest int + //like n = (((float)n)/(float)rfLen/(float)10); + } else {// 0->1 crossing + n=myround((float)(n+1)/((float)(rfLen-2)/(float)10)); // as int 120/6 = 20 as float 120/(64/10) = 18 (18.75) + //n=(n+1) / l2h_crossing_value; + } + if (n == 0) n = 1; //this should never happen... should we error if it does? + + if (n < maxConsequtiveBits) // Consecutive //when the consecutive bits are low - the noise tolerance can be high + //if it is high then we must be careful how much noise tolerance we allow + { + if (invert==0){ // do not invert bits + for (n2=0; n20 && strlen(Cmd)<=2) { + rfLen=param_get8(Cmd, 0); //if rfLen option only is used + if (rfLen==1){ + invert=1; //if invert option only is used + rfLen = 50; + } else if(rfLen==0) rfLen=50; + } + if (strlen(Cmd)>2) { + rfLen=param_get8(Cmd, 0); //if both options are used + invert=param_get8(Cmd,1); + } + PrintAndLog("Args invert: %d \nClock:%d",invert,rfLen); + + size_t size = fskdemod(rfLen,invert); + + PrintAndLog("FSK decoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + if(size > (7*32)+2) size = (7*32)+2; //only output a max of 7 blocks of 32 bits most tags will have full bit stream inside that sample size + printBitStream(GraphBuffer,size); + + ClearGraph(1); + return 0; +} + +//by marshmellow +int CmdFSKdemodHID(const char *Cmd) +{ + //raw fsk demod no manchester decoding no start bit finding just get binary from wave + //set defaults + uint8_t rfLen = 50; + uint8_t invert=0;//param_get8(Cmd, 0); + size_t idx=0; + uint32_t hi2=0, hi=0, lo=0; + + //get binary from fsk wave + size_t size = fskdemod(rfLen,invert); + + // final loop, go over previously decoded fsk data and now manchester decode into usable tag ID + // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 + int frame_marker_mask[] = {1,1,1,0,0,0}; + int numshifts = 0; + idx = 0; + while( idx + 6 < size) { + // search for a start of frame marker + + if ( memcmp(GraphBuffer+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { // frame marker found + idx+=6;//sizeof(frame_marker_mask); //size of int is >6 + while(GraphBuffer[idx] != GraphBuffer[idx+1] && idx < size-2) + { + // Keep going until next frame marker (or error) + // Shift in a bit. Start by shifting high registers + hi2 = (hi2<<1)|(hi>>31); + hi = (hi<<1)|(lo>>31); + //Then, shift in a 0 or one into low + if (GraphBuffer[idx] && !GraphBuffer[idx+1]) // 1 0 + lo=(lo<<1)|0; + else // 0 1 + lo=(lo<<1)|1; + numshifts++; + idx += 2; + } + + //PrintAndLog("Num shifts: %d ", numshifts); + // Hopefully, we read a tag and hit upon the next frame marker + if(idx + 6 < size) + { + if ( memcmp(GraphBuffer+(idx), frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { + if (hi2 != 0){ //extra large HID tags + PrintAndLog("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + } + else { //standard HID tags <38 bits + //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd + uint8_t bitlen = 0; + uint32_t fc = 0; + uint32_t cardnum = 0; + if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used + uint32_t lo2=0; + lo2=(((hi & 15) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit + uint8_t idx3 = 1; + while(lo2>1){ //find last bit set to 1 (format len bit) + lo2=lo2>>1; + idx3++; + } + bitlen =idx3+19; + fc =0; + cardnum=0; + if(bitlen==26){ + cardnum = (lo>>1)&0xFFFF; + fc = (lo>>17)&0xFF; + } + if(bitlen==37){ + cardnum = (lo>>1)&0x7FFFF; + fc = ((hi&0xF)<<12)|(lo>>20); + } + if(bitlen==34){ + cardnum = (lo>>1)&0xFFFF; + fc= ((hi&1)<<15)|(lo>>17); + } + if(bitlen==35){ + cardnum = (lo>>1)&0xFFFFF; + fc = ((hi&1)<<11)|(lo>>21); + } + } + else { //if bit 38 is not set then 37 bit format is used + bitlen= 37; + fc =0; + cardnum=0; + if(bitlen==37){ + cardnum = (lo>>1)&0x7FFFF; + fc = ((hi&0xF)<<12)|(lo>>20); + } + } + + PrintAndLog("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, + (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); + ClearGraph(1); + return 0; + } + } + } + // reset + hi2 = hi = lo = 0; + numshifts = 0; + }else + { + idx++; + } + } + if (idx + sizeof(frame_marker_mask) >= size){ + PrintAndLog("start bits for hid not found"); + PrintAndLog("FSK decoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + printBitStream(GraphBuffer,size); + + } + ClearGraph(1); + return 0; +} + +//by marshmellow +int CmdFSKdemodIO(const char *Cmd) +{ + //raw fsk demod no manchester decoding no start bit finding just get binary from wave + //set defaults + uint8_t rfLen = 64; + uint8_t invert=1; + size_t idx=0; + uint8_t testMax=0; + //test samples are not just noise + if (GraphTraceLen < 64) return 0; + for(idx=0;idx<64;idx++){ + if (testMax40){ + //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 (raw) + //Handle the data + int mask[] = {0,0,0,0,0,0,0,0,0,1}; + for( idx=0; idx < (size - 74); idx++) { + if ( memcmp(GraphBuffer + idx, mask, sizeof(mask))==0) { + //frame marker found + if (GraphBuffer[idx+17]==1 && GraphBuffer[idx+26]==1 && GraphBuffer[idx+35]==1 && GraphBuffer[idx+44]==1 && GraphBuffer[idx+53]==1){ + //confirmed proper separator bits found + + PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx], GraphBuffer[idx+1], GraphBuffer[idx+2], GraphBuffer[idx+3], GraphBuffer[idx+4], GraphBuffer[idx+5], GraphBuffer[idx+6], GraphBuffer[idx+7], GraphBuffer[idx+8]); + PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+9], GraphBuffer[idx+10], GraphBuffer[idx+11],GraphBuffer[idx+12],GraphBuffer[idx+13],GraphBuffer[idx+14],GraphBuffer[idx+15],GraphBuffer[idx+16],GraphBuffer[idx+17]); + PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+18], GraphBuffer[idx+19], GraphBuffer[idx+20],GraphBuffer[idx+21],GraphBuffer[idx+22],GraphBuffer[idx+23],GraphBuffer[idx+24],GraphBuffer[idx+25],GraphBuffer[idx+26]); + PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+27], GraphBuffer[idx+28], GraphBuffer[idx+29],GraphBuffer[idx+30],GraphBuffer[idx+31],GraphBuffer[idx+32],GraphBuffer[idx+33],GraphBuffer[idx+34],GraphBuffer[idx+35]); + PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+36], GraphBuffer[idx+37], GraphBuffer[idx+38],GraphBuffer[idx+39],GraphBuffer[idx+40],GraphBuffer[idx+41],GraphBuffer[idx+42],GraphBuffer[idx+43],GraphBuffer[idx+44]); + PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+45], GraphBuffer[idx+46], GraphBuffer[idx+47],GraphBuffer[idx+48],GraphBuffer[idx+49],GraphBuffer[idx+50],GraphBuffer[idx+51],GraphBuffer[idx+52],GraphBuffer[idx+53]); + PrintAndLog("%d%d%d%d%d%d%d%d %d%d",GraphBuffer[idx+54],GraphBuffer[idx+55],GraphBuffer[idx+56],GraphBuffer[idx+57],GraphBuffer[idx+58],GraphBuffer[idx+59],GraphBuffer[idx+60],GraphBuffer[idx+61],GraphBuffer[idx+62],GraphBuffer[idx+63]); + + uint32_t code = bytebits_to_byte(GraphBuffer+idx,32); + uint32_t code2 = bytebits_to_byte(GraphBuffer+idx+32,32); + short version = bytebits_to_byte(GraphBuffer+idx+27,8); //14,4 + uint8_t facilitycode = bytebits_to_byte(GraphBuffer+idx+19,8) ; + uint16_t number = (bytebits_to_byte(GraphBuffer+idx+36,8)<<8)|(bytebits_to_byte(GraphBuffer+idx+45,8)); //36,9 + + PrintAndLog("XSF(%02d)%02x:%d (%08x%08x)",version,facilitycode,number,code,code2); + ClearGraph(1); + return 0; + } else { + PrintAndLog("thought we had a valid tag but did not match format"); + } + } + } + if (idx >= (size-74)){ + PrintAndLog("start bits for io prox not found"); + PrintAndLog("FSK decoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + printBitStream(GraphBuffer,size); + } + } + ClearGraph(1); + return 0; +} +int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating { static const int LowTone[] = { 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, @@ -320,7 +952,7 @@ int CmdFSKdemod(const char *Cmd) GraphTraceLen -= (convLen + 16); RepaintGraphWindow(); - // Find bit-sync (3 lo followed by 3 high) + // Find bit-sync (3 lo followed by 3 high) (HID ONLY) int max = 0, maxPos = 0; for (i = 0; i < 6000; ++i) { int dec = 0; @@ -954,6 +1586,7 @@ static command_t CommandTable[] = {"help", CmdHelp, 1, "This help"}, {"amp", CmdAmp, 1, "Amplify peaks"}, {"askdemod", Cmdaskdemod, 1, "<0|1> -- Attempt to demodulate simple ASK tags"}, + {"askmandemod", Cmdaskmandemod, 1, "[clock] [invert<0 or 1>] -- Attempt to demodulate ASK/Manchester tags and output binary (args optional[clock will try Auto-detect])"}, {"autocorr", CmdAutoCorr, 1, " -- Autocorrelation over window"}, {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"}, {"bitstream", CmdBitstream, 1, "[clock rate] -- Convert waveform into a bitstream"}, @@ -962,6 +1595,9 @@ static command_t CommandTable[] = {"detectclock", CmdDetectClockRate, 1, "Detect clock rate"}, {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"}, + {"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate graph window as a HID FSK using raw"}, + {"fskiodemod", CmdFSKdemodIO, 1, "Demodulate graph window as an IO Prox FSK using raw"}, + {"fskrawdemod", CmdFSKrawdemod, 1, "[clock rate] [invert] Demodulate graph window from FSK to binary (clock = 64 or 50)(invert = 1 or 0)"}, {"grid", CmdGrid, 1, " -- overlay grid on graph window, use zero value to turn off either"}, {"hexsamples", CmdHexsamples, 0, " [] -- Dump big buffer as hex bytes"}, {"hide", CmdHide, 1, "Hide graph window"}, diff --git a/client/cmddata.h b/client/cmddata.h index 8073c34c..432ae687 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -17,6 +17,7 @@ int CmdData(const char *Cmd); int CmdAmp(const char *Cmd); int Cmdaskdemod(const char *Cmd); +int Cmdaskrawdemod(const char *Cmd); int CmdAutoCorr(const char *Cmd); int CmdBitsamples(const char *Cmd); int CmdBitstream(const char *Cmd); @@ -24,6 +25,9 @@ int CmdBuffClear(const char *Cmd); int CmdDec(const char *Cmd); int CmdDetectClockRate(const char *Cmd); int CmdFSKdemod(const char *Cmd); +int CmdFSKdemodHID(const char *Cmd); +int CmdFSKdemodIO(const char *Cmd); +int CmdFSKrawdemod(const char *Cmd); int CmdGrid(const char *Cmd); int CmdHexsamples(const char *Cmd); int CmdHide(const char *Cmd); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index bfa7bfbf..f09c555b 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -231,7 +231,6 @@ int CmdHF14AReader(const char *Cmd) c.arg[1] = 0; c.arg[2] = 0; SendCommand(&c); - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes bool ta1 = 0, tb1 = 0, tc1 = 0; diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 748e9c45..f32ae444 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -124,10 +124,10 @@ int CmdHF14AMfWrBl(const char *Cmd) PrintAndLog("--block no:%d, key type:%c, key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6)); PrintAndLog("--data: %s", sprint_hex(bldata, 16)); - UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; + UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); memcpy(c.d.asBytes + 10, bldata, 16); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -168,9 +168,9 @@ int CmdHF14AMfRdBl(const char *Cmd) } PrintAndLog("--block no:%d, key type:%c, key:%s ", blockNo, keyType?'B':'A', sprint_hex(key, 6)); - UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; + UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -1460,11 +1460,12 @@ int CmdHF14AMfCSetUID(const char *Cmd) res = mfCSetUID(uid, oldUid, wipeCard); if (res) { - PrintAndLog("Can't set UID. error=%d", res); - return 1; - } + PrintAndLog("Can't set UID. error=%d", res); + return 1; + } PrintAndLog("old UID:%s", sprint_hex(oldUid, 4)); + PrintAndLog("new UID:%s", sprint_hex(uid, 4)); return 0; } diff --git a/client/cmdlf.c b/client/cmdlf.c index faf95ccd..97dcf0ba 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -371,6 +371,9 @@ int CmdLFRead(const char *Cmd) } SendCommand(&c); WaitForResponse(CMD_ACK,NULL); + + // load samples + CmdSamples(""); return 0; } diff --git a/client/cmdlfawid26.c b/client/cmdlfawid26.c index 0e1fca8e..71f227f2 100644 --- a/client/cmdlfawid26.c +++ b/client/cmdlfawid26.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "proxmark3.h" #include "ui.h" //#include "graph.h" @@ -43,22 +44,25 @@ int CmdClone(const char *Cmd) // 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, unsigned char *awid26) +bool awid26_hex_to_uid(unsigned char *response, char *awid26) { - // uint8_t i, tmp[96], tmp1[7]; - // int site; - // int id; + uint8_t i, tmp[96], tmp1[7]; + int site; + int id; - // if(!hextobinarray(tmp, awid26)) - // return false; + 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 @@ -71,7 +75,7 @@ bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26) // // check and strip parity on the rest // for(i= 1 ; i < 23 ; ++i) - // if(tmp[(i * 4) - 1] != parity(tmp + (i - 1) * 4, ODD, 3)) + // 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); @@ -86,9 +90,9 @@ bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26) // memcpy(tmp, tmp +8, 58); // // standard wiegand parity check - even for 1st 12 bits, odd for 2nd 12 - // if(tmp[0] != parity(tmp + 1, EVEN, 12)) + // if(tmp[0] != GetParity(tmp + 1, EVEN, 12)) // return false; - // if(tmp[25] != parity(tmp + 13, ODD, 12)) + // if(tmp[25] != GetParity(tmp + 13, ODD, 12)) // return false; // // convert to hex, ignoring parity bits @@ -146,7 +150,7 @@ bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd) // // add parity bits // for(i= 1 ; i < 24 ; ++i) - // awid26[((i + 1) * 4) - 1]= parity(&awid26[i * 4], ODD, 3); + // awid26[((i + 1) * 4) - 1]= GetParity(&awid26[i * 4], ODD, 3); return false; } diff --git a/client/cmdlfawid26.h b/client/cmdlfawid26.h index cb1cd9e2..7c23d567 100644 --- a/client/cmdlfawid26.h +++ b/client/cmdlfawid26.h @@ -13,6 +13,6 @@ int CmdLFAWID26(const char *Cmd); int CmdClone(const char *Cmd); -bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26); +bool awid26_hex_to_uid(unsigned char *response, char *awid26); bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd); #endif diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index ce21ddc8..93d06406 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -58,6 +58,7 @@ int CmdHIDSim(const char *Cmd) } PrintAndLog("Emulating tag with ID %x%16x", hi, lo); + PrintAndLog("Press pm3-button to abort simulation"); UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}}; SendCommand(&c); diff --git a/client/cmdlfio.c b/client/cmdlfio.c index 78d8fa21..129323ac 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -55,7 +55,7 @@ int CmdIOClone(const char *Cmd) } PrintAndLog("Cloning tag with ID %08x %08x", hi, lo); - + PrintAndLog("Press pm3-button to abort simulation"); c.cmd = CMD_IO_CLONE_TAG; c.arg[0] = hi; c.arg[1] = lo; diff --git a/client/graph.c b/client/graph.c index 7b45f3f2..bb815995 100644 --- a/client/graph.c +++ b/client/graph.c @@ -51,13 +51,15 @@ int ClearGraph(int redraw) /* * Detect clock rate */ -int DetectClock(int peak) + //decommissioned - has difficulty detecting rf/32 and only works if data is manchester encoded +/* +int DetectClock2(int peak) { int i; int clock = 0xFFFF; int lastpeak = 0; - /* Detect peak if we don't have one */ + // Detect peak if we don't have one if (!peak) for (i = 0; i < GraphTraceLen; ++i) if (GraphBuffer[i] > peak) @@ -65,36 +67,90 @@ int DetectClock(int peak) for (i = 1; i < GraphTraceLen; ++i) { - /* If this is the beginning of a peak */ - if (GraphBuffer[i - 1] != GraphBuffer[i] && GraphBuffer[i] == peak) + // If this is the beginning of a peak + if (GraphBuffer[i - 1] != GraphBuffer[i] && GraphBuffer[i] >= peak) { - /* Find lowest difference between peaks */ + // Find lowest difference between peaks if (lastpeak && i - lastpeak < clock) clock = i - lastpeak; lastpeak = i; } } - int clockmod = clock%8; - if ( clockmod == 0) return clock; - - // When detected clock is 31 or 33 then return 32 - - printf("Found clock at %d ", clock); - switch( clockmod ) - { - case 7: clock++; break; - case 6: clock += 2 ; break; - case 1: clock--; break; - case 2: clock -= 2; break; - } - if ( clock < 32) - clock = 32; - - printf("- adjusted it to %d \n", clock); - return clock; } +*/ + +// by marshmellow +// not perfect especially with lower clocks or VERY good antennas (heavy wave clipping) +// maybe somehow adjust peak trimming value based on samples to fix? +int DetectClock(int peak) + { + int i=0; + int low=0; + int clk[]={16,32,40,50,64,100,128,256}; + if (!peak){ + for (i=0;ipeak){ + peak = GraphBuffer[i]; + } + if(GraphBuffer[i]=peak) || (GraphBuffer[ii]<=low)){ + //numbits=0; + //good=1; + errCnt[clkCnt]=0; + for (i=0; i<((int)(GraphTraceLen/clk[clkCnt])-1); ++i){ + if (GraphBuffer[ii+(i*clk[clkCnt])]>=peak || GraphBuffer[ii+(i*clk[clkCnt])]<=low){ + //numbits++; + }else if(GraphBuffer[ii+(i*clk[clkCnt])-tol]>=peak || GraphBuffer[ii+(i*clk[clkCnt])-tol]<=low){ + }else if(GraphBuffer[ii+(i*clk[clkCnt])+tol]>=peak || GraphBuffer[ii+(i*clk[clkCnt])+tol]<=low){ + }else{ //error no peak detected + //numbits=0; + //good=0; + errCnt[clkCnt]++; + //break; + } + } + if(errCnt[clkCnt]==0) return clk[clkCnt]; + if(errCnt[clkCnt]fd, F_SETLK, &fl) == -1) { // A conflicting lock is held by another process + free(sp); return CLAIMED_SERIAL_PORT; } diff --git a/client/util.c b/client/util.c index 0418dd98..b8d5c316 100644 --- a/client/util.c +++ b/client/util.c @@ -372,7 +372,7 @@ void binarraytobinstring(char *target, char *source, int length) } // return parity bit required to match type -uint8_t parity( char *bits, uint8_t type, int length) +uint8_t GetParity( char *bits, uint8_t type, int length) { int x; @@ -386,8 +386,8 @@ uint8_t parity( char *bits, uint8_t type, int length) // add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half void wiegand_add_parity(char *target, char *source, char length) { - *(target++)= parity(source, EVEN, length / 2); + *(target++)= GetParity(source, EVEN, length / 2); memcpy(target, source, length); target += length; - *(target)= parity(source + length / 2, ODD, length / 2); + *(target)= GetParity(source + length / 2, ODD, length / 2); } diff --git a/client/util.h b/client/util.h index 10bafba9..22d41e0c 100644 --- a/client/util.h +++ b/client/util.h @@ -56,6 +56,6 @@ int param_getstr(const char *line, int paramnum, char * str); int hextobinstring( char *target, char *source); int binarraytohex( char *target, char *source, int length); void binarraytobinstring(char *target, char *source, int length); -uint8_t parity( char *string, uint8_t type, int length); +uint8_t GetParity( char *string, uint8_t type, int length); void wiegand_add_parity(char *target, char *source, char length); From d52e4e881910964f151e0ea51dd5621e6ab6315e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 26 Dec 2014 21:32:58 +0100 Subject: [PATCH 64/78] ADD: HF 14A READER is now able to see if a presented card responses to the chinese magic backdoor commands. FIX: simple namechange of some defines where it hinted it was related to "eml" when it wasn't. --- armsrc/appmain.c | 7 +++-- armsrc/apps.h | 1 + armsrc/mifarecmd.c | 70 ++++++++++++++++++++++++++---------------- armsrc/mifaredesfire.c | 4 +-- client/cmdhf14a.c | 23 ++++++++++---- include/usb_cmd.h | 7 +++-- 6 files changed, 73 insertions(+), 39 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c3cf3999..33944c1d 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -854,12 +854,15 @@ void UsbPacketReceived(uint8_t *packet, int len) break; // Work with "magic Chinese" card - case CMD_MIFARE_EML_CSETBLOCK: + case CMD_MIFARE_CSETBLOCK: MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; - case CMD_MIFARE_EML_CGETBLOCK: + case CMD_MIFARE_CGETBLOCK: MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; + case CMD_MIFARE_CIDENT: + MifareCIdent(); + break; // mifare sniffer case CMD_MIFARE_SNIFFER: diff --git a/armsrc/apps.h b/armsrc/apps.h index 6725741f..5e1926f9 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -211,6 +211,7 @@ void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareCIdent(); // is "magic chinese" card? // mifaredesfire.h bool InitDesfireCard(); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 1352215e..ee2132ef 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -937,29 +937,22 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // variables byte_t isOK = 0; - uint8_t uid[10]; - uint8_t d_block[18]; + uint8_t uid[10] = {0x00}; + uint8_t d_block[18] = {0x00}; uint32_t cuid; - memset(uid, 0x00, 10); uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; // reset FPGA and LED if (workFlags & 0x08) { - iso14a_clear_trace(); - iso14a_set_tracing(TRUE); - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - //SpinDelay(300); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - //SpinDelay(100); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); } while (true) { @@ -967,7 +960,6 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // get UID from chip if (workFlags & 0x01) { if(!iso14443a_select_card(uid, NULL, &cuid)) { - Dbprintf("ICE"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; @@ -1065,28 +1057,20 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // variables byte_t isOK = 0; - uint8_t data[18]; + uint8_t data[18] = {0x00}; uint32_t cuid = 0; - memset(data, 0x00, 18); uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; if (workFlags & 0x08) { - // clear trace - iso14a_clear_trace(); - iso14a_set_tracing(TRUE); - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - // SpinDelay(300); - // FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - // SpinDelay(100); - // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); } while (true) { @@ -1132,3 +1116,35 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai } } +void MifareCIdent(){ + + // card commands + uint8_t wupC1[] = { 0x40 }; + uint8_t wupC2[] = { 0x43 }; + + // variables + byte_t isOK = 1; + + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + ReaderTransmitBitsPar(wupC1,7,0, NULL); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + isOK = 0; + }; + + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + isOK = 0; + }; + + if (mifare_classic_halt(NULL, 0)) { + isOK = 0; + }; + + cmd_send(CMD_ACK,isOK,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +} + diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 56166777..75119322 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -24,11 +24,11 @@ bool InitDesfireCard(){ byte_t cardbuf[USB_CMD_DATA_SIZE]; memset(cardbuf,0,sizeof(cardbuf)); + iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; iso14a_set_tracing(TRUE); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; int len = iso14443a_select_card(NULL,card,NULL); if (!len) { @@ -350,7 +350,7 @@ size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout){ 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 //FIXME: allow multiple selected cards + cmd[1] = 0x00; // CID: 0x00 //TODO: allow multiple selected cards memcpy(cmd+2, datain, len); AppendCrc14443a(cmd, len+2); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index f09c555b..27f0ac36 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -225,12 +225,6 @@ int CmdHF14AReader(const char *Cmd) memcpy(&card.ats, resp.d.asBytes, resp.arg[0]); card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes } - - // disconnect - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes bool ta1 = 0, tb1 = 0, tc1 = 0; @@ -370,6 +364,23 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog("proprietary non iso14443-4 card found, RATS not supported"); } + + // try to see if card responses to "chinese magic backdoor" commands. + c.cmd = CMD_MIFARE_CIDENT; + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); + WaitForResponse(CMD_ACK,&resp); + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog(" Answers to chinese magic backdoor commands: %s", (isOK ? "YES" : "NO") ); + + // disconnect + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); + return select_status; } diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 55df18f4..65631d98 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -137,8 +137,11 @@ typedef struct { #define CMD_MIFARE_EML_MEMSET 0x0602 #define CMD_MIFARE_EML_MEMGET 0x0603 #define CMD_MIFARE_EML_CARDLOAD 0x0604 -#define CMD_MIFARE_EML_CSETBLOCK 0x0605 -#define CMD_MIFARE_EML_CGETBLOCK 0x0606 + +// magic chinese card commands +#define CMD_MIFARE_CSETBLOCK 0x0605 +#define CMD_MIFARE_CGETBLOCK 0x0606 +#define CMD_MIFARE_CIDENT 0x0607 #define CMD_SIMULATE_MIFARE_CARD 0x0610 From 9c7c222c035156c33766daec6c635113414eab41 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 26 Dec 2014 22:38:23 +0100 Subject: [PATCH 65/78] FIX: minor fixes to the new feature in "hf 14a reader". Not turning off the field and the consequent changes to the define names. (CMD_MIFARE_EML_CGETBLO -> CMD_MIFARE_CGETBLO) --- armsrc/mifarecmd.c | 5 +---- client/cmdhf14a.c | 1 + client/mifarehost.c | 6 +++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index ee2132ef..b84d0484 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1127,9 +1127,7 @@ void MifareCIdent(){ uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - + ReaderTransmitBitsPar(wupC1,7,0, NULL); if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { isOK = 0; @@ -1145,6 +1143,5 @@ void MifareCIdent(){ }; cmd_send(CMD_ACK,isOK,0,0,0,0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); } diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 27f0ac36..5798fee6 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -376,6 +376,7 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" Answers to chinese magic backdoor commands: %s", (isOK ? "YES" : "NO") ); // disconnect + c.cmd = CMD_READER_ISO_14443a; c.arg[0] = 0; c.arg[1] = 0; c.arg[2] = 0; diff --git a/client/mifarehost.c b/client/mifarehost.c index 41ea1030..3516fca4 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -236,7 +236,7 @@ int mfCSetUID(uint8_t *uid, uint8_t *oldUID, bool wantWipe) { memcpy(block0, uid, 4); block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // Mifare UID BCC // mifare classic SAK(byte 5) and ATQA(byte 6 and 7) - block0[5] = 0x88; + block0[5] = 0x08; block0[6] = 0x04; block0[7] = 0x00; @@ -246,7 +246,7 @@ int mfCSetUID(uint8_t *uid, uint8_t *oldUID, bool wantWipe) { int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params) { uint8_t isOK = 0; - UsbCommand c = {CMD_MIFARE_EML_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}}; + UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}}; memcpy(c.d.asBytes, data, 16); SendCommand(&c); @@ -265,7 +265,7 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uin int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) { uint8_t isOK = 0; - UsbCommand c = {CMD_MIFARE_EML_CGETBLOCK, {params, 0, blockNo}}; + UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}}; SendCommand(&c); UsbCommand resp; From 6ff6ade2f5f24ffb52a9f90238ee7b8c77edc89c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 31 Dec 2014 11:35:43 +0100 Subject: [PATCH 66/78] ADD: midnitesnakes desfire, ultralight changes from Unstable branch. ADD: Marshmellows fixes for the LF (demods) commands, (LF SEACH) ADD: Holimans changes with hash1_brute FIXES: minor fixes with some calls to "free" and redundant debug statement and code cleanup. removal of commented code. --- armsrc/Makefile | 8 +- armsrc/appmain.c | 3 + armsrc/apps.h | 5 + armsrc/crapto1.c | 4 +- armsrc/lfops.c | 279 +- armsrc/mifarecmd.c | 75 + armsrc/mifareutil.c | 94 +- armsrc/mifareutil.h | 6 + client/Makefile | 8 +- client/cmddata.c | 773 +- client/cmddata.h | 3 + client/cmdhfmfdesfire.c | 250 + client/cmdhfmfdesfire.h | 5 + client/cmdlf.c | 38 +- client/cmdlf.h | 1 + client/cmdlfem4x.c | 16 +- client/cmdlfem4x.h | 2 +- client/cmdlfhitag.c | 1 + client/graph.c | 55 +- client/graph.h | 4 +- client/loclass/cipherutils.c | 1 + client/loclass/hash1_brute.c | 92 + client/loclass/hash1_brute.h | 5 + client/loclass/ikeys.c | 6 +- common/lfdemod.c | 677 + common/lfdemod.h | 25 + include/usb_cmd.h | 2 + traces/Casi-12ed825c29.pm3 | 16000 +++++++++++ traces/EM4102-Fob.pm3 | 40000 ++++++++++++++++++++++++++++ traces/indala-504278295.pm3 | 20000 ++++++++++++++ traces/ioProx-XSF-01-BE-03011.pm3 | 16000 +++++++++++ traces/ioprox-XSF-01-3B-44725.pm3 | 40000 ++++++++++++++++++++++++++++ 32 files changed, 133707 insertions(+), 731 deletions(-) create mode 100644 client/cmdhfmfdesfire.c create mode 100644 client/cmdhfmfdesfire.h create mode 100644 client/loclass/hash1_brute.c create mode 100644 client/loclass/hash1_brute.h create mode 100644 common/lfdemod.c create mode 100644 common/lfdemod.h create mode 100644 traces/Casi-12ed825c29.pm3 create mode 100644 traces/EM4102-Fob.pm3 create mode 100644 traces/indala-504278295.pm3 create mode 100644 traces/ioProx-XSF-01-BE-03011.pm3 create mode 100644 traces/ioprox-XSF-01-3B-44725.pm3 diff --git a/armsrc/Makefile b/armsrc/Makefile index d37e935a..69e4738a 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -18,7 +18,7 @@ SRC_LF = lfops.c hitag2.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 desfire_key.c desfire_crypto.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 \ @@ -35,14 +35,14 @@ THUMBSRC = start.c \ # These are to be compiled in ARM mode ARMSRC = fpgaloader.c \ legicrf.c \ + lfdemod.c \ $(SRC_ISO14443a) \ $(SRC_ISO14443b) \ $(SRC_CRAPTO1) \ $(SRC_CRC) \ legic_prng.c \ - iclass.c \ - mifaredesfire.c - + iclass.c + # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS += -I. diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 33944c1d..dbbbe6bd 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -656,6 +656,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_IO_CLONE_TAG: CopyIOtoT55x7(c->arg[0], c->arg[1], c->d.asBytes[0]); break; + case CMD_EM410X_DEMOD: + CmdEM410xdemod(c->arg[0], 0, 0, 1); + break; case CMD_EM410X_WRITE_TAG: WriteEM410x(c->arg[0], c->arg[1], c->arg[2]); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 5e1926f9..81124a1a 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -149,6 +149,7 @@ void SimulateTagLowFrequencyA(int period, int gap); void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol); void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol); +void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol); void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol); void CopyIOtoT55x7(uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an ioProx card to T5557/T5567 void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen); @@ -213,6 +214,10 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareCIdent(); // is "magic chinese" card? +//desfire +void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain); +void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); + // mifaredesfire.h bool InitDesfireCard(); void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); diff --git a/armsrc/crapto1.c b/armsrc/crapto1.c index 17b78e32..c0a7fc32 100644 --- a/armsrc/crapto1.c +++ b/armsrc/crapto1.c @@ -44,12 +44,12 @@ static void quicksort(uint32_t* const start, uint32_t* const stop) else if(*rit > *start) --rit; else - *it ^= (*it ^= *rit, *rit ^= *it); + *it ^= ( (*it ^= *rit ), *rit ^= *it); if(*rit >= *start) --rit; if(rit != start) - *rit ^= (*rit ^= *start, *start ^= *rit); + *rit ^= ( (*rit ^= *start), *start ^= *rit); quicksort(start, rit - 1); quicksort(rit + 1, stop); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 5e01e9b0..ea2b0c44 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -11,11 +11,12 @@ #include "../include/proxmark3.h" #include "apps.h" #include "util.h" -#include "../include/hitag2.h" #include "../common/crc16.h" +#include "../common/lfdemod.h" #include "string.h" #include "crapto1.h" -#include "mifareutil.h" +#include "mifareutil.h" +#include "../include/hitag2.h" // 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 @@ -721,105 +722,12 @@ void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) LED_A_OFF(); } -//translate wave to 11111100000 (1 for each short wave 0 for each long wave) -size_t fsk_demod(uint8_t * dest, size_t size) -{ - uint32_t last_transition = 0; - uint32_t idx = 1; - uint32_t maxVal=0; - // // we don't care about actual value, only if it's more or less than a - // // threshold essentially we capture zero crossings for later analysis - - // we do care about the actual value as sometimes near the center of the - // wave we may get static that changes direction of wave for one value - // if our value is too low it might affect the read. and if our tag or - // antenna is weak a setting too high might not see anything. [marshmellow] - if (size<100) return size; - for(idx=1; idx<100; idx++){ - if(maxVal1 transition - if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition - - dest[numBits] = (idx-last_transition < 9) ? 1 : 0; - last_transition = idx; - numBits++; - } - } - return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 -} - -uint32_t myround(float f) -{ - if (f >= 2000) return 2000;//something bad happened - return (uint32_t) (f + (float)0.5); -} - -//translate 11111100000 to 10 -size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert )// uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, -{ - uint8_t lastval=dest[0]; - uint32_t idx=0; - size_t numBits=0; - uint32_t n=1; - - for( idx=1; idx < size; idx++) { - - if (dest[idx]==lastval) { - n++; - continue; - } - //if lastval was 1, we have a 1->0 crossing - if ( dest[idx-1]==1 ) { - n=myround((float)(n+1)/((float)(rfLen)/(float)8)); - //n=(n+1) / h2l_crossing_value; - } else {// 0->1 crossing - n=myround((float)(n+1)/((float)(rfLen-2)/(float)10)); - //n=(n+1) / l2h_crossing_value; - } - if (n == 0) n = 1; - - if(n < maxConsequtiveBits) - { - if ( invert==0) - memset(dest+numBits, dest[idx-1] , n); - else - memset(dest+numBits, dest[idx-1]^1 , n); - - numBits += n; - } - n=0; - lastval=dest[idx]; - }//end for - - return numBits; - -} // loop to get raw HID waveform then FSK demodulate the TAG ID from it void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { uint8_t *dest = get_bigbufptr_recvrespbuf(); - size_t size=0,idx=0; //, found=0; + size_t size=0; //, found=0; uint32_t hi2=0, hi=0, lo=0; // Configure to go in 125Khz listen mode @@ -831,58 +739,21 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) if (ledcontrol) LED_A_ON(); DoAcquisition125k_internal(-1,true); - + size = sizeof(BigBuf); + if (size < 2000) continue; // FSK demodulator - size = fsk_demod(dest, FREE_BUFFER_SIZE); - // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns - // 1->0 : fc/8 in sets of 6 (RF/50 / 8 = 6.25) - // 0->1 : fc/10 in sets of 5 (RF/50 / 10= 5) - // do not invert - size = aggregate_bits(dest,size, 50,5,0); //6,5,5,0 + int bitLen = HIDdemodFSK(dest,size,&hi2,&hi,&lo); WDT_HIT(); + if (bitLen>0 && lo>0){ // final loop, go over previously decoded manchester data and decode into usable tag ID // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 - uint8_t frame_marker_mask[] = {1,1,1,0,0,0}; - int numshifts = 0; - idx = 0; - //one scan - uint8_t sameCardCount =0; - while( idx + sizeof(frame_marker_mask) < size) { - // search for a start of frame marker - if (sameCardCount>2) break; //only up to 2 valid sets of data for the same read of looping card data - if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { // frame marker found - idx+=sizeof(frame_marker_mask); - - while(dest[idx] != dest[idx+1] && idx < size-2) - { - // Keep going until next frame marker (or error) - // Shift in a bit. Start by shifting high registers - hi2=(hi2<<1)|(hi>>31); - hi=(hi<<1)|(lo>>31); - //Then, shift in a 0 or one into low - if (dest[idx] && !dest[idx+1]) // 1 0 - lo=(lo<<1)|0; - else // 0 1 - lo=(lo<<1)| - 1; - numshifts ++; - idx += 2; - } - //Dbprintf("Num shifts: %d ", numshifts); - // Hopefully, we read a tag and hit upon the next frame marker - if(idx + sizeof(frame_marker_mask) < size) - { - if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { if (hi2 != 0){ //extra large HID tags Dbprintf("TAG ID: %x%08x%08x (%d)", (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - } - else { //standard HID tags <38 bits + }else { //standard HID tags <38 bits //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd uint8_t bitlen = 0; uint32_t fc = 0; @@ -930,50 +801,86 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); } - sameCardCount++; if (findone){ if (ledcontrol) LED_A_OFF(); return; - } - } } // reset hi2 = hi = lo = 0; - numshifts = 0; - } else { - idx++; - } } WDT_HIT(); + //SpinDelay(50); + } + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); +} +void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) +{ + uint8_t *dest = (uint8_t *)BigBuf; + + size_t size=0; //, found=0; + uint32_t bitLen=0; + int clk=0, invert=0, errCnt=0; + uint64_t lo=0; + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(95, true); + + while(!BUTTON_PRESS()) { + + WDT_HIT(); + if (ledcontrol) LED_A_ON(); + + DoAcquisition125k_internal(-1,true); + size = sizeof(BigBuf); + if (size < 2000) continue; + // FSK demodulator + //int askmandemod(uint8_t *BinStream,uint32_t *BitLen,int *clk, int *invert); + bitLen=size; + //Dbprintf("DEBUG: Buffer got"); + errCnt = askmandemod(dest,&bitLen,&clk,&invert); //HIDdemodFSK(dest,size,&hi2,&hi,&lo); + //Dbprintf("DEBUG: ASK Got"); + WDT_HIT(); + + if (errCnt>=0){ + lo = Em410xDecode(dest,bitLen); + //Dbprintf("DEBUG: EM GOT"); + //printEM410x(lo); + if (lo>0){ + 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(); + return; + } + } else { + //Dbprintf("DEBUG: No Tag"); + } + WDT_HIT(); + lo = 0; + clk=0; + invert=0; + errCnt=0; + size=0; + //SpinDelay(50); } DbpString("Stopped"); if (ledcontrol) LED_A_OFF(); } -uint32_t bytebits_to_byte(uint8_t* src, int numbits) -{ - uint32_t num = 0; - for(int i = 0 ; i < numbits ; i++) - { - num = (num << 1) | (*src); - src++; - } - return num; -} - - void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) { uint8_t *dest = (uint8_t *)BigBuf; - size_t size=0, idx=0; + size_t size=0; + int idx=0; uint32_t code=0, code2=0; - uint8_t isFinish = 0; - + uint8_t version=0; + uint8_t facilitycode=0; + uint16_t number=0; // Configure to go in 125Khz listen mode LFSetupFPGAForADC(0, true); - while(!BUTTON_PRESS() & !isFinish) { + while(!BUTTON_PRESS()) { WDT_HIT(); @@ -982,23 +889,13 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) DoAcquisition125k_internal(-1,true); size = sizeof(BigBuf); //make sure buffer has data - if (size < 64) return; - //test samples are not just noise - uint8_t testMax=0; - for(idx=0;idx<64;idx++){ - if (testMax170){ - //Dbprintf("testMax: %d",testMax); - // FSK demodulator - size = fsk_demod(dest, size); - // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns - // 1->0 : fc/8 in sets of 7 (RF/64 / 8 = 8) - // 0->1 : fc/10 in sets of 6 (RF/64 / 10 = 6.4) - size = aggregate_bits(dest, size, 64, 13, 1); //13 max Consecutive should be ok as most 0s in row should be 10 for init seq - invert bits + if (size < 2000) continue; + //fskdemod and get start index WDT_HIT(); + idx = IOdemodFSK(dest,size); + if (idx>0){ + //valid tag found + //Index map //0 10 20 30 40 50 60 //| | | | | | | @@ -1008,14 +905,6 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) // //XSF(version)facility:codeone+codetwo //Handle the data - uint8_t sameCardCount=0; - uint8_t mask[] = {0,0,0,0,0,0,0,0,0,1}; - for( idx=0; idx < (size - 74); idx++) { - if (sameCardCount>2) break; - if ( memcmp(dest + idx, mask, sizeof(mask))==0) { - //frame marker found - if (!dest[idx+8] && dest[idx+17]==1 && dest[idx+26]==1 && dest[idx+35]==1 && dest[idx+44]==1 && dest[idx+53]==1){ - //confirmed proper separator bits found 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]); @@ -1027,22 +916,20 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) } code = bytebits_to_byte(dest+idx,32); code2 = bytebits_to_byte(dest+idx+32,32); - short version = bytebits_to_byte(dest+idx+27,8); //14,4 - uint8_t facilitycode = bytebits_to_byte(dest+idx+19,8) ; - uint16_t number = (bytebits_to_byte(dest+idx+36,8)<<8)|(bytebits_to_byte(dest+idx+45,8)); //36,9 + 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:%d (%08x%08x)",version,facilitycode,number,code,code2); - + 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(); - isFinish = 1; - break; - } - sameCardCount++; - } - } + return; } + code=code2=0; + version=facilitycode=0; + number=0; + idx=0; } WDT_HIT(); } diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index b84d0484..fc480a38 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1145,3 +1145,78 @@ void MifareCIdent(){ cmd_send(CMD_ACK,isOK,0,0,0,0); } + // +// DESFIRE +// + +void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card, something went wrong before auth"); + }; + + if(mifare_desfire_des_auth1(cuid, dataoutbuf)){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part1: Fail."); + } + + isOK=1; + if (MF_DBGLEVEL >= 2) DbpString("AUTH 1 FINISHED"); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,cuid,0,dataoutbuf,11); + LED_B_OFF(); + + // Thats it... + //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ + // params + uint32_t cuid = arg0; + uint8_t key[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + + memcpy(key, datain, 16); + // clear trace + //iso14a_clear_trace(); + //iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + +// Dbprintf("Sending %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", +// key[0],key[1],key[2],key[3],key[4],key[5],key[6],key[7],key[8], +// key[9],key[10],key[11],key[12],key[13],key[14],key[15]); + + if(mifare_desfire_des_auth2(cuid, key, dataoutbuf)){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail..."); + } + isOK=1; + if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED"); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,12); + LED_B_OFF(); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} \ No newline at end of file diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index dcea901d..84f77a35 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -94,8 +94,8 @@ int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer, answer_parity); if(!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); - return 2; + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + return 2; } return len; } @@ -433,7 +433,6 @@ int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) // variables uint16_t len; uint8_t par[3] = {0}; // enough for 18 parity bits - uint8_t d_block[18]; uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; @@ -466,7 +465,6 @@ int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) { uint16_t len; - uint8_t d_block[8]; uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; @@ -625,3 +623,91 @@ void emlClearMem(void) { emlSetMem((uint8_t *)uid, 0, 1); return; } + +// +//DESFIRE +// +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) +{ + uint8_t dcmd[5] = {0x00}; + dcmd[0] = cmd; + memcpy(dcmd+1,data,2); + AppendCrc14443a(dcmd, 3); + + ReaderTransmit(dcmd, sizeof(dcmd), NULL); + int len = ReaderReceive(answer, answer_parity); + if(!len) { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + return 2; + } + return len; +} + +int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing) +{ + uint8_t dcmd[20] = {0x00}; + dcmd[0] = cmd; + memcpy(dcmd+1,data,17); + AppendCrc14443a(dcmd, 18); + + ReaderTransmit(dcmd, sizeof(dcmd), NULL); + int len = ReaderReceive(answer, answer_parity); + if(!len){ + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + return 2; + } + return len; +} + +int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData){ + // variables + int len; + // load key, keynumber + uint8_t data[2]={0x0a, 0x00}; + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; + + // command MIFARE_CLASSIC_READBLOCK + len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer,receivedAnswerPar,NULL); + if (len == 1) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + + if (len == 12) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], + receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], + receivedAnswer[10],receivedAnswer[11]); + memcpy(blockData, receivedAnswer, 12); + return 0; + } + return 1; +} + +int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ + // variables + int len; + uint8_t data[17]={0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + memcpy(data+1,key,16); + + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; + + // command MIFARE_CLASSIC_READBLOCK + len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar ,NULL); + + if ((receivedAnswer[0] == 0x03)&&(receivedAnswer[1] == 0xae)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]); + return 1; + } + if (len == 12){ + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], + receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], + receivedAnswer[10],receivedAnswer[11]); + memcpy(blockData, receivedAnswer, 12); + return 0; + } + return 1; +} \ No newline at end of file diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 12064829..6ef5e0a5 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -71,6 +71,12 @@ int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); int mifare_ultra_halt(uint32_t uid); + +// desfire +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); +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); +int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData); +int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); // crypto functions void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len); diff --git a/client/Makefile b/client/Makefile index 7ef23fa6..83d00260 100644 --- a/client/Makefile +++ b/client/Makefile @@ -60,9 +60,10 @@ CMDSRCS = nonce2key/crapto1.c\ loclass/cipherutils.c \ loclass/des.c \ loclass/ikeys.c \ - loclass/elite_crack.c\ - loclass/fileutils.c\ - mifarehost.c\ + loclass/elite_crack.c \ + loclass/fileutils.c \ + loclass/hash1_brute.c \ + mifarehost.c \ crc16.c \ iso14443crc.c \ iso15693tools.c \ @@ -70,6 +71,7 @@ CMDSRCS = nonce2key/crapto1.c\ graph.c \ ui.c \ cmddata.c \ + lfdemod.c \ cmdhf.c \ cmdhf14a.c \ cmdhf14b.c \ diff --git a/client/cmddata.c b/client/cmddata.c index b2c68b97..7aa8fcf4 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -20,7 +20,7 @@ #include "util.h" #include "cmdmain.h" #include "cmddata.h" - +#include "lfdemod.h" static int CmdHelp(const char *Cmd); @@ -78,12 +78,8 @@ int Cmdaskdemod(const char *Cmd) sscanf(Cmd, "%i", &c); - if (c != 0 && c != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - - /* Detect high and lows */ + /* Detect high and lows and clock */ + // (AL - clock???) for (i = 0; i < GraphTraceLen; ++i) { if (GraphBuffer[i] > high) @@ -91,7 +87,13 @@ int Cmdaskdemod(const char *Cmd) else if (GraphBuffer[i] < low) low = GraphBuffer[i]; } - + high=abs(high*.75); + low=abs(low*.75); + if (c != 0 && c != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + //prime loop if (GraphBuffer[0] > 0) { GraphBuffer[0] = 1-c; } else { @@ -119,39 +121,14 @@ int Cmdaskdemod(const char *Cmd) return 0; } -void printBitStream(int BitStream[], uint32_t bitLen){ - uint32_t i = 0; - if (bitLen<16) return; - if (bitLen>512) bitLen=512; - for (i = 0; i < (bitLen-16); i+=16) { - PrintAndLog("%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", - BitStream[i], - BitStream[i+1], - BitStream[i+2], - BitStream[i+3], - BitStream[i+4], - BitStream[i+5], - BitStream[i+6], - BitStream[i+7], - BitStream[i+8], - BitStream[i+9], - BitStream[i+10], - BitStream[i+11], - BitStream[i+12], - BitStream[i+13], - BitStream[i+14], - BitStream[i+15]); - } - return; -} -void printBitStream2(uint8_t BitStream[], uint32_t bitLen){ +void printBitStream(uint8_t BitStream[], uint32_t bitLen){ uint32_t i = 0; if (bitLen<16) { PrintAndLog("Too few bits found: %d",bitLen); return; } if (bitLen>512) bitLen=512; - for (i = 0; i < (bitLen-16); i+=16) { + for (i = 0; i <= (bitLen-16); i+=16) { PrintAndLog("%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", BitStream[i], BitStream[i+1], @@ -172,219 +149,213 @@ void printBitStream2(uint8_t BitStream[], uint32_t bitLen){ } return; } - -//by marshmellow -//takes 1s and 0s and searches for EM410x format - output EM ID -int Em410xDecode(const char *Cmd) +void printEM410x(uint64_t id) { - //no arguments needed - built this way in case we want this to be a direct call from "data " cmds in the future - // otherwise could be a void with no arguments - //set defaults - int high=0, low=0; - uint64_t lo=0; //hi=0, - - uint32_t i = 0; - uint32_t initLoopMax = 1000; - if (initLoopMax>GraphTraceLen) initLoopMax=GraphTraceLen; - - for (;i < initLoopMax; ++i) //1000 samples should be plenty to find high and low values - { - if (GraphBuffer[i] > high) - high = GraphBuffer[i]; - else if (GraphBuffer[i] < low) - low = GraphBuffer[i]; - } - if (((high !=1)||(low !=0))){ //allow only 1s and 0s - PrintAndLog("no data found"); - return 0; - } - uint8_t parityTest=0; - // 111111111 bit pattern represent start of frame - int frame_marker_mask[] = {1,1,1,1,1,1,1,1,1}; - uint32_t idx = 0; - uint32_t ii=0; - uint8_t resetCnt = 0; - while( (idx + 64) < GraphTraceLen) { -restart: - // search for a start of frame marker - if ( memcmp(GraphBuffer+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { // frame marker found - idx+=9;//sizeof(frame_marker_mask); - for (i=0; i<10;i++){ - for(ii=0; ii<5; ++ii){ - parityTest += GraphBuffer[(i*5)+ii+idx]; - } - if (parityTest== ((parityTest>>1)<<1)){ - parityTest=0; - for (ii=0; ii<4;++ii){ - //hi = (hi<<1)|(lo>>31); - lo=(lo<<1LL)|(GraphBuffer[(i*5)+ii+idx]); - } - //PrintAndLog("DEBUG: EM parity passed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d,lo: %d",parityTest,i,ii,idx,GraphBuffer[idx+ii+(i*5)-5],GraphBuffer[idx+ii+(i*5)-4],GraphBuffer[idx+ii+(i*5)-3],GraphBuffer[idx+ii+(i*5)-2],GraphBuffer[idx+ii+(i*5)-1],lo); - }else {//parity failed - //PrintAndLog("DEBUG: EM parity failed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d",parityTest,i,ii,idx,GraphBuffer[idx+ii+(i*5)-5],GraphBuffer[idx+ii+(i*5)-4],GraphBuffer[idx+ii+(i*5)-3],GraphBuffer[idx+ii+(i*5)-2],GraphBuffer[idx+ii+(i*5)-1]); - parityTest=0; - idx-=8; - if (resetCnt>5)return 0; - resetCnt++; - goto restart;//continue; - } - } - //skip last 5 bit parity test for simplicity. - - //get Unique ID + if (id !=0){ uint64_t iii=1; uint64_t id2lo=0; //id2hi=0, - //for (i=0;i<8;i++){ //for uint32 instead of uint64 - // id2hi=(id2hi<<1)|((hi & (iii<<(i)))>>i); - //} + uint32_t ii=0; + uint32_t i=0; for (ii=5; ii>0;ii--){ for (i=0;i<8;i++){ - id2lo=(id2lo<<1LL)|((lo & (iii<<(i+((ii-1)*8))))>>(i+((ii-1)*8))); + id2lo=(id2lo<<1LL)|((id & (iii<<(i+((ii-1)*8))))>>(i+((ii-1)*8))); } } //output em id - PrintAndLog("EM TAG ID : %010llx", lo); + PrintAndLog("EM TAG ID : %010llx", id); PrintAndLog("Unique TAG ID: %010llx", id2lo); //id2hi, - PrintAndLog("DEZ 8 : %08lld",lo & 0xFFFFFF); - PrintAndLog("DEZ 10 : %010lld",lo & 0xFFFFFF); - PrintAndLog("DEZ 5.5 : %05lld.%05lld",(lo>>16LL) & 0xFFFF,(lo & 0xFFFF)); - PrintAndLog("DEZ 3.5A : %03lld.%05lld",(lo>>32ll),(lo & 0xFFFF)); - PrintAndLog("DEZ 14/IK2 : %014lld",lo); + PrintAndLog("DEZ 8 : %08lld",id & 0xFFFFFF); + PrintAndLog("DEZ 10 : %010lld",id & 0xFFFFFF); + PrintAndLog("DEZ 5.5 : %05lld.%05lld",(id>>16LL) & 0xFFFF,(id & 0xFFFF)); + PrintAndLog("DEZ 3.5A : %03lld.%05lld",(id>>32ll),(id & 0xFFFF)); + PrintAndLog("DEZ 14/IK2 : %014lld",id); PrintAndLog("DEZ 15/IK3 : %015lld",id2lo); - PrintAndLog("Other : %05lld_%03lld_%08lld",(lo&0xFFFF),((lo>>16LL) & 0xFF),(lo & 0xFFFFFF)); - return 0; - }else{ - idx++; - } - } - return 0; + PrintAndLog("Other : %05lld_%03lld_%08lld",(id&0xFFFF),((id>>16LL) & 0xFF),(id & 0xFFFFFF)); + } + return; } +int CmdEm410xDecode(const char *Cmd) +{ + uint64_t id=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + uint32_t i=0; + i=getFromGraphBuf(BitStream); + id = Em410xDecode(BitStream,i); + printEM410x(id); + if (id>0) return 1; + return 0; +} //by marshmellow //takes 2 arguments - clock and invert both as integers +//attempts to demodulate ask while decoding manchester //prints binary found and saves in graphbuffer for further commands int Cmdaskmandemod(const char *Cmd) { - uint32_t i; - int invert=0; //invert default - int high = 0, low = 0; - int clk=DetectClock(0); //clock default - uint8_t BitStream[MAX_GRAPH_TRACE_LEN] = {0}; - sscanf(Cmd, "%i %i", &clk, &invert); - if (clk<8) clk =64; - if (clk<32) clk=32; + int invert=0; + int clk=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + sscanf(Cmd, "%i %i", &clk, &invert); if (invert != 0 && invert != 1) { PrintAndLog("Invalid argument: %s", Cmd); return 0; } - uint32_t initLoopMax = 1000; - if (initLoopMax>GraphTraceLen) initLoopMax=GraphTraceLen; - // Detect high and lows - PrintAndLog("Using Clock: %d and invert=%d",clk,invert); - for (i = 0; i < initLoopMax; ++i) //1000 samples should be plenty to find high and low values - { - if (GraphBuffer[i] > high) - high = GraphBuffer[i]; - else if (GraphBuffer[i] < low) - low = GraphBuffer[i]; + uint32_t BitLen = getFromGraphBuf(BitStream); + + int errCnt=0; + errCnt = askmandemod(BitStream, &BitLen,&clk,&invert); + if (errCnt<0){ //if fatal error (or -1) + // PrintAndLog("no data found %d, errors:%d, bitlen:%d, clock:%d",errCnt,invert,BitLen,clk); + return 0; + } + if (BitLen<16) return 0; + PrintAndLog("\nUsing Clock: %d - Invert: %d - Bits Found: %d",clk,invert,BitLen); + + if (errCnt>0){ + PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); } - if ((high < 30) && ((high !=1)||(low !=-1))){ //throw away static - allow 1 and -1 (in case of threshold command first) - PrintAndLog("no data found"); + PrintAndLog("ASK/Manchester decoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + printBitStream(BitStream,BitLen); + uint64_t lo =0; + lo = Em410xDecode(BitStream,BitLen); + if (lo>0){ + //set GraphBuffer for clone or sim command + setGraphBuf(BitStream,BitLen); + PrintAndLog("EM410x pattern found: "); + printEM410x(lo); + } + if (BitLen>16) return 1; + return 0; +} + +//by marshmellow +//manchester decode +//stricktly take 10 and 01 and convert to 0 and 1 +int Cmdmandecoderaw(const char *Cmd) +{ + int i =0; + int errCnt=0; + int bitnum=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + int high = 0, low = 0; + for (;ihigh) high=GraphBuffer[i]; + else if(GraphBuffer[i]1 || low <0 ){ + PrintAndLog("Error: please raw demod the wave first then mancheseter raw decode"); return 0; } - //13% fuzz in case highs and lows aren't clipped [marshmellow] - high=(int)(0.75*high); - low=(int)(0.75*low); - - //PrintAndLog("DEBUG - valid high: %d - valid low: %d",high,low); - int lastBit = 0; //set first clock check - uint32_t bitnum = 0; //output counter - uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave - if (clk==32)tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely - uint32_t iii = 0; - uint32_t gLen = GraphTraceLen; - if (gLen > 500) gLen=500; - uint8_t errCnt =0; - uint32_t bestStart = GraphTraceLen; - uint32_t bestErrCnt = (GraphTraceLen/1000); - //PrintAndLog("DEBUG - lastbit - %d",lastBit); - //loop to find first wave that works - for (iii=0; iii < gLen; ++iii){ - if ((GraphBuffer[iii]>=high)||(GraphBuffer[iii]<=low)){ - lastBit=iii-clk; - //loop through to see if this start location works - for (i = iii; i < GraphTraceLen; ++i) { - if ((GraphBuffer[i] >= high) && ((i-lastBit)>(clk-tol))){ - lastBit+=clk; - BitStream[bitnum] = invert; - bitnum++; - } else if ((GraphBuffer[i] <= low) && ((i-lastBit)>(clk-tol))){ - //low found and we are expecting a bar - lastBit+=clk; - BitStream[bitnum] = 1-invert; - bitnum++; - } else { - //mid value found or no bar supposed to be here - if ((i-lastBit)>(clk+tol)){ - //should have hit a high or low based on clock!! - - - //debug - //PrintAndLog("DEBUG - no wave in expected area - location: %d, expected: %d-%d, lastBit: %d - resetting search",i,(lastBit+(clk-((int)(tol)))),(lastBit+(clk+((int)(tol)))),lastBit); - if (bitnum > 0){ - BitStream[bitnum]=77; - bitnum++; - } - - - errCnt++; - lastBit+=clk;//skip over until hit too many errors - if (errCnt>((GraphTraceLen/1000))){ //allow 1 error for every 1000 samples else start over - errCnt=0; - bitnum=0;//start over - break; - } - } - } - } - //we got more than 64 good bits and not all errors - if ((bitnum > (64+errCnt)) && (errCnt<(GraphTraceLen/1000))) { - //possible good read - if (errCnt==0) break; //great read - finish - if (bestStart == iii) break; //if current run == bestErrCnt run (after exhausted testing) then finish - if (errCnt=gLen){ //exhausted test - //if there was a ok test go back to that one and re-run the best run (then dump after that run) - if (bestErrCnt < (GraphTraceLen/1000)) iii=bestStart; - } + bitnum=i; + errCnt=manrawdecode(BitStream,&bitnum); + if (errCnt>=20){ + PrintAndLog("Too many errors: %d",errCnt); + return 0; } - if (bitnum>16){ - - PrintAndLog("Data start pos:%d, lastBit:%d, stop pos:%d, numBits:%d",iii,lastBit,i,bitnum); - //move BitStream back to GraphBuffer + PrintAndLog("Manchester Decoded - # errors:%d - data:",errCnt); + printBitStream(BitStream,bitnum); + if (errCnt==0){ + //put back in graphbuffer ClearGraph(0); for (i=0; i < bitnum; ++i){ GraphBuffer[i]=BitStream[i]; } GraphTraceLen=bitnum; RepaintGraphWindow(); + uint64_t id = 0; + id = Em410xDecode(BitStream,i); + printEM410x(id); + } + return 1; +} + +//by marshmellow +//biphase decode +//take 01 or 10 = 0 and 11 or 00 = 1 +//takes 1 argument "offset" default = 0 if 1 it will shift the decode by one bit +// since it is not like manchester and doesn't have an incorrect bit pattern we +// cannot determine if our decode is correct or if it should be shifted by one bit +// the argument offset allows us to manually shift if the output is incorrect +// (better would be to demod and decode at the same time so we can distinguish large +// width waves vs small width waves to help the decode positioning) or askbiphdemod +int CmdBiphaseDecodeRaw(const char *Cmd) +{ + int i = 0; + int errCnt=0; + int bitnum=0; + int offset=0; + int high=0, low=0; + sscanf(Cmd, "%i", &offset); + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + //get graphbuffer & high and low + for (;ihigh)high=GraphBuffer[i]; + else if(GraphBuffer[i]1 || low <0){ + PrintAndLog("Error: please raw demod the wave first then decode"); + return 0; +} + bitnum=i; + errCnt=BiphaseRawDecode(BitStream,&bitnum, offset); + if (errCnt>=20){ + PrintAndLog("Too many errors attempting to decode: %d",errCnt); + return 0; + } + PrintAndLog("Biphase Decoded using offset: %d - # errors:%d - data:",offset,errCnt); + printBitStream(BitStream,bitnum); + PrintAndLog("\nif bitstream does not look right try offset=1"); + return 1; +} + + +//by marshmellow +//takes 2 arguments - clock and invert both as integers +//attempts to demodulate ask only +//prints binary found and saves in graphbuffer for further commands +int Cmdaskrawdemod(const char *Cmd) +{ + uint32_t i; + int invert=0; + int clk=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + sscanf(Cmd, "%i %i", &clk, &invert); + if (invert != 0 && invert != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + int BitLen = getFromGraphBuf(BitStream); + int errCnt=0; + errCnt = askrawdemod(BitStream, &BitLen,&clk,&invert); + if (errCnt==-1){ //throw away static - allow 1 and -1 (in case of threshold command first) + PrintAndLog("no data found"); + return 0; + } + if (BitLen<16) return 0; + PrintAndLog("Using Clock: %d - invert: %d - Bits Found: %d",clk,invert,BitLen); + //PrintAndLog("Data start pos:%d, lastBit:%d, stop pos:%d, numBits:%d",iii,lastBit,i,bitnum); + //move BitStream back to GraphBuffer + + ClearGraph(0); + for (i=0; i < BitLen; ++i){ + GraphBuffer[i]=BitStream[i]; + } + GraphTraceLen=BitLen; + RepaintGraphWindow(); + //output if (errCnt>0){ PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); } - PrintAndLog("ASK decoded bitstream:"); + PrintAndLog("ASK demoded bitstream:"); // Now output the bitstream to the scrollback by line of 16 bits - printBitStream2(BitStream,bitnum); - Em410xDecode(Cmd); - } - return 0; + printBitStream(BitStream,BitLen); + + return 1; } int CmdAutoCorr(const char *Cmd) @@ -525,240 +496,84 @@ int CmdDec(const char *Cmd) } /* Print our clock rate */ +// uses data from graphbuffer int CmdDetectClockRate(const char *Cmd) { - int clock = DetectClock(0); - PrintAndLog("Auto-detected clock rate: %d", clock); + GetClock("",0,0); return 0; } //by marshmellow -//demod GraphBuffer wave to 0s and 1s for each wave - 0s for short waves 1s for long waves -size_t fsk_wave_demod(int size) -{ - uint32_t last_transition = 0; - uint32_t idx = 1; - uint32_t maxVal = 0; - // we don't care about actual value, only if it's more or less than a - // threshold essentially we capture zero crossings for later analysis - for(idx=1; idx1 transition - if (GraphBuffer[idx-1] < GraphBuffer[idx]) { // 0 -> 1 transition - if (idx-last_transition<6){ - // do nothing with extra garbage (shouldn't be any) noise tolerance? - } else if(idx-last_transition < 9) { - GraphBuffer[numBits]=1; - // Other fsk demods reverse this making the short waves 1 and long waves 0 - // this is really backwards... smaller waves will typically be 0 and larger 1 [marshmellow] - // but will leave as is and invert when needed later - } else{ - GraphBuffer[numBits]=0; - } - last_transition = idx; - numBits++; - // PrintAndLog("numbits %d",numBits); - } - } - return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 -} -uint32_t myround(float f) -{ - if (f >= UINT_MAX) return UINT_MAX; - return (uint32_t) (f + (float)0.5); -} - -//by marshmellow (from holiman's base) -//translate 11111100000 to 10 -size_t aggregate_bits(int size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert) //,uint8_t l2h_crossing_value -{ - int lastval=GraphBuffer[0]; - uint32_t idx=0; - size_t numBits=0; - uint32_t n=1; - uint32_t n2=0; - for( idx=1; idx < size; idx++) { - - if (GraphBuffer[idx]==lastval) { - n++; - continue; - } - // if lastval was 1, we have a 1->0 crossing - if ( GraphBuffer[idx-1]==1 ) { - n=myround((float)(n+1)/((float)(rfLen)/(float)8)); //-2 noise tolerance - - // n=(n+1) / h2l_crossing_value; - //truncating could get us into trouble - //now we will try with actual clock (RF/64 or RF/50) variable instead - //then devide with float casting then truncate after more acurate division - //and round to nearest int - //like n = (((float)n)/(float)rfLen/(float)10); - } else {// 0->1 crossing - n=myround((float)(n+1)/((float)(rfLen-2)/(float)10)); // as int 120/6 = 20 as float 120/(64/10) = 18 (18.75) - //n=(n+1) / l2h_crossing_value; - } - if (n == 0) n = 1; //this should never happen... should we error if it does? - - if (n < maxConsequtiveBits) // Consecutive //when the consecutive bits are low - the noise tolerance can be high - //if it is high then we must be careful how much noise tolerance we allow - { - if (invert==0){ // do not invert bits - for (n2=0; n20 && strlen(Cmd)<=2) { - rfLen=param_get8(Cmd, 0); //if rfLen option only is used + //rfLen=param_get8(Cmd, 0); //if rfLen option only is used if (rfLen==1){ invert=1; //if invert option only is used rfLen = 50; } else if(rfLen==0) rfLen=50; } - if (strlen(Cmd)>2) { - rfLen=param_get8(Cmd, 0); //if both options are used - invert=param_get8(Cmd,1); - } - PrintAndLog("Args invert: %d \nClock:%d",invert,rfLen); - - size_t size = fskdemod(rfLen,invert); - + PrintAndLog("Args invert: %d - Clock:%d - fchigh:%d - fclow: %d",invert,rfLen,fchigh, fclow); + uint32_t i=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + uint32_t BitLen = getFromGraphBuf(BitStream); + int size = fskdemod(BitStream,BitLen,(uint8_t)rfLen,(uint8_t)invert,(uint8_t)fchigh,(uint8_t)fclow); + if (size>0){ PrintAndLog("FSK decoded bitstream:"); + ClearGraph(0); + for (i=0;i (7*32)+2) size = (7*32)+2; //only output a max of 7 blocks of 32 bits most tags will have full bit stream inside that sample size - printBitStream(GraphBuffer,size); - - ClearGraph(1); + if(size > (8*32)+2) size = (8*32)+2; //only output a max of 8 blocks of 32 bits most tags will have full bit stream inside that sample size + printBitStream(BitStream,size); + } else{ + PrintAndLog("no FSK data found"); + } return 0; } -//by marshmellow +//by marshmellow (based on existing demod + holiman's refactor) +//HID Prox demod - FSK RF/50 with preamble of 00011101 (then manchester encoded) +//print full HID Prox ID and some bit format details if found int CmdFSKdemodHID(const char *Cmd) { //raw fsk demod no manchester decoding no start bit finding just get binary from wave - //set defaults - uint8_t rfLen = 50; - uint8_t invert=0;//param_get8(Cmd, 0); - size_t idx=0; uint32_t hi2=0, hi=0, lo=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + uint32_t BitLen = getFromGraphBuf(BitStream); //get binary from fsk wave - size_t size = fskdemod(rfLen,invert); - - // final loop, go over previously decoded fsk data and now manchester decode into usable tag ID - // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 - int frame_marker_mask[] = {1,1,1,0,0,0}; - int numshifts = 0; - idx = 0; - while( idx + 6 < size) { - // search for a start of frame marker - - if ( memcmp(GraphBuffer+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { // frame marker found - idx+=6;//sizeof(frame_marker_mask); //size of int is >6 - while(GraphBuffer[idx] != GraphBuffer[idx+1] && idx < size-2) - { - // Keep going until next frame marker (or error) - // Shift in a bit. Start by shifting high registers - hi2 = (hi2<<1)|(hi>>31); - hi = (hi<<1)|(lo>>31); - //Then, shift in a 0 or one into low - if (GraphBuffer[idx] && !GraphBuffer[idx+1]) // 1 0 - lo=(lo<<1)|0; - else // 0 1 - lo=(lo<<1)|1; - numshifts++; - idx += 2; + size_t size = HIDdemodFSK(BitStream,BitLen,&hi2,&hi,&lo); + if (size<0){ + PrintAndLog("Error demoding fsk"); + return 0; } - - //PrintAndLog("Num shifts: %d ", numshifts); - // Hopefully, we read a tag and hit upon the next frame marker - if(idx + 6 < size) - { - if ( memcmp(GraphBuffer+(idx), frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { + if (hi2==0 && hi==0 && lo==0) return 0; if (hi2 != 0){ //extra large HID tags PrintAndLog("TAG ID: %x%08x%08x (%d)", (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + setGraphBuf(BitStream,BitLen); + return 1; } else { //standard HID tags <38 bits //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd - uint8_t bitlen = 0; + uint8_t fmtLen = 0; uint32_t fc = 0; uint32_t cardnum = 0; if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used @@ -769,84 +584,67 @@ int CmdFSKdemodHID(const char *Cmd) lo2=lo2>>1; idx3++; } - bitlen =idx3+19; + fmtLen =idx3+19; fc =0; cardnum=0; - if(bitlen==26){ + if(fmtLen==26){ cardnum = (lo>>1)&0xFFFF; fc = (lo>>17)&0xFF; } - if(bitlen==37){ + if(fmtLen==37){ cardnum = (lo>>1)&0x7FFFF; fc = ((hi&0xF)<<12)|(lo>>20); } - if(bitlen==34){ + if(fmtLen==34){ cardnum = (lo>>1)&0xFFFF; fc= ((hi&1)<<15)|(lo>>17); } - if(bitlen==35){ + if(fmtLen==35){ cardnum = (lo>>1)&0xFFFFF; fc = ((hi&1)<<11)|(lo>>21); } } else { //if bit 38 is not set then 37 bit format is used - bitlen= 37; + fmtLen= 37; fc =0; cardnum=0; - if(bitlen==37){ + if(fmtLen==37){ cardnum = (lo>>1)&0x7FFFF; fc = ((hi&0xF)<<12)|(lo>>20); } } - PrintAndLog("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, - (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); - ClearGraph(1); - return 0; + (unsigned int) fmtLen, (unsigned int) fc, (unsigned int) cardnum); + setGraphBuf(BitStream,BitLen); + return 1; } - } - } - // reset - hi2 = hi = lo = 0; - numshifts = 0; - }else - { - idx++; - } - } - if (idx + sizeof(frame_marker_mask) >= size){ - PrintAndLog("start bits for hid not found"); - PrintAndLog("FSK decoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printBitStream(GraphBuffer,size); - - } - ClearGraph(1); return 0; } //by marshmellow +//IO-Prox demod - FSK RF/64 with preamble of 000000001 +//print ioprox ID and some format details int CmdFSKdemodIO(const char *Cmd) { //raw fsk demod no manchester decoding no start bit finding just get binary from wave //set defaults - uint8_t rfLen = 64; - uint8_t invert=1; - size_t idx=0; - uint8_t testMax=0; - //test samples are not just noise - if (GraphTraceLen < 64) return 0; - for(idx=0;idx<64;idx++){ - if (testMax 92) printBitStream(BitStream,92); + return 0; } - idx=0; - //get full binary from fsk wave - size_t size = fskdemod(rfLen,invert); - - //if not just noise - //PrintAndLog("testMax %d",testMax); - if (testMax>40){ //Index map //0 10 20 30 40 50 60 //| | | | | | | @@ -856,45 +654,26 @@ int CmdFSKdemodIO(const char *Cmd) // //XSF(version)facility:codeone+codetwo (raw) //Handle the data - int mask[] = {0,0,0,0,0,0,0,0,0,1}; - for( idx=0; idx < (size - 74); idx++) { - if ( memcmp(GraphBuffer + idx, mask, sizeof(mask))==0) { - //frame marker found - if (GraphBuffer[idx+17]==1 && GraphBuffer[idx+26]==1 && GraphBuffer[idx+35]==1 && GraphBuffer[idx+44]==1 && GraphBuffer[idx+53]==1){ - //confirmed proper separator bits found + if (idx+64>BitLen) return 0; + PrintAndLog("%d%d%d%d%d%d%d%d %d",BitStream[idx], BitStream[idx+1], BitStream[idx+2], BitStream[idx+3], BitStream[idx+4], BitStream[idx+5], BitStream[idx+6], BitStream[idx+7], BitStream[idx+8]); + PrintAndLog("%d%d%d%d%d%d%d%d %d",BitStream[idx+9], BitStream[idx+10], BitStream[idx+11],BitStream[idx+12],BitStream[idx+13],BitStream[idx+14],BitStream[idx+15],BitStream[idx+16],BitStream[idx+17]); + PrintAndLog("%d%d%d%d%d%d%d%d %d facility",BitStream[idx+18], BitStream[idx+19], BitStream[idx+20],BitStream[idx+21],BitStream[idx+22],BitStream[idx+23],BitStream[idx+24],BitStream[idx+25],BitStream[idx+26]); + PrintAndLog("%d%d%d%d%d%d%d%d %d version",BitStream[idx+27], BitStream[idx+28], BitStream[idx+29],BitStream[idx+30],BitStream[idx+31],BitStream[idx+32],BitStream[idx+33],BitStream[idx+34],BitStream[idx+35]); + PrintAndLog("%d%d%d%d%d%d%d%d %d code1",BitStream[idx+36], BitStream[idx+37], BitStream[idx+38],BitStream[idx+39],BitStream[idx+40],BitStream[idx+41],BitStream[idx+42],BitStream[idx+43],BitStream[idx+44]); + PrintAndLog("%d%d%d%d%d%d%d%d %d code2",BitStream[idx+45], BitStream[idx+46], BitStream[idx+47],BitStream[idx+48],BitStream[idx+49],BitStream[idx+50],BitStream[idx+51],BitStream[idx+52],BitStream[idx+53]); + PrintAndLog("%d%d%d%d%d%d%d%d %d%d checksum",BitStream[idx+54],BitStream[idx+55],BitStream[idx+56],BitStream[idx+57],BitStream[idx+58],BitStream[idx+59],BitStream[idx+60],BitStream[idx+61],BitStream[idx+62],BitStream[idx+63]); + + uint32_t code = bytebits_to_byte(BitStream+idx,32); + uint32_t code2 = bytebits_to_byte(BitStream+idx+32,32); + uint8_t version = bytebits_to_byte(BitStream+idx+27,8); //14,4 + uint8_t facilitycode = bytebits_to_byte(BitStream+idx+18,8) ; + uint16_t number = (bytebits_to_byte(BitStream+idx+36,8)<<8)|(bytebits_to_byte(BitStream+idx+45,8)); //36,9 - PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx], GraphBuffer[idx+1], GraphBuffer[idx+2], GraphBuffer[idx+3], GraphBuffer[idx+4], GraphBuffer[idx+5], GraphBuffer[idx+6], GraphBuffer[idx+7], GraphBuffer[idx+8]); - PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+9], GraphBuffer[idx+10], GraphBuffer[idx+11],GraphBuffer[idx+12],GraphBuffer[idx+13],GraphBuffer[idx+14],GraphBuffer[idx+15],GraphBuffer[idx+16],GraphBuffer[idx+17]); - PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+18], GraphBuffer[idx+19], GraphBuffer[idx+20],GraphBuffer[idx+21],GraphBuffer[idx+22],GraphBuffer[idx+23],GraphBuffer[idx+24],GraphBuffer[idx+25],GraphBuffer[idx+26]); - PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+27], GraphBuffer[idx+28], GraphBuffer[idx+29],GraphBuffer[idx+30],GraphBuffer[idx+31],GraphBuffer[idx+32],GraphBuffer[idx+33],GraphBuffer[idx+34],GraphBuffer[idx+35]); - PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+36], GraphBuffer[idx+37], GraphBuffer[idx+38],GraphBuffer[idx+39],GraphBuffer[idx+40],GraphBuffer[idx+41],GraphBuffer[idx+42],GraphBuffer[idx+43],GraphBuffer[idx+44]); - PrintAndLog("%d%d%d%d%d%d%d%d %d",GraphBuffer[idx+45], GraphBuffer[idx+46], GraphBuffer[idx+47],GraphBuffer[idx+48],GraphBuffer[idx+49],GraphBuffer[idx+50],GraphBuffer[idx+51],GraphBuffer[idx+52],GraphBuffer[idx+53]); - PrintAndLog("%d%d%d%d%d%d%d%d %d%d",GraphBuffer[idx+54],GraphBuffer[idx+55],GraphBuffer[idx+56],GraphBuffer[idx+57],GraphBuffer[idx+58],GraphBuffer[idx+59],GraphBuffer[idx+60],GraphBuffer[idx+61],GraphBuffer[idx+62],GraphBuffer[idx+63]); - - uint32_t code = bytebits_to_byte(GraphBuffer+idx,32); - uint32_t code2 = bytebits_to_byte(GraphBuffer+idx+32,32); - short version = bytebits_to_byte(GraphBuffer+idx+27,8); //14,4 - uint8_t facilitycode = bytebits_to_byte(GraphBuffer+idx+19,8) ; - uint16_t number = (bytebits_to_byte(GraphBuffer+idx+36,8)<<8)|(bytebits_to_byte(GraphBuffer+idx+45,8)); //36,9 - - PrintAndLog("XSF(%02d)%02x:%d (%08x%08x)",version,facilitycode,number,code,code2); - ClearGraph(1); - return 0; - } else { - PrintAndLog("thought we had a valid tag but did not match format"); - } - } - } - if (idx >= (size-74)){ - PrintAndLog("start bits for io prox not found"); - PrintAndLog("FSK decoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printBitStream(GraphBuffer,size); - } - } - ClearGraph(1); - return 0; + PrintAndLog("XSF(%02d)%02x:%05d (%08x%08x)",version,facilitycode,number,code,code2); + setGraphBuf(BitStream,BitLen); + return 1; } + int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating { static const int LowTone[] = { @@ -1093,7 +872,7 @@ int CmdSamples(const char *Cmd) int n = strtol(Cmd, NULL, 0); if (n == 0) - n = 16000; + n = 20000; if (n > sizeof(got)) n = sizeof(got); @@ -1107,6 +886,7 @@ int CmdSamples(const char *Cmd) RepaintGraphWindow(); return 0; } + int CmdTuneSamples(const char *Cmd) { int timeout = 0; @@ -1158,7 +938,6 @@ int CmdTuneSamples(const char *Cmd) return 0; } - int CmdLoad(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0x00}; @@ -1277,7 +1056,6 @@ int CmdManchesterDemod(const char *Cmd) /* If we're not working with 1/0s, demod based off clock */ if (high != 1) { - PrintAndLog("Entering path A"); bit = 0; /* We assume the 1st bit is zero, it may not be * the case: this routine (I think) has an init problem. * Ed. @@ -1585,14 +1363,16 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"amp", CmdAmp, 1, "Amplify peaks"}, - {"askdemod", Cmdaskdemod, 1, "<0|1> -- Attempt to demodulate simple ASK tags"}, + {"askdemod", Cmdaskdemod, 1, "<0 or 1> -- Attempt to demodulate simple ASK tags"}, {"askmandemod", Cmdaskmandemod, 1, "[clock] [invert<0 or 1>] -- Attempt to demodulate ASK/Manchester tags and output binary (args optional[clock will try Auto-detect])"}, + {"askrawdemod", Cmdaskrawdemod, 1, "[clock] [invert<0 or 1>] -- Attempt to demodulate ASK tags and output binary (args optional[clock will try Auto-detect])"}, {"autocorr", CmdAutoCorr, 1, " -- Autocorrelation over window"}, + {"biphaserawdecode",CmdBiphaseDecodeRaw,1,"[offset] Biphase decode binary stream already in graph buffer (offset = bit to start decode from)"}, {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"}, {"bitstream", CmdBitstream, 1, "[clock rate] -- Convert waveform into a bitstream"}, {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, {"dec", CmdDec, 1, "Decimate samples"}, - {"detectclock", CmdDetectClockRate, 1, "Detect clock rate"}, + {"detectaskclock",CmdDetectClockRate, 1, "Detect ASK clock rate"}, {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"}, {"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate graph window as a HID FSK using raw"}, @@ -1605,6 +1385,7 @@ static command_t CommandTable[] = {"load", CmdLoad, 1, " -- Load trace (to graph window"}, {"ltrim", CmdLtrim, 1, " -- Trim samples from left of trace"}, {"mandemod", CmdManchesterDemod, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"}, + {"manrawdecode", Cmdmandecoderaw, 1, "Manchester decode binary stream already in graph buffer"}, {"manmod", CmdManchesterMod, 1, "[clock rate] -- Manchester modulate a binary stream"}, {"norm", CmdNorm, 1, "Normalize max/min to +/-500"}, {"plot", CmdPlot, 1, "Show graph window (hit 'h' in window for keystroke help)"}, diff --git a/client/cmddata.h b/client/cmddata.h index 432ae687..9b8f22ca 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -18,7 +18,9 @@ int CmdData(const char *Cmd); int CmdAmp(const char *Cmd); int Cmdaskdemod(const char *Cmd); int Cmdaskrawdemod(const char *Cmd); +int Cmdaskmandemod(const char *Cmd); int CmdAutoCorr(const char *Cmd); +int CmdBiphaseDecodeRaw(const char *Cmd); int CmdBitsamples(const char *Cmd); int CmdBitstream(const char *Cmd); int CmdBuffClear(const char *Cmd); @@ -34,6 +36,7 @@ int CmdHide(const char *Cmd); int CmdHpf(const char *Cmd); int CmdLoad(const char *Cmd); int CmdLtrim(const char *Cmd); +int Cmdmandecoderaw(const char *Cmd); int CmdManchesterDemod(const char *Cmd); int CmdManchesterMod(const char *Cmd); int CmdNorm(const char *Cmd); diff --git a/client/cmdhfmfdesfire.c b/client/cmdhfmfdesfire.c new file mode 100644 index 00000000..f2c53dbf --- /dev/null +++ b/client/cmdhfmfdesfire.c @@ -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 +#include + +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 "); + 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 "); + 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 index 00000000..c29fd262 --- /dev/null +++ b/client/cmdhfmfdesfire.h @@ -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 diff --git a/client/cmdlf.c b/client/cmdlf.c index 97dcf0ba..70db0575 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -171,9 +171,10 @@ int CmdIndalaDemod(const char *Cmd) count = 0; } } - PrintAndLog("Recovered %d raw bits", rawbit); + 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) { @@ -303,7 +304,7 @@ int CmdIndalaDemod(const char *Cmd) } RepaintGraphWindow(); - return 0; + return 1; } int CmdIndalaClone(const char *Cmd) @@ -567,6 +568,36 @@ int CmdVchDemod(const char *Cmd) return 0; } +//by marshmellow +int CmdLFfind(const char *Cmd) +{ + int ans=0; + if (!offline){ + ans=CmdLFRead(""); + //ans=CmdSamples("20000"); + } + if (GraphTraceLen<1000) return 0; + PrintAndLog("Checking for known tags:"); + + ans=Cmdaskmandemod(""); + PrintAndLog("ASK_MAN: %s", (ans)?"YES":"NO" ); + + ans=CmdFSKdemodHID(""); + PrintAndLog("HID: %s", (ans)?"YES":"NO" ); + + ans=CmdFSKdemodIO(""); + PrintAndLog("IO prox: %s", (ans)?"YES":"NO" ); + + ans=CmdIndalaDemod(""); + PrintAndLog("Indala (64): %s", (ans)?"YES":"NO" ); + + ans=CmdIndalaDemod("224"); + PrintAndLog("Indala (224): %s", (ans)?"YES":"NO" ); + + //PrintAndLog("No Known Tags Found!\n"); + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -579,6 +610,7 @@ static command_t CommandTable[] = {"read", CmdLFRead, 0, "['h' or ] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134, alternatively: f=12MHz/(divisor+1))"}, + {"search", CmdLFfind, 1, "Read and Search for valid known tag (in offline mode it you can load first then search)"}, {"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"}, {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, {"simman", CmdLFSimManchester, 0, " [GAP] Simulate arbitrary Manchester LF tag"}, diff --git a/client/cmdlf.h b/client/cmdlf.h index 7278754b..e298d659 100644 --- a/client/cmdlf.h +++ b/client/cmdlf.h @@ -23,5 +23,6 @@ int CmdLFSimBidir(const char *Cmd); int CmdLFSimManchester(const char *Cmd); int CmdLFSnoop(const char *Cmd); int CmdVchDemod(const char *Cmd); +int CmdLFfind(const char *Cmd); #endif diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index c5f57d55..6567ee41 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -28,6 +28,20 @@ char *global_em410xId; static int CmdHelp(const char *Cmd); + + +int CmdEMdemodASK(const char *Cmd) +{ + int findone=0; + UsbCommand c={CMD_EM410X_DEMOD}; + if(Cmd[0]=='1') findone=1; + c.arg[0]=findone; + SendCommand(&c); + return 0; +} + + + /* Read the ID of an EM410x tag. * Format: * 1111 1111 1 <-- standard non-repeatable header @@ -644,7 +658,7 @@ int CmdWriteWordPWD(const char *Cmd) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - + {"410xdemod", CmdEMdemodASK, 0, "[clock rate] -- Extract ID from EM410x tag"}, {"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, {"410xsim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, {"replay", MWRem4xReplay, 0, "Watches for tag and simulates manchester encoded em4x tag"}, diff --git a/client/cmdlfem4x.h b/client/cmdlfem4x.h index 587dbf7f..2282f64e 100644 --- a/client/cmdlfem4x.h +++ b/client/cmdlfem4x.h @@ -12,7 +12,7 @@ #define CMDLFEM4X_H__ int CmdLFEM4X(const char *Cmd); - +int CmdEMdemodASK(const char *Cmd); int CmdEM410xRead(const char *Cmd); int CmdEM410xSim(const char *Cmd); int CmdEM410xWatch(const char *Cmd); diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 6d1cb87d..74578eea 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -159,6 +159,7 @@ int CmdLFHitagSim(const char *Cmd) { tag_mem_supplied = true; if (fread(c.d.asBytes,48,1,pf) == 0) { PrintAndLog("Error: File reading error"); + fclose(pf); return 1; } fclose(pf); diff --git a/client/graph.c b/client/graph.c index bb815995..ff5a02e4 100644 --- a/client/graph.c +++ b/client/graph.c @@ -13,6 +13,7 @@ #include #include "ui.h" #include "graph.h" +#include "lfdemod.h" int GraphBuffer[MAX_GRAPH_TRACE_LEN]; int GraphTraceLen; @@ -51,9 +52,9 @@ int ClearGraph(int redraw) /* * Detect clock rate */ - //decommissioned - has difficulty detecting rf/32 and only works if data is manchester encoded + //decommissioned - has difficulty detecting rf/32 /* -int DetectClock2(int peak) +int DetectClockOld(int peak) { int i; int clock = 0xFFFF; @@ -65,6 +66,7 @@ int DetectClock2(int peak) if (GraphBuffer[i] > peak) peak = GraphBuffer[i]; + // peak=(int)(peak*.75); for (i = 1; i < GraphTraceLen; ++i) { // If this is the beginning of a peak @@ -80,17 +82,21 @@ int DetectClock2(int peak) return clock; } */ +/* +NOW IN LFDEMOD.C // by marshmellow // not perfect especially with lower clocks or VERY good antennas (heavy wave clipping) // maybe somehow adjust peak trimming value based on samples to fix? -int DetectClock(int peak) +int DetectASKClock(int peak) { int i=0; int low=0; int clk[]={16,32,40,50,64,100,128,256}; + int loopCnt = 256; + if (GraphTraceLenpeak){ peak = GraphBuffer[i]; } @@ -101,15 +107,11 @@ int DetectClock(int peak) peak=(int)(peak*.75); low= (int)(low*.75); } - //int numbits; int ii; - int loopCnt = 256; - if (GraphTraceLen=peak) || (GraphBuffer[ii]<=low)){ - //numbits=0; - //good=1; errCnt[clkCnt]=0; for (i=0; i<((int)(GraphTraceLen/clk[clkCnt])-1); ++i){ if (GraphBuffer[ii+(i*clk[clkCnt])]>=peak || GraphBuffer[ii+(i*clk[clkCnt])]<=low){ - //numbits++; }else if(GraphBuffer[ii+(i*clk[clkCnt])-tol]>=peak || GraphBuffer[ii+(i*clk[clkCnt])-tol]<=low){ }else if(GraphBuffer[ii+(i*clk[clkCnt])+tol]>=peak || GraphBuffer[ii+(i*clk[clkCnt])+tol]<=low){ }else{ //error no peak detected - //numbits=0; - //good=0; errCnt[clkCnt]++; - //break; } } if(errCnt[clkCnt]==0) return clk[clkCnt]; if(errCnt[clkCnt]127) GraphBuffer[i]=127; //trim + if (GraphBuffer[i]<-127) GraphBuffer[i]=-127; //trim + buff[i]=(uint8_t)(GraphBuffer[i]+128); + } + return i; +} /* Get or auto-detect clock rate */ int GetClock(const char *str, int peak, int verbose) { @@ -164,7 +179,9 @@ int GetClock(const char *str, int peak, int verbose) /* Auto-detect clock */ if (!clock) { - clock = DetectClock(peak); + uint8_t grph[MAX_GRAPH_TRACE_LEN]={0}; + int size = getFromGraphBuf(grph); + clock = DetectASKClock(grph,size,0); //clock2 = DetectClock2(peak); /* Only print this message if we're not looping something */ if (!verbose) diff --git a/client/graph.h b/client/graph.h index ce803c82..afe23686 100644 --- a/client/graph.h +++ b/client/graph.h @@ -13,8 +13,10 @@ void AppendGraph(int redraw, int clock, int bit); int ClearGraph(int redraw); -int DetectClock(int peak); +//int DetectClock(int peak); +int getFromGraphBuf(uint8_t *buff); int GetClock(const char *str, int peak, int verbose); +void setGraphBuf(uint8_t *buff,int size); bool HasGraphData(); #define MAX_GRAPH_TRACE_LEN (1024*128) diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index 8c6a278a..f9c62273 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -207,6 +207,7 @@ void printarr_human_readable(char * title, uint8_t* arr, int len) cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i)); } prnlog(output); + free(output); } //----------------------------- diff --git a/client/loclass/hash1_brute.c b/client/loclass/hash1_brute.c new file mode 100644 index 00000000..a9fe0d19 --- /dev/null +++ b/client/loclass/hash1_brute.c @@ -0,0 +1,92 @@ +#include +#include "cipherutils.h" +#include +#include +#include +#include +#include +#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 index 00000000..b26ad96d --- /dev/null +++ b/client/loclass/hash1_brute.h @@ -0,0 +1,5 @@ +#ifndef HASH1_BRUTE_H +#define HASH1_BRUTE_H +void brute_hash1(); + +#endif // HASH1_BRUTE_H diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index a55227ef..4c5bba2b 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -742,7 +742,11 @@ int readKeyFile(uint8_t key[8]) f = fopen("iclass_key.bin", "rb"); if (f) { - if(fread(key, sizeof(key), 1, f) == 1) return 0; + if(fread(key, sizeof(uint8_t), 8, f) == 1) + { + retval = 0; + } + fclose(f); } return retval; } diff --git a/common/lfdemod.c b/common/lfdemod.c new file mode 100644 index 00000000..d30262f3 --- /dev/null +++ b/common/lfdemod.c @@ -0,0 +1,677 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2014 +// +// 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 commands +//----------------------------------------------------------------------------- + +#include +#include +#include "lfdemod.h" + +//by marshmellow +//takes 1s and 0s and searches for EM410x format - output EM ID +uint64_t Em410xDecode(uint8_t *BitStream,uint32_t BitLen) +{ + //no arguments needed - built this way in case we want this to be a direct call from "data " cmds in the future + // otherwise could be a void with no arguments + //set defaults + int high=0, low=128; + uint64_t lo=0; //hi=0, + + uint32_t i = 0; + uint32_t initLoopMax = 65; + if (initLoopMax>BitLen) initLoopMax=BitLen; + + for (;i < initLoopMax; ++i) //65 samples should be plenty to find high and low values + { + if (BitStream[i] > high) + high = BitStream[i]; + else if (BitStream[i] < low) + low = BitStream[i]; + } + if (((high !=1)||(low !=0))){ //allow only 1s and 0s + // PrintAndLog("no data found"); + return 0; + } + uint8_t parityTest=0; + // 111111111 bit pattern represent start of frame + uint8_t frame_marker_mask[] = {1,1,1,1,1,1,1,1,1}; + uint32_t idx = 0; + uint32_t ii=0; + uint8_t resetCnt = 0; + while( (idx + 64) < BitLen) { + restart: + // search for a start of frame marker + if ( memcmp(BitStream+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { // frame marker found + idx+=9;//sizeof(frame_marker_mask); + for (i=0; i<10;i++){ + for(ii=0; ii<5; ++ii){ + parityTest += BitStream[(i*5)+ii+idx]; + } + if (parityTest== ((parityTest>>1)<<1)){ + parityTest=0; + for (ii=0; ii<4;++ii){ + //hi = (hi<<1)|(lo>>31); + lo=(lo<<1LL)|(BitStream[(i*5)+ii+idx]); + } + //PrintAndLog("DEBUG: EM parity passed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d,lo: %d",parityTest,i,ii,idx,BitStream[idx+ii+(i*5)-5],BitStream[idx+ii+(i*5)-4],BitStream[idx+ii+(i*5)-3],BitStream[idx+ii+(i*5)-2],BitStream[idx+ii+(i*5)-1],lo); + }else {//parity failed + //PrintAndLog("DEBUG: EM parity failed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d",parityTest,i,ii,idx,BitStream[idx+ii+(i*5)-5],BitStream[idx+ii+(i*5)-4],BitStream[idx+ii+(i*5)-3],BitStream[idx+ii+(i*5)-2],BitStream[idx+ii+(i*5)-1]); + parityTest=0; + idx-=8; + if (resetCnt>5)return 0; + resetCnt++; + goto restart;//continue; + } + } + //skip last 5 bit parity test for simplicity. + return lo; + }else{ + idx++; + } + } + return 0; +} + +//by marshmellow +//takes 2 arguments - clock and invert both as integers +//attempts to demodulate ask while decoding manchester +//prints binary found and saves in graphbuffer for further commands +int askmandemod(uint8_t * BinStream,uint32_t *BitLen,int *clk, int *invert) +{ + int i; + int high = 0, low = 128; + *clk=DetectASKClock(BinStream,(size_t)*BitLen,*clk); //clock default + + if (*clk<8) *clk =64; + if (*clk<32) *clk=32; + if (*invert != 1) *invert=0; + + uint32_t initLoopMax = 200; + if (initLoopMax>*BitLen) initLoopMax=*BitLen; + + // Detect high and lows + for (i = 0; i < initLoopMax; ++i) //200 samples should be enough to find high and low values + { + if (BinStream[i] > high) + high = BinStream[i]; + else if (BinStream[i] < low) + low = BinStream[i]; + } + if ((high < 158) ){ //throw away static + return -2; + } + //25% fuzz in case highs and lows aren't clipped [marshmellow] + high=(int)((high-128)*.75)+128; + low= (int)((low-128)*.75)+128; + + //PrintAndLog("DEBUG - valid high: %d - valid low: %d",high,low); + int lastBit = 0; //set first clock check + uint32_t bitnum = 0; //output counter + int tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave + if (*clk==32)tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely + int iii = 0; + uint32_t gLen = *BitLen; + if (gLen > 3000) gLen=3000; + uint8_t errCnt =0; + uint32_t bestStart = *BitLen; + uint32_t bestErrCnt = (*BitLen/1000); + uint32_t maxErr = (*BitLen/1000); + + //loop to find first wave that works + for (iii=0; iii < gLen; ++iii){ + if ((BinStream[iii]>=high)||(BinStream[iii]<=low)){ + lastBit=iii-*clk; + errCnt=0; + //loop through to see if this start location works + for (i = iii; i < *BitLen; ++i) { + if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ + lastBit+=*clk; + } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ + //low found and we are expecting a bar + lastBit+=*clk; + } else { + //mid value found or no bar supposed to be here + if ((i-lastBit)>(*clk+tol)){ + //should have hit a high or low based on clock!! + + errCnt++; + lastBit+=*clk;//skip over until hit too many errors + if (errCnt>(maxErr)) break; //allow 1 error for every 1000 samples else start over + } + } + if ((i-iii) >(400 * *clk)) break; //got plenty of bits + } + //we got more than 64 good bits and not all errors + if ((((i-iii)/ *clk) > (64+errCnt)) && (errCnt= high) && ((i-lastBit)>(*clk-tol))){ + lastBit+=*clk; + BinStream[bitnum] = *invert; + bitnum++; + } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ + //low found and we are expecting a bar + lastBit+=*clk; + BinStream[bitnum] = 1-*invert; + bitnum++; + } else { + //mid value found or no bar supposed to be here + if ((i-lastBit)>(*clk+tol)){ + //should have hit a high or low based on clock!! + + if (bitnum > 0){ + BinStream[bitnum]=77; + bitnum++; + } + + lastBit+=*clk;//skip over error + } + } + if (bitnum >=400) break; + } + *BitLen=bitnum; + } else{ + *invert=bestStart; + *clk=iii; + return -1; + } + return bestErrCnt; +} + +//by marshmellow +//take 10 and 01 and manchester decode +//run through 2 times and take least errCnt +int manrawdecode(uint8_t * BitStream, int *bitLen) +{ + int bitnum=0; + int errCnt =0; + int i=1; + int bestErr = 1000; + int bestRun = 0; + int ii=1; + for (ii=1;ii<3;++ii){ + i=1; + for (i=i+ii;i<*bitLen-2;i+=2){ + if(BitStream[i]==1 && (BitStream[i+1]==0)){ + } else if((BitStream[i]==0)&& BitStream[i+1]==1){ + } else { + errCnt++; + } + if(bitnum>300) break; + } + if (bestErr>errCnt){ + bestErr=errCnt; + bestRun=ii; + } + errCnt=0; + } + errCnt=bestErr; + if (errCnt<20){ + ii=bestRun; + i=1; + for (i=i+ii;i<*bitLen-2;i+=2){ + if(BitStream[i]==1 && (BitStream[i+1]==0)){ + BitStream[bitnum++]=0; + } else if((BitStream[i]==0)&& BitStream[i+1]==1){ + BitStream[bitnum++]=1; + } else { + BitStream[bitnum++]=77; + //errCnt++; + } + if(bitnum>300) break; + } + *bitLen=bitnum; + } + return errCnt; +} + + +//by marshmellow +//take 01 or 10 = 0 and 11 or 00 = 1 +int BiphaseRawDecode(uint8_t * BitStream, int *bitLen, int offset) +{ + uint8_t bitnum = 0; + uint32_t errCnt = 0; + uint32_t i = 1; + i=offset; + for (;i<*bitLen-2;i+=2){ + if((BitStream[i]==1 && BitStream[i+1]==0)||(BitStream[i]==0 && BitStream[i+1]==1)){ + BitStream[bitnum++]=1; + } else if((BitStream[i]==0 && BitStream[i+1]==0)||(BitStream[i]==1 && BitStream[i+1]==1)){ + BitStream[bitnum++]=0; + } else { + BitStream[bitnum++]=77; + errCnt++; + } + if(bitnum>250) break; + } + *bitLen=bitnum; + return errCnt; +} + +//by marshmellow +//takes 2 arguments - clock and invert both as integers +//attempts to demodulate ask only +//prints binary found and saves in graphbuffer for further commands +int askrawdemod(uint8_t *BinStream, int *bitLen,int *clk, int *invert) +{ + uint32_t i; + // int invert=0; //invert default + int high = 0, low = 128; + *clk=DetectASKClock(BinStream,*bitLen,*clk); //clock default + uint8_t BitStream[502] = {0}; + + if (*clk<8) *clk =64; + if (*clk<32) *clk=32; + if (*invert != 1) *invert = 0; + + uint32_t initLoopMax = 200; + if (initLoopMax>*bitLen) initLoopMax=*bitLen; + // Detect high and lows + for (i = 0; i < initLoopMax; ++i) //200 samples should be plenty to find high and low values + { + if (BinStream[i] > high) + high = BinStream[i]; + else if (BinStream[i] < low) + low = BinStream[i]; + } + if ((high < 158)){ //throw away static + return -2; + } + //25% fuzz in case highs and lows aren't clipped [marshmellow] + high=(int)((high-128)*.75)+128; + low= (int)((low-128)*.75)+128; + + int lastBit = 0; //set first clock check + uint32_t bitnum = 0; //output counter + uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave + if (*clk==32) tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely + uint32_t iii = 0; + uint32_t gLen = *bitLen; + if (gLen > 500) gLen=500; + uint8_t errCnt =0; + uint32_t bestStart = *bitLen; + uint32_t bestErrCnt = (*bitLen/1000); + uint8_t midBit=0; + + //loop to find first wave that works + for (iii=0; iii < gLen; ++iii){ + if ((BinStream[iii]>=high)||(BinStream[iii]<=low)){ + lastBit=iii-*clk; + //loop through to see if this start location works + for (i = iii; i < *bitLen; ++i) { + if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ + lastBit+=*clk; + BitStream[bitnum] = *invert; + bitnum++; + midBit=0; + } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ + //low found and we are expecting a bar + lastBit+=*clk; + BitStream[bitnum] = 1-*invert; + bitnum++; + midBit=0; + } else if ((BinStream[i]<=low) && (midBit==0) && ((i-lastBit)>((*clk/2)-tol))){ + //mid bar? + midBit=1; + BitStream[bitnum]= 1-*invert; + bitnum++; + } else if ((BinStream[i]>=high)&&(midBit==0) && ((i-lastBit)>((*clk/2)-tol))){ + //mid bar? + midBit=1; + BitStream[bitnum]= *invert; + bitnum++; + } else if ((i-lastBit)>((*clk/2)+tol)&&(midBit==0)){ + //no mid bar found + midBit=1; + BitStream[bitnum]= BitStream[bitnum-1]; + bitnum++; + } else { + //mid value found or no bar supposed to be here + + if ((i-lastBit)>(*clk+tol)){ + //should have hit a high or low based on clock!! + + if (bitnum > 0){ + BitStream[bitnum]=77; + bitnum++; + } + + errCnt++; + lastBit+=*clk;//skip over until hit too many errors + if (errCnt>((*bitLen/1000))){ //allow 1 error for every 1000 samples else start over + errCnt=0; + bitnum=0;//start over + break; + } + } + } + if (bitnum>500) break; + } + //we got more than 64 good bits and not all errors + if ((bitnum > (64+errCnt)) && (errCnt<(*bitLen/1000))) { + //possible good read + if (errCnt==0) break; //great read - finish + if (bestStart == iii) break; //if current run == bestErrCnt run (after exhausted testing) then finish + if (errCnt=gLen){ //exhausted test + //if there was a ok test go back to that one and re-run the best run (then dump after that run) + if (bestErrCnt < (*bitLen/1000)) iii=bestStart; + } + } + if (bitnum>16){ + + for (i=0; i < bitnum; ++i){ + BinStream[i]=BitStream[i]; + } + *bitLen = bitnum; + } else { + return -1; + } + return errCnt; +} +//translate wave to 11111100000 (1 for each short wave 0 for each long wave) +size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow) +{ + uint32_t last_transition = 0; + uint32_t idx = 1; + uint32_t maxVal=0; + if (fchigh==0) fchigh=10; + if (fclow==0) fclow=8; + // we do care about the actual theshold value as sometimes near the center of the + // wave we may get static that changes direction of wave for one value + // if our value is too low it might affect the read. and if our tag or + // antenna is weak a setting too high might not see anything. [marshmellow] + if (size<100) return 0; + for(idx=1; idx<100; idx++){ + if(maxVal1 transition + if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition + if ((idx-last_transition)<(fclow-2)){ //0-5 = garbage noise + //do nothing with extra garbage + } else if ((idx-last_transition) < (fchigh-1)) { //6-8 = 8 waves + dest[numBits]=1; + } else { //9+ = 10 waves + dest[numBits]=0; + } + last_transition = idx; + numBits++; + } + } + return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 +} + +uint32_t myround2(float f) +{ + if (f >= 2000) return 2000;//something bad happened + return (uint32_t) (f + (float)0.5); +} + +//translate 11111100000 to 10 +size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert,uint8_t fchigh,uint8_t fclow )// uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, +{ + uint8_t lastval=dest[0]; + uint32_t idx=0; + size_t numBits=0; + uint32_t n=1; + + for( idx=1; idx < size; idx++) { + + if (dest[idx]==lastval) { + n++; + continue; + } + //if lastval was 1, we have a 1->0 crossing + if ( dest[idx-1]==1 ) { + n=myround2((float)(n+1)/((float)(rfLen)/(float)fclow)); + //n=(n+1) / h2l_crossing_value; + } else {// 0->1 crossing + n=myround2((float)(n+1)/((float)(rfLen-2)/(float)fchigh)); //-2 for fudge factor + //n=(n+1) / l2h_crossing_value; + } + if (n == 0) n = 1; + + if(n < maxConsequtiveBits) //Consecutive + { + if(invert==0){ //invert bits + memset(dest+numBits, dest[idx-1] , n); + }else{ + memset(dest+numBits, dest[idx-1]^1 , n); + } + numBits += n; + } + n=0; + lastval=dest[idx]; + }//end for + return numBits; +} +//by marshmellow (from holiman's base) +// full fsk demod from GraphBuffer wave to decoded 1s and 0s (no mandemod) +int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow) +{ + // FSK demodulator + size = fsk_wave_demod(dest, size, fchigh, fclow); + size = aggregate_bits(dest, size,rfLen,192,invert,fchigh,fclow); + return size; +} +// loop to get raw HID waveform then FSK demodulate the TAG ID from it +int HIDdemodFSK(uint8_t *dest, size_t size, uint32_t *hi2, uint32_t *hi, uint32_t *lo) +{ + + size_t idx=0; //, found=0; //size=0, + // FSK demodulator + size = fskdemod(dest, size,50,0,10,8); + + // final loop, go over previously decoded manchester data and decode into usable tag ID + // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 + uint8_t frame_marker_mask[] = {1,1,1,0,0,0}; + int numshifts = 0; + idx = 0; + //one scan + while( idx + sizeof(frame_marker_mask) < size) { + // search for a start of frame marker + if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { // frame marker found + idx+=sizeof(frame_marker_mask); + while(dest[idx] != dest[idx+1] && idx < size-2) + { + // Keep going until next frame marker (or error) + // Shift in a bit. Start by shifting high registers + *hi2 = (*hi2<<1)|(*hi>>31); + *hi = (*hi<<1)|(*lo>>31); + //Then, shift in a 0 or one into low + if (dest[idx] && !dest[idx+1]) // 1 0 + *lo=(*lo<<1)|0; + else // 0 1 + *lo=(*lo<<1)|1; + numshifts++; + idx += 2; + } + // Hopefully, we read a tag and hit upon the next frame marker + if(idx + sizeof(frame_marker_mask) < size) + { + if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { + //good return + return idx; + } + } + // reset + *hi2 = *hi = *lo = 0; + numshifts = 0; + }else { + idx++; + } + } + return -1; +} + +uint32_t bytebits_to_byte(uint8_t* src, int numbits) +{ + uint32_t num = 0; + for(int i = 0 ; i < numbits ; i++) { + num = (num << 1) | (*src); + src++; + } + return num; +} + +int IOdemodFSK(uint8_t *dest, size_t size) +{ + uint32_t idx=0; + //make sure buffer has data + if (size < 66) return -1; + //test samples are not just noise + uint8_t testMax=0; + for(idx=0;idx<65;idx++){ + if (testMax170){ + // FSK demodulator + size = fskdemod(dest, size,64,1,10,8); // RF/64 and invert + if (size < 65) return -1; //did we get a good demod? + //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 + uint8_t mask[] = {0,0,0,0,0,0,0,0,0,1}; + for( idx=0; idx < (size - 65); idx++) { + if ( memcmp(dest + idx, mask, sizeof(mask))==0) { + //frame marker found + if (!dest[idx+8] && dest[idx+17]==1 && dest[idx+26]==1 && dest[idx+35]==1 && dest[idx+44]==1 && dest[idx+53]==1){ + //confirmed proper separator bits found + //return start position + return (int) idx; + } + } + } + } + return 0; +} + +// by marshmellow +// not perfect especially with lower clocks or VERY good antennas (heavy wave clipping) +// maybe somehow adjust peak trimming value based on samples to fix? +int DetectASKClock(uint8_t dest[], size_t size, int clock) +{ + int i=0; + int peak=0; + int low=128; + int clk[]={16,32,40,50,64,100,128,256}; + int loopCnt = 256; //don't need to loop through entire array... + if (sizepeak){ + peak = dest[i]; + } + if(dest[i]=peak) || (dest[ii]<=low)){ + errCnt[clkCnt]=0; + // now that we have the first one lined up test rest of wave array + for (i=0; i<((int)(size/clk[clkCnt])-1); ++i){ + if (dest[ii+(i*clk[clkCnt])]>=peak || dest[ii+(i*clk[clkCnt])]<=low){ + }else if(dest[ii+(i*clk[clkCnt])-tol]>=peak || dest[ii+(i*clk[clkCnt])-tol]<=low){ + }else if(dest[ii+(i*clk[clkCnt])+tol]>=peak || dest[ii+(i*clk[clkCnt])+tol]<=low){ + }else{ //error no peak detected + errCnt[clkCnt]++; + } + } + //if we found no errors this is correct one - return this clock + if(errCnt[clkCnt]==0) return clk[clkCnt]; + //if we found errors see if it is lowest so far and save it as best run + if(errCnt[clkCnt] + +int DetectASKClock(uint8_t dest[], size_t size, int clock); +int askmandemod(uint8_t *BinStream,uint32_t *BitLen,int *clk, int *invert); +uint64_t Em410xDecode(uint8_t *BitStream,uint32_t BitLen); +int manrawdecode(uint8_t *BitStream, int *bitLen); +int BiphaseRawDecode(uint8_t * BitStream, int *bitLen, int offset); +int askrawdemod(uint8_t *BinStream, int *bitLen,int *clk, int *invert); +int HIDdemodFSK(uint8_t *dest, size_t size, uint32_t *hi2, uint32_t *hi, uint32_t *lo); +int IOdemodFSK(uint8_t *dest, size_t size); +int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow); +uint32_t bytebits_to_byte(uint8_t* src, int numbits); + +#endif diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 65631d98..18e54e33 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -81,6 +81,8 @@ typedef struct { #define CMD_EM4X_WRITE_WORD 0x0219 #define CMD_IO_DEMOD_FSK 0x021A #define CMD_IO_CLONE_TAG 0x021B +#define CMD_EM410X_DEMOD 0x021c + /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ // For the 13.56 MHz tags diff --git a/traces/Casi-12ed825c29.pm3 b/traces/Casi-12ed825c29.pm3 new file mode 100644 index 00000000..d49c13a2 --- /dev/null +++ b/traces/Casi-12ed825c29.pm3 @@ -0,0 +1,16000 @@ +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +115 +104 +62 +24 +-7 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +112 +111 +104 +99 +89 +83 +76 +71 +65 +61 +55 +19 +-13 +-38 +-61 +-78 +-94 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +95 +94 +89 +84 +76 +71 +64 +61 +55 +52 +47 +44 +40 +37 +33 +31 +28 +27 +23 +22 +19 +18 +16 +15 +13 +13 +10 +-20 +-46 +-66 +-85 +-99 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +5 +127 +127 +127 +114 +80 +78 +74 +70 +63 +59 +53 +50 +45 +42 +38 +4 +-25 +-49 +-70 +-86 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +60 +22 +-8 +-35 +-56 +-75 +-90 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +111 +110 +104 +97 +88 +83 +75 +70 +64 +60 +54 +52 +45 +43 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +13 +-18 +-44 +-65 +-84 +-98 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +116 +109 +99 +93 +85 +79 +72 +68 +62 +59 +52 +49 +45 +42 +38 +36 +32 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +120 +85 +84 +79 +75 +68 +63 +57 +53 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +125 +90 +88 +84 +79 +71 +67 +60 +57 +51 +48 +43 +9 +-21 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +90 +90 +85 +80 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +114 +104 +97 +89 +83 +77 +72 +65 +61 +56 +52 +47 +45 +40 +37 +34 +31 +28 +-5 +-33 +-55 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +14 +127 +127 +127 +121 +86 +85 +80 +76 +68 +64 +58 +55 +49 +46 +42 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +91 +90 +85 +80 +72 +67 +61 +58 +52 +49 +44 +10 +-21 +-45 +-67 +-83 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +97 +88 +83 +76 +71 +65 +60 +55 +52 +46 +44 +39 +37 +33 +31 +27 +-5 +-33 +-56 +-76 +-91 +-106 +-100 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +121 +85 +84 +79 +75 +68 +63 +57 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +90 +89 +84 +79 +71 +67 +60 +56 +51 +48 +43 +9 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +61 +23 +-8 +-34 +-56 +-74 +-89 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +112 +110 +104 +99 +89 +83 +76 +71 +65 +61 +55 +19 +-13 +-38 +-61 +-78 +-94 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +95 +94 +89 +84 +75 +70 +64 +60 +55 +51 +46 +44 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +15 +15 +13 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +115 +108 +98 +56 +19 +-11 +-37 +-58 +-77 +-91 +-104 +-98 +-108 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +109 +108 +102 +96 +87 +82 +74 +70 +63 +60 +54 +51 +45 +43 +38 +37 +32 +31 +27 +26 +23 +22 +19 +18 +15 +15 +12 +-18 +-44 +-65 +-84 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +82 +74 +70 +63 +59 +53 +51 +46 +44 +39 +37 +33 +31 +28 +-5 +-33 +-55 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +100 +94 +86 +81 +73 +69 +63 +59 +53 +50 +45 +42 +38 +35 +32 +30 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +94 +87 +81 +74 +70 +63 +60 +54 +50 +45 +43 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +81 +74 +70 +63 +59 +54 +50 +45 +42 +38 +36 +32 +30 +27 +-5 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +120 +85 +85 +80 +75 +68 +63 +57 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +61 +23 +-7 +-34 +-56 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +46 +127 +127 +127 +127 +112 +110 +104 +98 +89 +83 +75 +71 +64 +61 +55 +19 +-13 +-38 +-61 +-79 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +95 +93 +88 +83 +75 +70 +63 +60 +54 +51 +45 +11 +-20 +-44 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +62 +58 +53 +50 +45 +10 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +21 +127 +127 +127 +127 +92 +91 +86 +81 +72 +68 +62 +58 +53 +50 +45 +42 +37 +36 +31 +30 +27 +25 +22 +22 +19 +18 +15 +15 +13 +12 +10 +-20 +-46 +-67 +-85 +-99 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +115 +108 +99 +93 +85 +79 +72 +68 +62 +58 +52 +49 +44 +42 +38 +35 +32 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +14 +127 +127 +127 +121 +86 +85 +80 +75 +68 +63 +57 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +111 +101 +59 +21 +-9 +-35 +-56 +-75 +-90 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +42 +127 +127 +127 +127 +110 +108 +102 +97 +88 +81 +74 +70 +64 +60 +54 +51 +46 +43 +39 +37 +33 +31 +28 +27 +23 +23 +20 +19 +16 +16 +13 +-17 +-44 +-65 +-83 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +100 +94 +85 +80 +72 +69 +62 +58 +53 +50 +45 +42 +37 +35 +31 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +102 +59 +21 +-9 +-35 +-57 +-75 +-90 +-103 +-98 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +111 +109 +104 +97 +88 +83 +75 +70 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-94 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +22 +127 +127 +127 +127 +95 +93 +88 +83 +75 +70 +64 +59 +54 +51 +46 +11 +-20 +-44 +-65 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +22 +127 +127 +127 +127 +92 +91 +86 +82 +73 +68 +62 +59 +53 +50 +45 +42 +37 +36 +32 +30 +27 +26 +23 +21 +19 +18 +15 +15 +13 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +3 +127 +127 +127 +115 +80 +79 +74 +70 +63 +59 +52 +50 +45 +42 +37 +3 +-26 +-49 +-70 +-87 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +16 +127 +127 +127 +124 +88 +87 +83 +78 +70 +65 +59 +56 +51 +47 +43 +8 +-22 +-46 +-67 +-84 +-99 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +91 +90 +85 +80 +72 +67 +61 +58 +52 +49 +44 +10 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +91 +89 +84 +79 +72 +67 +60 +57 +51 +48 +43 +9 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +91 +90 +85 +80 +71 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +21 +127 +127 +127 +127 +92 +91 +85 +81 +73 +68 +62 +59 +52 +49 +45 +10 +-20 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +85 +81 +72 +68 +61 +58 +52 +49 +44 +10 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +90 +90 +84 +79 +72 +67 +61 +57 +51 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +114 +104 +61 +23 +-7 +-34 +-56 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +112 +110 +104 +98 +89 +83 +76 +71 +65 +61 +55 +19 +-13 +-38 +-61 +-78 +-94 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +94 +89 +84 +75 +70 +64 +61 +55 +51 +46 +44 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +12 +12 +10 +-19 +-46 +-66 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +7 +127 +127 +127 +115 +80 +79 +75 +70 +63 +59 +53 +51 +45 +42 +38 +5 +-25 +-49 +-70 +-86 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +111 +102 +60 +22 +-8 +-35 +-56 +-75 +-90 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +42 +127 +127 +127 +127 +110 +109 +103 +97 +88 +82 +75 +70 +63 +60 +54 +51 +46 +43 +39 +37 +33 +30 +28 +26 +23 +22 +19 +18 +16 +15 +12 +-18 +-44 +-65 +-84 +-98 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +109 +99 +93 +85 +79 +72 +69 +62 +59 +53 +49 +44 +42 +38 +35 +31 +30 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +121 +86 +85 +79 +75 +68 +63 +57 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +125 +90 +89 +84 +79 +72 +67 +60 +57 +52 +48 +44 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +91 +89 +84 +80 +72 +67 +61 +57 +51 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +97 +89 +84 +77 +72 +65 +61 +56 +52 +47 +44 +40 +37 +33 +31 +28 +-5 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +121 +86 +85 +80 +76 +68 +63 +57 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +125 +90 +89 +84 +79 +72 +67 +60 +56 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +115 +104 +98 +89 +84 +77 +72 +65 +61 +55 +52 +47 +44 +40 +37 +33 +31 +28 +-5 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +121 +85 +84 +79 +75 +67 +63 +56 +54 +48 +45 +41 +6 +-24 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +90 +89 +84 +79 +71 +66 +60 +56 +51 +48 +43 +9 +-22 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +111 +109 +104 +97 +88 +82 +75 +70 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +94 +93 +88 +83 +75 +70 +63 +60 +54 +51 +46 +44 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +13 +13 +10 +-19 +-45 +-66 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +115 +108 +99 +57 +19 +-10 +-37 +-58 +-76 +-91 +-104 +-98 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +42 +127 +127 +127 +127 +109 +108 +102 +96 +87 +81 +74 +69 +63 +59 +53 +50 +45 +43 +38 +36 +32 +30 +27 +25 +22 +21 +19 +17 +15 +14 +12 +-18 +-44 +-65 +-84 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +115 +109 +99 +93 +85 +80 +72 +68 +62 +59 +53 +50 +45 +43 +38 +36 +33 +31 +27 +-5 +-33 +-56 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +112 +102 +96 +88 +82 +75 +70 +63 +60 +54 +51 +45 +43 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +100 +94 +86 +81 +73 +69 +63 +59 +53 +50 +45 +43 +38 +36 +32 +31 +27 +-5 +-33 +-56 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +94 +86 +81 +74 +69 +62 +59 +53 +50 +45 +43 +38 +36 +32 +30 +27 +-5 +-34 +-56 +-76 +-92 +-106 +-101 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +120 +85 +84 +79 +74 +67 +62 +56 +53 +48 +46 +41 +6 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +111 +110 +104 +98 +89 +83 +75 +71 +65 +61 +54 +19 +-13 +-38 +-61 +-78 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +93 +88 +83 +75 +70 +63 +60 +54 +51 +45 +11 +-20 +-44 +-66 +-82 +-98 +-110 +-104 +-112 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +85 +81 +72 +67 +61 +58 +52 +49 +45 +10 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +90 +85 +81 +72 +67 +61 +58 +52 +50 +44 +42 +38 +35 +32 +30 +26 +25 +22 +21 +18 +17 +15 +14 +12 +12 +10 +-20 +-46 +-67 +-85 +-99 +-113 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +109 +100 +93 +84 +80 +73 +69 +62 +58 +52 +49 +45 +42 +37 +35 +31 +30 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +120 +85 +84 +79 +75 +68 +63 +57 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +103 +61 +23 +-8 +-34 +-56 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +109 +108 +102 +96 +86 +81 +73 +69 +62 +59 +52 +49 +44 +42 +37 +35 +31 +29 +25 +24 +22 +20 +17 +16 +14 +13 +11 +-19 +-45 +-66 +-84 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +100 +94 +86 +80 +74 +69 +62 +59 +53 +51 +45 +43 +38 +36 +32 +31 +27 +-5 +-33 +-56 +-76 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +110 +101 +59 +21 +-9 +-35 +-57 +-75 +-90 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +42 +127 +127 +127 +127 +111 +109 +103 +97 +88 +83 +75 +71 +64 +61 +54 +18 +-13 +-38 +-61 +-79 +-94 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +94 +89 +84 +76 +70 +64 +60 +55 +51 +45 +11 +-19 +-44 +-66 +-83 +-98 +-110 +-104 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +61 +57 +53 +50 +44 +42 +37 +35 +31 +30 +27 +25 +22 +21 +18 +17 +15 +14 +12 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +5 +127 +127 +127 +115 +80 +79 +75 +71 +63 +59 +53 +50 +45 +43 +38 +4 +-25 +-49 +-70 +-86 +-101 +-112 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +16 +127 +127 +127 +125 +89 +88 +83 +78 +71 +66 +59 +56 +51 +47 +42 +8 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +16 +127 +127 +127 +125 +90 +89 +84 +79 +72 +67 +60 +57 +52 +48 +43 +9 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +85 +81 +72 +67 +61 +58 +52 +49 +44 +10 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +90 +89 +84 +79 +72 +66 +60 +57 +51 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +91 +90 +85 +80 +72 +67 +61 +57 +52 +49 +44 +10 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +90 +85 +81 +72 +67 +61 +58 +52 +49 +44 +10 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +91 +90 +85 +80 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +111 +109 +104 +98 +88 +83 +75 +71 +64 +61 +55 +19 +-13 +-38 +-61 +-78 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +93 +88 +83 +75 +70 +64 +60 +54 +51 +46 +43 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +13 +13 +10 +-19 +-45 +-66 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +5 +127 +127 +127 +115 +79 +79 +74 +70 +63 +59 +53 +50 +45 +43 +38 +5 +-25 +-49 +-70 +-86 +-101 +-112 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +61 +23 +-7 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +111 +109 +103 +97 +88 +82 +75 +70 +64 +60 +54 +51 +45 +43 +39 +37 +32 +30 +27 +26 +23 +21 +19 +18 +15 +14 +12 +-18 +-44 +-65 +-84 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +108 +99 +93 +85 +80 +72 +68 +61 +58 +53 +50 +45 +42 +37 +35 +31 +29 +26 +-5 +-34 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +120 +85 +84 +79 +75 +67 +63 +56 +53 +48 +45 +40 +6 +-24 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +125 +90 +89 +84 +79 +71 +67 +61 +57 +52 +48 +43 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +91 +89 +85 +80 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +97 +89 +83 +76 +72 +64 +61 +55 +52 +47 +44 +39 +37 +33 +31 +28 +-5 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +121 +86 +85 +80 +75 +68 +63 +57 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +125 +90 +89 +84 +79 +72 +67 +61 +57 +52 +49 +44 +10 +-21 +-45 +-67 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +114 +104 +97 +89 +84 +76 +72 +65 +61 +56 +52 +47 +44 +40 +38 +33 +32 +29 +-4 +-32 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +121 +86 +85 +80 +75 +68 +63 +57 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +90 +88 +83 +79 +71 +66 +60 +56 +51 +48 +43 +9 +-21 +-46 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +111 +110 +103 +97 +88 +82 +75 +71 +64 +60 +54 +18 +-13 +-38 +-61 +-78 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +22 +127 +127 +127 +127 +94 +93 +88 +83 +75 +70 +63 +59 +54 +51 +45 +43 +38 +36 +32 +30 +27 +26 +23 +22 +19 +18 +15 +15 +13 +12 +10 +-20 +-46 +-67 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +115 +109 +99 +57 +20 +-10 +-36 +-57 +-76 +-91 +-104 +-98 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +42 +127 +127 +127 +127 +109 +108 +102 +96 +88 +82 +74 +70 +63 +59 +54 +51 +45 +43 +38 +36 +32 +30 +27 +26 +22 +21 +19 +17 +15 +15 +12 +-18 +-44 +-65 +-84 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +115 +109 +99 +93 +85 +80 +72 +68 +62 +58 +53 +50 +45 +42 +37 +35 +31 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +112 +102 +96 +88 +83 +75 +71 +65 +61 +55 +52 +47 +44 +40 +37 +34 +31 +29 +-4 +-32 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +110 +101 +94 +86 +81 +73 +69 +62 +59 +53 +50 +45 +42 +38 +35 +31 +30 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +81 +74 +70 +63 +59 +54 +51 +45 +43 +38 +36 +32 +30 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +10 +127 +127 +127 +120 +85 +84 +79 +74 +67 +62 +56 +54 +48 +45 +40 +6 +-24 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +61 +22 +-8 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +112 +110 +104 +98 +89 +83 +75 +71 +65 +61 +55 +19 +-13 +-38 +-60 +-78 +-94 +-106 +-101 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +94 +89 +84 +76 +71 +64 +60 +55 +51 +46 +11 +-19 +-44 +-65 +-82 +-98 +-109 +-104 +-112 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +61 +58 +52 +49 +45 +10 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +126 +91 +90 +84 +80 +72 +67 +61 +57 +52 +49 +44 +42 +37 +35 +31 +29 +26 +25 +22 +21 +18 +17 +14 +14 +12 +11 +10 +-20 +-46 +-67 +-85 +-99 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +109 +100 +93 +85 +80 +73 +68 +62 +59 +53 +50 +45 +43 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +121 +85 +84 +80 +75 +67 +63 +57 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +46 +127 +127 +127 +127 +112 +110 +104 +98 +88 +83 +75 +71 +63 +60 +54 +51 +46 +43 +38 +36 +32 +30 +27 +26 +22 +21 +18 +17 +14 +14 +12 +-18 +-44 +-65 +-84 +-98 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +114 +107 +98 +92 +83 +79 +72 +67 +61 +57 +52 +49 +44 +42 +37 +35 +32 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +112 +102 +60 +22 +-8 +-35 +-56 +-75 +-90 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +42 +127 +127 +127 +127 +110 +109 +103 +97 +87 +82 +74 +69 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +21 +127 +127 +127 +127 +95 +93 +88 +84 +76 +70 +63 +60 +55 +51 +46 +11 +-19 +-44 +-65 +-82 +-98 +-109 +-104 +-112 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +62 +58 +53 +49 +45 +42 +37 +35 +32 +30 +27 +25 +22 +21 +18 +17 +15 +14 +12 +11 +10 +-20 +-46 +-67 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +4 +127 +127 +127 +115 +80 +79 +74 +70 +63 +59 +52 +49 +45 +43 +38 +4 +-26 +-49 +-70 +-86 +-101 +-112 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +16 +127 +127 +127 +125 +90 +88 +84 +79 +71 +67 +60 +57 +51 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +91 +90 +85 +80 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +125 +90 +89 +84 +79 +72 +67 +60 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +127 +91 +90 +85 +80 +72 +68 +61 +57 +52 +49 +45 +10 +-20 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +90 +90 +84 +80 +71 +66 +61 +57 +51 +49 +43 +9 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +90 +89 +84 +79 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +85 +81 +73 +68 +62 +58 +52 +50 +45 +10 +-20 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +111 +109 +103 +97 +88 +83 +75 +71 +64 +60 +54 +18 +-14 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +22 +127 +127 +127 +127 +94 +93 +88 +83 +75 +70 +63 +60 +54 +51 +45 +43 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +13 +12 +10 +-20 +-46 +-66 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +3 +127 +127 +127 +115 +80 +79 +74 +70 +63 +59 +53 +51 +45 +43 +38 +4 +-25 +-49 +-70 +-86 +-101 +-112 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +112 +110 +104 +99 +89 +83 +75 +71 +65 +61 +55 +51 +47 +44 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +13 +-17 +-44 +-65 +-83 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +115 +108 +99 +93 +84 +79 +72 +68 +62 +58 +52 +50 +44 +42 +37 +35 +31 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +120 +85 +84 +80 +75 +67 +63 +56 +53 +48 +46 +40 +6 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +125 +90 +89 +84 +79 +71 +67 +60 +57 +51 +48 +43 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +91 +90 +84 +80 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +97 +89 +83 +76 +71 +65 +61 +55 +51 +47 +44 +40 +37 +33 +31 +27 +-5 +-33 +-56 +-76 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +121 +86 +85 +80 +75 +68 +63 +56 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +126 +90 +89 +84 +79 +71 +67 +60 +57 +51 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +97 +89 +84 +76 +72 +65 +61 +56 +52 +47 +44 +39 +37 +34 +32 +28 +-4 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +121 +86 +85 +81 +76 +68 +63 +58 +55 +50 +47 +42 +8 +-22 +-46 +-68 +-84 +-99 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +126 +90 +89 +84 +79 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +103 +61 +22 +-8 +-34 +-56 +-75 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +111 +110 +104 +98 +89 +83 +75 +71 +64 +60 +54 +19 +-13 +-38 +-61 +-78 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +93 +88 +83 +75 +70 +63 +60 +54 +51 +46 +43 +38 +36 +32 +31 +27 +26 +23 +21 +19 +18 +15 +15 +13 +12 +10 +-20 +-46 +-67 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +115 +108 +99 +57 +19 +-10 +-37 +-58 +-76 +-91 +-104 +-98 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +41 +127 +127 +127 +127 +110 +109 +102 +97 +88 +82 +75 +70 +63 +60 +54 +51 +45 +43 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +15 +15 +13 +-18 +-44 +-65 +-83 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +115 +109 +99 +93 +84 +79 +72 +68 +61 +58 +52 +49 +45 +42 +37 +35 +31 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +81 +74 +69 +63 +59 +54 +51 +45 +43 +39 +37 +33 +31 +28 +-5 +-33 +-55 +-76 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +96 +88 +83 +75 +71 +64 +60 +54 +51 +45 +43 +39 +36 +32 +31 +27 +-5 +-33 +-56 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +110 +100 +94 +86 +81 +74 +69 +62 +59 +53 +50 +45 +43 +38 +35 +32 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +121 +85 +85 +79 +75 +68 +63 +57 +54 +48 +45 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +61 +22 +-8 +-34 +-56 +-75 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +111 +109 +103 +97 +88 +82 +75 +71 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-94 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +95 +94 +88 +83 +75 +70 +63 +60 +54 +52 +46 +11 +-19 +-43 +-65 +-82 +-98 +-110 +-104 +-112 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +62 +58 +53 +50 +45 +10 +-20 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +90 +85 +81 +72 +67 +62 +58 +52 +49 +45 +42 +37 +35 +31 +30 +26 +25 +22 +21 +18 +17 +15 +14 +12 +12 +10 +-20 +-46 +-67 +-85 +-99 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +115 +109 +99 +93 +85 +80 +72 +67 +62 +58 +52 +50 +45 +42 +38 +35 +31 +30 +27 +-5 +-34 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +121 +86 +85 +80 +76 +68 +63 +57 +54 +49 +47 +42 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +112 +110 +104 +98 +89 +84 +76 +71 +65 +61 +55 +52 +47 +45 +40 +37 +34 +32 +29 +27 +23 +23 +20 +19 +16 +15 +13 +-17 +-44 +-65 +-83 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +114 +107 +98 +91 +83 +78 +71 +66 +59 +56 +51 +48 +43 +40 +35 +34 +30 +28 +25 +-7 +-35 +-57 +-77 +-93 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +112 +102 +59 +22 +-9 +-35 +-56 +-75 +-90 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +112 +110 +104 +99 +89 +83 +76 +71 +65 +61 +55 +19 +-13 +-38 +-61 +-78 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +94 +93 +87 +83 +75 +69 +63 +59 +54 +51 +45 +11 +-20 +-44 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +86 +81 +72 +68 +62 +58 +53 +50 +45 +42 +38 +36 +32 +30 +27 +25 +22 +21 +19 +18 +15 +14 +12 +12 +9 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +3 +127 +127 +127 +115 +80 +79 +74 +70 +62 +59 +53 +50 +45 +42 +38 +4 +-26 +-49 +-70 +-86 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +15 +127 +127 +127 +125 +89 +88 +83 +78 +71 +66 +60 +57 +51 +48 +43 +9 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +85 +81 +73 +68 +61 +58 +53 +50 +45 +10 +-20 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +86 +80 +72 +68 +61 +58 +52 +49 +44 +10 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +126 +90 +89 +84 +79 +71 +67 +60 +56 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +127 +92 +90 +85 +80 +72 +68 +61 +58 +52 +49 +45 +10 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +91 +90 +85 +80 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +126 +90 +89 +84 +79 +72 +67 +61 +57 +52 +49 +44 +10 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +112 +110 +104 +99 +88 +83 +75 +71 +65 +61 +54 +18 +-13 +-39 +-61 +-78 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +95 +93 +88 +83 +75 +70 +63 +60 +54 +51 +45 +43 +39 +36 +32 +31 +27 +25 +23 +22 +19 +18 +15 +15 +12 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +5 +127 +127 +127 +115 +79 +79 +74 +70 +62 +59 +53 +50 +45 +43 +38 +4 +-25 +-49 +-70 +-86 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +103 +61 +22 +-8 +-34 +-56 +-75 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +112 +110 +104 +99 +89 +83 +75 +72 +65 +61 +55 +52 +47 +44 +40 +37 +33 +32 +28 +27 +24 +23 +20 +19 +16 +15 +13 +-17 +-44 +-65 +-84 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +109 +99 +93 +85 +79 +72 +68 +62 +58 +53 +50 +45 +42 +38 +35 +31 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +120 +85 +84 +79 +75 +67 +62 +57 +54 +48 +45 +40 +6 +-24 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +90 +89 +84 +79 +72 +67 +60 +56 +52 +49 +43 +9 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +127 +91 +89 +85 +80 +72 +67 +61 +57 +52 +49 +43 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +97 +89 +84 +77 +72 +65 +61 +55 +52 +47 +44 +40 +37 +33 +31 +28 +-4 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +121 +86 +85 +80 +75 +68 +63 +56 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +126 +90 +89 +84 +79 +71 +67 +60 +56 +51 +48 +43 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +114 +104 +98 +89 +83 +77 +72 +65 +61 +56 +52 +47 +45 +40 +37 +33 +32 +28 +-4 +-32 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +121 +86 +85 +80 +75 +68 +63 +58 +54 +49 +46 +42 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +126 +91 +90 +85 +79 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +111 +109 +103 +97 +89 +83 +75 +70 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +94 +93 +88 +83 +75 +70 +63 +59 +54 +51 +45 +43 +38 +36 +32 +31 +27 +26 +23 +22 +18 +17 +15 +15 +12 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +115 +108 +99 +57 +19 +-11 +-37 +-58 +-76 +-91 +-104 +-98 +-108 +-128 +-128 +-128 +-128 +-128 +-128 +42 +127 +127 +127 +127 +109 +108 +102 +96 +87 +81 +74 +70 +63 +60 +54 +51 +46 +43 +38 +37 +33 +30 +28 +26 +23 +22 +19 +18 +15 +15 +13 +-18 +-44 +-65 +-84 +-98 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +116 +109 +100 +93 +85 +80 +73 +68 +62 +59 +53 +50 +45 +42 +38 +35 +32 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +81 +74 +70 +63 +60 +54 +51 +45 +43 +38 +36 +32 +31 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +112 +103 +96 +88 +83 +76 +71 +65 +61 +55 +52 +47 +44 +40 +38 +34 +32 +29 +-4 +-32 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +81 +74 +69 +63 +59 +53 +50 +44 +42 +38 +35 +31 +30 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +120 +85 +84 +79 +74 +67 +62 +56 +53 +48 +46 +40 +6 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +61 +23 +-8 +-34 +-56 +-74 +-89 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +111 +109 +103 +97 +88 +82 +75 +70 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +94 +93 +88 +83 +75 +70 +63 +60 +53 +51 +45 +11 +-20 +-44 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +61 +58 +53 +50 +45 +10 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +21 +127 +127 +127 +127 +92 +90 +86 +81 +73 +68 +61 +58 +53 +50 +45 +42 +38 +35 +31 +30 +26 +25 +22 +20 +18 +18 +15 +14 +12 +11 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +115 +108 +99 +93 +85 +79 +72 +68 +62 +58 +52 +50 +45 +42 +38 +35 +31 +30 +27 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +121 +86 +84 +80 +75 +68 +63 +57 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +115 +104 +62 +23 +-7 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +112 +110 +104 +98 +89 +83 +75 +71 +64 +61 +54 +51 +46 +44 +39 +37 +33 +31 +27 +25 +23 +22 +19 +18 +16 +15 +13 +-17 +-44 +-65 +-84 +-98 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +116 +109 +100 +93 +85 +80 +73 +68 +61 +58 +52 +49 +44 +42 +38 +35 +31 +29 +26 +-6 +-34 +-57 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +116 +109 +99 +57 +19 +-10 +-37 +-58 +-76 +-91 +-104 +-98 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +111 +110 +104 +98 +88 +83 +75 +71 +65 +61 +55 +19 +-13 +-38 +-61 +-79 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +96 +94 +90 +85 +77 +71 +64 +61 +55 +52 +47 +12 +-19 +-43 +-65 +-82 +-98 +-109 +-104 +-112 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +85 +81 +73 +68 +61 +57 +52 +49 +44 +42 +37 +35 +31 +29 +26 +25 +22 +20 +18 +17 +15 +14 +12 +11 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +5 +127 +127 +127 +115 +80 +79 +75 +70 +63 +59 +53 +50 +46 +43 +38 +4 +-25 +-49 +-70 +-86 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +16 +127 +127 +127 +125 +89 +89 +84 +79 +70 +65 +60 +56 +51 +48 +43 +8 +-22 +-46 +-67 +-84 +-99 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +91 +90 +85 +80 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +85 +81 +72 +68 +61 +59 +53 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +62 +58 +53 +50 +45 +10 +-20 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +90 +89 +84 +79 +71 +66 +60 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +21 +127 +127 +127 +127 +91 +90 +85 +80 +72 +68 +61 +58 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +126 +91 +90 +85 +80 +72 +67 +61 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +112 +110 +104 +98 +89 +83 +76 +71 +64 +60 +55 +19 +-13 +-38 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +93 +88 +84 +75 +70 +64 +60 +54 +51 +46 +43 +39 +37 +33 +31 +27 +26 +22 +21 +19 +18 +15 +15 +13 +12 +10 +-20 +-46 +-67 +-85 +-99 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +4 +127 +127 +127 +115 +79 +78 +74 +69 +62 +58 +52 +49 +45 +42 +38 +4 +-26 +-49 +-70 +-86 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +61 +22 +-8 +-35 +-56 +-75 +-90 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +112 +110 +104 +98 +89 +83 +76 +72 +65 +61 +55 +52 +47 +44 +40 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +13 +-18 +-44 +-65 +-84 +-98 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +109 +100 +93 +86 +81 +73 +69 +62 +59 +53 +50 +45 +42 +37 +35 +32 +30 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +121 +85 +84 +79 +75 +67 +62 +56 +53 +48 +45 +40 +6 +-24 +-47 +-69 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +89 +88 +83 +79 +71 +66 +60 +56 +51 +48 +43 +8 +-22 +-46 +-67 +-84 +-99 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +91 +90 +85 +80 +72 +67 +61 +58 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +114 +104 +97 +89 +83 +76 +72 +65 +61 +55 +52 +46 +43 +39 +37 +33 +31 +28 +-5 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +121 +86 +86 +80 +75 +68 +63 +57 +53 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +125 +90 +89 +84 +79 +72 +67 +60 +57 +52 +49 +43 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +97 +89 +83 +76 +72 +65 +61 +55 +52 +47 +44 +40 +37 +33 +31 +28 +-4 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +14 +127 +127 +127 +121 +86 +85 +80 +76 +68 +63 +57 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +90 +89 +85 +79 +72 +67 +61 +57 +52 +48 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +115 +105 +62 +24 +-7 +-33 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +47 +127 +127 +127 +127 +112 +110 +104 +97 +88 +82 +75 +70 +64 +60 +54 +18 +-14 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +93 +88 +83 +75 +70 +63 +59 +54 +51 +46 +43 +38 +36 +32 +31 +27 +26 +23 +21 +19 +18 +15 +14 +12 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +115 +108 +99 +57 +19 +-11 +-37 +-58 +-77 +-91 +-104 +-98 +-108 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +109 +108 +102 +96 +87 +81 +74 +69 +63 +59 +53 +50 +45 +43 +38 +36 +32 +30 +27 +25 +22 +21 +18 +18 +15 +14 +12 +-18 +-44 +-65 +-84 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +100 +93 +85 +80 +73 +69 +63 +59 +53 +50 +45 +42 +37 +35 +32 +30 +27 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +87 +81 +74 +69 +63 +59 +54 +50 +45 +43 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +81 +74 +69 +63 +59 +53 +50 +45 +43 +38 +36 +32 +31 +28 +-5 +-33 +-55 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +97 +89 +83 +76 +72 +65 +61 +55 +52 +47 +44 +39 +37 +33 +31 +28 +-5 +-33 +-55 +-76 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +120 +84 +84 +78 +73 +65 +61 +56 +53 +47 +45 +40 +6 +-24 +-48 +-69 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +61 +22 +-8 +-34 +-56 +-75 +-89 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +111 +109 +104 +97 +88 +82 +75 +71 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-95 +-107 +-102 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +94 +93 +88 +83 +74 +69 +63 +59 +54 +50 +45 +10 +-20 +-44 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +91 +90 +86 +81 +72 +67 +61 +58 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +90 +85 +81 +73 +68 +61 +58 +52 +49 +44 +42 +37 +35 +31 +29 +26 +25 +22 +22 +18 +17 +15 +14 +12 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +109 +100 +93 +85 +79 +72 +68 +62 +58 +53 +50 +45 +42 +38 +35 +32 +30 +26 +-6 +-34 +-57 +-77 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +15 +127 +127 +127 +120 +85 +84 +79 +75 +67 +62 +56 +54 +48 +46 +40 +6 +-24 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +46 +127 +127 +127 +127 +112 +111 +105 +99 +90 +84 +76 +72 +65 +61 +55 +52 +47 +45 +40 +38 +34 +32 +28 +27 +24 +23 +19 +18 +16 +15 +13 +-17 +-44 +-65 +-83 +-98 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +109 +100 +93 +85 +80 +73 +68 +63 +59 +53 +50 +45 +43 +38 +36 +32 +31 +27 +-5 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +100 +58 +20 +-10 +-36 +-57 +-76 +-91 +-104 +-98 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +41 +127 +127 +127 +127 +108 +106 +100 +95 +86 +80 +73 +68 +61 +58 +52 +16 +-15 +-40 +-62 +-80 +-95 +-108 +-103 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +95 +93 +88 +84 +76 +71 +64 +61 +55 +52 +47 +12 +-19 +-43 +-65 +-82 +-98 +-110 +-104 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +22 +127 +127 +127 +127 +93 +92 +87 +82 +74 +69 +63 +59 +54 +51 +45 +42 +38 +36 +32 +31 +27 +25 +22 +21 +18 +17 +15 +14 +12 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +4 +127 +127 +127 +114 +79 +78 +73 +69 +61 +57 +52 +49 +44 +42 +37 +4 +-26 +-49 +-70 +-87 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +125 +89 +88 +83 +79 +71 +65 +59 +56 +51 +48 +43 +9 +-22 +-46 +-67 +-84 +-99 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +91 +90 +85 +80 +72 +67 +60 +58 +52 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +91 +90 +85 +80 +72 +67 +61 +58 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +62 +58 +53 +50 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +22 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +62 +58 +53 +49 +44 +10 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +90 +89 +85 +80 +72 +67 +60 +57 +51 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +91 +90 +85 +81 +72 +67 +61 +58 +52 +49 +45 +10 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +61 +23 +-8 +-34 +-56 +-75 +-89 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +46 +127 +127 +127 +127 +111 +110 +104 +97 +88 +83 +75 +71 +64 +61 +55 +19 +-13 +-38 +-61 +-78 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +95 +93 +89 +84 +75 +70 +63 +60 +54 +51 +46 +44 +39 +37 +32 +30 +28 +26 +23 +22 +19 +18 +16 +15 +13 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +6 +127 +127 +127 +115 +79 +79 +74 +69 +62 +58 +52 +50 +44 +42 +38 +4 +-26 +-49 +-70 +-87 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +113 +103 +61 +22 +-8 +-35 +-56 +-75 +-90 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +111 +110 +103 +97 +88 +83 +75 +71 +64 +61 +54 +51 +46 +44 +39 +37 +33 +31 +28 +26 +24 +22 +19 +18 +15 +15 +13 +-17 +-44 +-65 +-84 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +110 +100 +94 +86 +81 +73 +69 +62 +59 +53 +50 +45 +42 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-100 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +121 +86 +85 +80 +75 +68 +63 +57 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +90 +89 +84 +79 +70 +65 +60 +56 +51 +48 +43 +9 +-21 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +90 +89 +84 +79 +72 +67 +60 +56 +51 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +97 +89 +84 +76 +71 +65 +61 +55 +52 +47 +44 +40 +37 +33 +31 +28 +-5 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +121 +85 +84 +79 +75 +68 +63 +57 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +90 +89 +84 +79 +71 +66 +61 +57 +51 +49 +44 +9 +-21 +-45 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +97 +88 +84 +76 +72 +65 +61 +55 +52 +47 +44 +40 +37 +33 +31 +28 +-5 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +121 +85 +85 +80 +75 +68 +63 +57 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +16 +127 +127 +127 +126 +90 +89 +84 +80 +72 +67 +61 +57 +52 +49 +44 +10 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +112 +111 +105 +99 +89 +84 +76 +71 +65 +61 +56 +19 +-13 +-38 +-60 +-78 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +24 +127 +127 +127 +127 +95 +94 +88 +83 +75 +70 +63 +59 +54 +51 +45 +43 +39 +37 +33 +30 +27 +26 +22 +22 +18 +17 +15 +14 +12 +12 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +115 +108 +99 +57 +19 +-11 +-37 +-58 +-76 +-91 +-104 +-98 +-108 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +109 +107 +102 +96 +87 +82 +74 +69 +63 +59 +54 +51 +45 +43 +38 +36 +32 +31 +27 +26 +22 +21 +18 +17 +15 +14 +12 +-18 +-44 +-65 +-84 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +115 +109 +99 +93 +85 +80 +72 +69 +62 +58 +52 +49 +45 +42 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +87 +81 +74 +70 +63 +59 +53 +50 +45 +43 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +82 +74 +70 +63 +60 +54 +51 +45 +42 +38 +36 +33 +31 +27 +-5 +-33 +-55 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +111 +102 +96 +87 +82 +75 +71 +64 +61 +55 +52 +47 +44 +39 +38 +34 +32 +29 +-4 +-32 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +14 +127 +127 +127 +123 +86 +86 +81 +77 +69 +64 +58 +55 +49 +47 +42 +7 +-23 +-46 +-68 +-85 +-99 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +112 +102 +60 +22 +-8 +-35 +-56 +-75 +-90 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +111 +109 +104 +97 +88 +83 +75 +71 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +94 +93 +88 +83 +75 +70 +63 +60 +54 +51 +46 +11 +-19 +-44 +-65 +-83 +-98 +-110 +-104 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +126 +91 +90 +85 +80 +72 +67 +61 +57 +51 +48 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +91 +90 +85 +80 +72 +67 +61 +57 +51 +49 +44 +41 +37 +35 +31 +29 +25 +24 +22 +21 +18 +17 +14 +14 +12 +11 +10 +-20 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +109 +99 +93 +85 +80 +72 +69 +62 +59 +53 +50 +45 +42 +37 +35 +32 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +120 +86 +84 +79 +75 +67 +63 +57 +53 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +61 +23 +-7 +-34 +-56 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +45 +127 +127 +127 +127 +112 +110 +104 +99 +90 +84 +75 +71 +64 +61 +55 +52 +47 +45 +40 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +13 +-17 +-44 +-65 +-83 +-98 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +109 +100 +93 +85 +80 +72 +69 +62 +58 +52 +49 +44 +42 +38 +35 +32 +30 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-101 +-111 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +102 +60 +21 +-9 +-35 +-56 +-75 +-90 +-103 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +109 +108 +102 +96 +87 +82 +74 +69 +62 +58 +53 +17 +-14 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +86 +81 +72 +67 +60 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +61 +58 +53 +50 +45 +43 +38 +36 +32 +30 +27 +26 +23 +21 +18 +18 +16 +15 +13 +13 +10 +-19 +-46 +-66 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +5 +127 +127 +127 +115 +80 +79 +75 +70 +63 +59 +53 +50 +45 +43 +38 +4 +-25 +-49 +-70 +-86 +-101 +-112 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +16 +127 +127 +127 +124 +88 +87 +82 +78 +70 +65 +59 +56 +51 +47 +43 +8 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +126 +90 +89 +84 +80 +72 +67 +61 +57 +52 +49 +44 +10 +-21 +-45 +-66 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +17 +127 +127 +127 +127 +92 +90 +85 +80 +72 +68 +62 +58 +52 +49 +45 +10 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +91 +90 +85 +80 +72 +67 +61 +58 +52 +49 +45 +10 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +20 +127 +127 +127 +127 +92 +91 +86 +81 +72 +68 +62 +57 +52 +50 +45 +10 +-20 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +62 +58 +52 +49 +44 +10 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +90 +89 +84 +79 +71 +67 +60 +57 +51 +49 +43 +9 +-22 +-46 +-67 +-84 +-99 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +111 +110 +104 +97 +89 +83 +75 +71 +64 +60 +54 +18 +-14 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +22 +127 +127 +127 +127 +94 +93 +88 +83 +75 +70 +63 +60 +54 +51 +46 +44 +39 +37 +33 +31 +28 +26 +23 +22 +19 +18 +16 +15 +13 +12 +10 +-19 +-45 +-66 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +5 +127 +127 +127 +115 +79 +79 +74 +69 +62 +58 +53 +50 +45 +43 +38 +4 +-25 +-49 +-70 +-86 +-101 +-97 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +112 +103 +60 +22 +-8 +-35 +-56 +-75 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +111 +109 +103 +97 +88 +83 +75 +70 +63 +60 +54 +51 +46 +43 +39 +37 +33 +31 +28 +26 +22 +21 +19 +18 +15 +15 +13 +-17 +-44 +-65 +-83 +-98 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +116 +110 +100 +93 +86 +81 +73 +68 +62 +59 +53 +50 +45 +43 +38 +35 +31 +30 +27 +-5 +-33 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +14 +127 +127 +127 +120 +85 +85 +80 +75 +68 +63 +57 +54 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +126 +90 +89 +84 +79 +72 +67 +61 +57 +52 +49 +43 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +90 +90 +85 +80 +71 +66 +60 +57 +52 +49 +44 +9 +-21 +-45 +-67 +-83 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +97 +88 +83 +76 +71 +65 +61 +55 +52 +47 +43 +40 +37 +33 +31 +28 +-4 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +13 +127 +127 +127 +120 +85 +85 +80 +75 +67 +63 +57 +54 +48 +46 +40 +6 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +90 +89 +83 +79 +71 +67 +60 +57 +51 +48 +44 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +104 +97 +89 +83 +76 +72 +65 +61 +54 +52 +47 +44 +40 +37 +33 +31 +28 +-5 +-33 +-55 +-75 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +121 +85 +85 +80 +75 +67 +63 +57 +53 +48 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +125 +90 +89 +84 +79 +71 +67 +60 +56 +51 +48 +44 +9 +-21 +-45 +-67 +-84 +-99 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +122 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +112 +110 +104 +98 +89 +83 +76 +71 +65 +61 +55 +19 +-13 +-38 +-61 +-78 +-94 +-106 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +27 +127 +127 +127 +127 +95 +94 +89 +84 +76 +71 +64 +61 +54 +52 +47 +44 +40 +37 +33 +31 +27 +26 +23 +22 +19 +18 +16 +15 +13 +12 +10 +-20 +-46 +-67 +-85 +-99 +-112 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +115 +108 +98 +56 +19 +-11 +-37 +-58 +-77 +-91 +-104 +-98 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +41 +127 +127 +127 +127 +109 +108 +102 +96 +87 +81 +74 +69 +63 +59 +53 +50 +45 +43 +38 +37 +32 +30 +27 +25 +22 +21 +19 +18 +15 +14 +12 +-18 +-44 +-65 +-84 +-98 +-112 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +116 +108 +98 +93 +85 +80 +72 +68 +61 +58 +52 +49 +44 +41 +37 +35 +31 +29 +26 +-6 +-34 +-56 +-76 +-92 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +82 +74 +69 +63 +60 +54 +50 +46 +43 +39 +36 +32 +31 +28 +-5 +-33 +-55 +-76 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +81 +74 +69 +63 +59 +53 +50 +45 +43 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +101 +95 +86 +81 +74 +69 +63 +59 +53 +50 +45 +43 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +12 +127 +127 +127 +121 +86 +86 +81 +77 +69 +65 +58 +56 +50 +47 +42 +8 +-22 +-46 +-68 +-84 +-99 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +114 +104 +61 +23 +-7 +-34 +-55 +-74 +-89 +-102 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +44 +127 +127 +127 +127 +110 +109 +102 +97 +87 +81 +74 +70 +64 +60 +54 +18 +-13 +-39 +-61 +-79 +-95 +-107 +-102 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +23 +127 +127 +127 +127 +94 +93 +88 +83 +75 +70 +63 +60 +54 +51 +45 +11 +-20 +-44 +-66 +-83 +-98 +-110 +-104 +-112 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +18 +127 +127 +127 +127 +92 +91 +86 +81 +73 +68 +61 +58 +52 +49 +44 +10 +-21 +-45 +-66 +-83 +-98 +-110 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +19 +127 +127 +127 +126 +90 +89 +85 +79 +71 +67 +60 +57 +51 +49 +43 +41 +36 +35 +31 +29 +25 +24 +21 +20 +18 +17 +15 +14 +12 +11 +9 +-21 +-46 +-67 +-85 +-100 +-113 +-107 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +99 +93 +85 +80 +72 +68 +62 +59 +53 +50 +45 +42 +38 +35 +32 +30 +27 +-5 +-33 +-56 +-76 +-91 +-106 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +11 +127 +127 +127 +120 +85 +85 +80 +75 +68 +63 +57 +54 +49 +46 +41 +7 +-23 +-47 +-68 +-85 +-100 +-111 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +121 +113 +103 +61 +23 +-7 +-34 +-56 +-74 +-89 +-103 +-97 +-106 +-128 +-128 +-128 +-128 +-128 +-128 +43 +127 +127 +127 +127 +111 +110 +104 +98 +89 +83 +75 +71 +64 +61 +55 +51 +46 +44 +39 +37 +33 +31 +27 +26 +23 +22 +19 +18 +16 +15 +13 +-18 +-44 +-65 +-83 +-98 +-111 +-105 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +100 +94 +86 +81 +74 +69 +63 +59 +53 +50 +45 +43 +38 +36 +32 +30 +27 +-5 +-33 +-56 +-76 +-91 +-105 +-100 +-110 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 +-128 diff --git a/traces/EM4102-Fob.pm3 b/traces/EM4102-Fob.pm3 new file mode 100644 index 00000000..1fb16070 --- /dev/null +++ b/traces/EM4102-Fob.pm3 @@ -0,0 +1,40000 @@ +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +71 +50 +27 +7 +-8 +-16 +-21 +-20 +-16 +-11 +-8 +-3 +-1 +-1 +0 +0 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-16 +-14 +-14 +-13 +-13 +-12 +-14 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-5 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-13 +-13 +-14 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-15 +-15 +-15 +-14 +-15 +-14 +-13 +-12 +-13 +-12 +20 +73 +89 +89 +71 +50 +27 +7 +-8 +-17 +-20 +-19 +-16 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-23 +-16 +-14 +-14 +-16 +-17 +-19 +-20 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +71 +50 +27 +8 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-19 +-19 +-19 +-17 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-20 +-16 +-11 +-8 +-3 +-2 +-1 +-1 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-21 +-18 +-18 +-16 +-16 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +20 +73 +89 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +89 +71 +50 +27 +7 +-8 +-16 +-20 +-19 +-16 +-12 +-9 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-13 +-15 +-16 +-18 +-20 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +74 +90 +88 +71 +50 +27 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-16 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-20 +-20 +-17 +-12 +-8 +-4 +-2 +0 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-66 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-6 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-79 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-19 +-18 +-17 +-17 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +89 +72 +51 +27 +9 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-3 +-4 +-5 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +89 +71 +50 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +-1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-11 +-9 +-10 +-10 +-11 +-10 +-10 +-11 +-35 +-73 +-98 +-98 +-85 +-67 +-49 +-34 +-23 +-17 +-15 +-14 +-17 +-17 +-20 +-21 +-21 +-20 +-21 +-19 +-19 +-17 +-17 +-15 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +18 +72 +89 +88 +71 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-13 +-8 +-3 +-2 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-15 +-13 +-13 +-15 +-16 +-19 +-20 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-14 +-15 +-14 +-13 +-14 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-19 +-17 +-12 +-7 +-4 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-97 +-83 +-64 +-47 +-31 +-22 +-16 +-14 +-13 +-16 +-16 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-11 +-10 +22 +75 +91 +90 +74 +52 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-3 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-82 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-18 +-20 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +20 +74 +89 +88 +71 +50 +27 +8 +-7 +-17 +-20 +-19 +-18 +-12 +-8 +-4 +-1 +1 +1 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-8 +-7 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-35 +-72 +-99 +-98 +-86 +-67 +-49 +-33 +-24 +-17 +-14 +-14 +-16 +-18 +-20 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +21 +76 +92 +90 +74 +53 +28 +9 +-7 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-5 +-6 +-6 +-6 +-6 +-32 +-70 +-96 +-97 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +89 +89 +72 +50 +27 +7 +-9 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +26 +8 +-7 +-17 +-20 +-19 +-16 +-12 +-7 +-3 +-2 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-6 +-7 +-7 +-7 +-8 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-72 +-99 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-14 +-17 +-18 +-19 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +-1 +-1 +-1 +-4 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-97 +-84 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +22 +76 +92 +91 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-1 +-3 +-3 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-9 +-10 +-9 +-9 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-36 +-74 +-98 +-98 +-85 +-67 +-49 +-34 +-23 +-17 +-16 +-15 +-16 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-19 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +50 +27 +7 +-7 +-16 +-20 +-19 +-17 +-12 +-8 +-5 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-97 +-83 +-64 +-47 +-31 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-16 +-17 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +21 +75 +92 +91 +74 +53 +29 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-19 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +74 +90 +88 +72 +50 +26 +7 +-7 +-16 +-20 +-20 +-17 +-13 +-8 +-3 +-2 +1 +0 +-1 +-2 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-36 +-73 +-99 +-99 +-85 +-66 +-49 +-34 +-23 +-17 +-16 +-15 +-17 +-18 +-20 +-20 +-22 +-20 +-20 +-19 +-19 +-17 +-17 +-16 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-9 +-10 +-10 +22 +75 +91 +91 +73 +53 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-2 +-2 +-3 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-9 +-8 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-11 +-10 +-36 +-73 +-99 +-99 +-86 +-67 +-49 +-33 +-23 +-16 +-15 +-14 +-16 +-18 +-20 +-20 +-22 +-20 +-20 +-18 +-18 +-17 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +19 +72 +89 +88 +71 +51 +27 +7 +-8 +-17 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-23 +-15 +-13 +-14 +-15 +-16 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-16 +-15 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +87 +71 +51 +27 +8 +-7 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-2 +1 +0 +-1 +-2 +-2 +-4 +-5 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-20 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +73 +89 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-20 +-17 +-12 +-9 +-4 +-1 +0 +0 +0 +-2 +-3 +-4 +-5 +-6 +-5 +-6 +-6 +-6 +-6 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-14 +-13 +-14 +-14 +-14 +-13 +-14 +-12 +19 +73 +90 +89 +72 +51 +27 +7 +-7 +-16 +-20 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +0 +-2 +-2 +-3 +-5 +-5 +-5 +-7 +-6 +-6 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-84 +-65 +-47 +-33 +-22 +-15 +-14 +-14 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +20 +73 +90 +89 +71 +51 +27 +7 +-8 +-17 +-20 +-19 +-17 +-11 +-8 +-4 +-2 +-1 +-1 +-1 +-1 +-3 +-4 +-4 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-14 +-14 +-13 +-13 +-13 +-13 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +22 +75 +92 +91 +73 +52 +28 +9 +-6 +-14 +-19 +-18 +-16 +-11 +-8 +-3 +-1 +0 +1 +1 +-1 +-1 +-3 +-4 +-6 +-5 +-6 +-6 +-6 +-5 +-7 +-7 +-7 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-98 +-84 +-66 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-17 +-19 +-21 +-21 +-21 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-14 +-13 +-12 +-13 +-12 +-13 +-12 +-13 +-12 +-12 +-11 +-11 +-11 +-12 +-12 +-12 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +22 +75 +92 +91 +74 +53 +29 +9 +-7 +-15 +-20 +-19 +-16 +-10 +-7 +-2 +-1 +0 +0 +1 +-1 +-2 +-3 +-3 +-6 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-9 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-33 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-16 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +19 +72 +89 +89 +71 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +-1 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-6 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-10 +-10 +-10 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +22 +76 +91 +90 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-2 +-4 +-5 +-6 +-5 +-6 +-5 +-6 +-6 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-16 +-18 +-19 +-19 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-14 +-13 +19 +73 +89 +89 +73 +50 +27 +8 +-8 +-17 +-21 +-20 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-3 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-8 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-11 +-36 +-73 +-98 +-98 +-85 +-66 +-49 +-34 +-23 +-17 +-15 +-14 +-16 +-17 +-19 +-20 +-21 +-21 +-21 +-19 +-19 +-17 +-16 +-15 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +50 +27 +7 +-9 +-17 +-20 +-20 +-16 +-12 +-9 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-13 +-16 +-17 +-18 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-11 +-7 +-4 +-2 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-8 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-20 +-20 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-16 +-14 +-14 +-14 +-13 +-13 +-14 +-13 +19 +74 +90 +89 +73 +51 +27 +8 +-8 +-17 +-20 +-20 +-17 +-12 +-7 +-4 +-1 +0 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-8 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-18 +-20 +-20 +-19 +-20 +-19 +-17 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +1 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +74 +89 +88 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +1 +0 +0 +-1 +-3 +-4 +-5 +-6 +-6 +-6 +-5 +-7 +-6 +-7 +-7 +-33 +-71 +-97 +-97 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-19 +-20 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-14 +-14 +-14 +-14 +-14 +-15 +-13 +-13 +-13 +19 +74 +89 +88 +71 +51 +26 +7 +-8 +-17 +-20 +-19 +-16 +-11 +-7 +-3 +-2 +1 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-31 +-22 +-15 +-14 +-14 +-15 +-17 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-13 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +26 +7 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-4 +-2 +0 +-1 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-21 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-21 +-19 +-19 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +18 +73 +89 +88 +72 +51 +26 +8 +-8 +-16 +-20 +-19 +-16 +-12 +-7 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-12 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +21 +76 +92 +90 +74 +52 +28 +8 +-7 +-15 +-20 +-18 +-15 +-11 +-6 +-3 +-2 +0 +0 +1 +-1 +-1 +-3 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-3 +-1 +1 +-1 +-1 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-21 +-19 +-19 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +18 +73 +90 +88 +72 +51 +27 +8 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-1 +1 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-7 +-17 +-21 +-19 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-8 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-19 +-21 +-19 +-19 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-12 +20 +74 +90 +88 +71 +50 +26 +7 +-7 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-2 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-7 +-7 +-6 +-7 +-6 +-7 +-6 +-8 +-7 +-7 +-8 +-8 +-7 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-36 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-24 +-17 +-15 +-14 +-16 +-18 +-20 +-21 +-21 +-21 +-20 +-19 +-19 +-17 +-16 +-15 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +21 +76 +92 +91 +74 +53 +28 +9 +-7 +-16 +-20 +-19 +-15 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-6 +-6 +-7 +-7 +-6 +-32 +-70 +-96 +-97 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-14 +-13 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-20 +-17 +-11 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-5 +-7 +-6 +-7 +-6 +-8 +-7 +-7 +-7 +-7 +-7 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-99 +-85 +-66 +-49 +-33 +-23 +-17 +-15 +-15 +-17 +-19 +-20 +-20 +-21 +-20 +-20 +-20 +-19 +-17 +-17 +-16 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +22 +76 +92 +91 +73 +52 +28 +8 +-7 +-15 +-19 +-18 +-15 +-10 +-7 +-3 +-1 +1 +0 +1 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-46 +-32 +-23 +-16 +-14 +-13 +-15 +-17 +-18 +-19 +-20 +-20 +-20 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-14 +-13 +-12 +19 +74 +90 +88 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-3 +-1 +-1 +0 +-1 +-1 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-17 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +20 +73 +90 +89 +71 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-11 +-7 +-3 +-1 +-1 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-20 +-21 +-20 +-19 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +89 +72 +51 +27 +7 +-7 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-3 +-4 +-5 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-64 +-47 +-33 +-23 +-16 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-15 +-14 +-14 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +88 +71 +50 +27 +8 +-9 +-16 +-20 +-19 +-17 +-11 +-9 +-4 +-2 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-6 +-7 +-7 +-32 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-14 +-14 +-12 +20 +74 +90 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-8 +-4 +-2 +-1 +0 +0 +-1 +-1 +-3 +-5 +-6 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-14 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +50 +27 +7 +-9 +-17 +-20 +-20 +-17 +-11 +-8 +-4 +-2 +0 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-20 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-6 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-23 +-15 +-13 +-14 +-15 +-17 +-20 +-20 +-21 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +19 +73 +89 +88 +72 +51 +27 +8 +-9 +-17 +-20 +-20 +-17 +-12 +-8 +-4 +-1 +0 +-1 +0 +-1 +-3 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-48 +-33 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-21 +-20 +-18 +-18 +-16 +-15 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-12 +20 +73 +90 +89 +71 +51 +27 +8 +-7 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-1 +0 +0 +-1 +-1 +-2 +-4 +-5 +-7 +-6 +-6 +-6 +-7 +-6 +-8 +-7 +-33 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-17 +-17 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +74 +90 +89 +72 +50 +26 +7 +-7 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +0 +-1 +0 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-20 +-19 +-20 +-20 +-19 +-18 +-19 +-17 +-16 +-15 +-15 +-13 +-13 +-13 +-14 +-13 +-14 +-13 +20 +73 +89 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-8 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-20 +-19 +-20 +-17 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-4 +-2 +0 +0 +0 +-2 +-2 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-7 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-9 +-9 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-15 +-17 +-17 +-20 +-21 +-21 +-20 +-21 +-19 +-18 +-17 +-17 +-16 +-16 +-15 +-14 +-13 +-14 +-13 +-14 +-14 +19 +73 +89 +89 +72 +50 +27 +7 +-8 +-17 +-20 +-19 +-17 +-11 +-8 +-4 +-2 +-1 +-1 +0 +-1 +-2 +-4 +-4 +-5 +-7 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +72 +89 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-20 +-20 +-19 +-19 +-18 +-17 +-17 +-16 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-11 +-10 +22 +76 +92 +91 +74 +53 +28 +9 +-6 +-16 +-19 +-18 +-15 +-11 +-7 +-3 +-1 +0 +1 +1 +-1 +-1 +-3 +-4 +-6 +-5 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-3 +-1 +0 +-1 +-1 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-7 +-8 +-7 +-7 +-8 +-8 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-8 +-10 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-36 +-73 +-99 +-99 +-86 +-67 +-50 +-34 +-23 +-17 +-16 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-19 +-17 +-17 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +22 +77 +92 +91 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +0 +-1 +-3 +-4 +-5 +-6 +-6 +-5 +-7 +-6 +-7 +-6 +-32 +-70 +-96 +-97 +-84 +-65 +-47 +-31 +-21 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-18 +-18 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +27 +8 +-7 +-16 +-21 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-7 +-6 +-7 +-6 +-7 +-6 +-6 +-7 +-32 +-70 +-96 +-97 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +89 +73 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-8 +-8 +-9 +-8 +-9 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-33 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-21 +-19 +-19 +-18 +-17 +-15 +-15 +-14 +-14 +-13 +-15 +-14 +-14 +-13 +19 +73 +89 +89 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-8 +-6 +-7 +-7 +-32 +-70 +-96 +-97 +-84 +-65 +-47 +-31 +-21 +-16 +-14 +-13 +-16 +-17 +-19 +-19 +-21 +-19 +-19 +-18 +-17 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-10 +-10 +-12 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +22 +76 +92 +91 +73 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-4 +-1 +1 +0 +1 +-1 +-1 +-3 +-4 +-5 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-7 +-9 +-8 +-8 +-9 +-9 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-86 +-67 +-50 +-34 +-23 +-17 +-15 +-14 +-16 +-17 +-19 +-20 +-22 +-21 +-21 +-19 +-19 +-17 +-17 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +50 +27 +7 +-8 +-16 +-21 +-19 +-17 +-13 +-8 +-4 +-2 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-7 +-6 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-16 +-18 +-20 +-20 +-19 +-20 +-19 +-18 +-17 +-16 +-15 +-14 +-14 +-13 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +22 +76 +92 +90 +74 +53 +29 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-2 +-4 +-4 +-5 +-4 +-6 +-5 +-6 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-18 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-12 +20 +74 +90 +89 +71 +51 +27 +8 +-7 +-17 +-20 +-20 +-18 +-12 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-16 +-15 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-3 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-7 +-6 +-7 +-8 +-8 +-7 +-8 +-7 +-8 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-9 +-9 +-10 +-8 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-85 +-66 +-49 +-34 +-23 +-17 +-15 +-15 +-16 +-17 +-19 +-20 +-22 +-21 +-20 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +21 +75 +92 +91 +74 +53 +29 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-2 +-1 +0 +0 +1 +-1 +-1 +-3 +-4 +-5 +-5 +-7 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-99 +-86 +-66 +-49 +-34 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-19 +-17 +-17 +-15 +-15 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +18 +73 +89 +88 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-5 +-5 +-5 +-7 +-7 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-84 +-65 +-47 +-33 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-12 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-16 +-21 +-20 +-17 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-5 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-21 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +20 +73 +90 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-6 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-2 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-19 +-19 +-18 +-17 +-17 +-16 +-15 +-15 +-13 +-13 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-11 +-10 +-10 +22 +76 +92 +91 +73 +53 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-8 +-3 +-1 +1 +0 +1 +-1 +-2 +-3 +-4 +-5 +-6 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-15 +-17 +-17 +-20 +-21 +-21 +-21 +-21 +-19 +-18 +-17 +-16 +-14 +-15 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +22 +76 +93 +92 +74 +53 +29 +9 +-7 +-15 +-20 +-19 +-15 +-11 +-7 +-3 +-1 +0 +0 +1 +-2 +-2 +-3 +-3 +-5 +-5 +-6 +-7 +-7 +-6 +-7 +-6 +-7 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-8 +-8 +-9 +-9 +-8 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-17 +-19 +-20 +-20 +-20 +-20 +-19 +-18 +-18 +-17 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +88 +88 +71 +51 +26 +7 +-8 +-17 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +-1 +-1 +-2 +-2 +-3 +-5 +-6 +-5 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-10 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +21 +76 +91 +91 +74 +52 +28 +9 +-7 +-15 +-19 +-18 +-16 +-10 +-7 +-3 +-1 +1 +0 +1 +-1 +-2 +-3 +-3 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-21 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-17 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-10 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-18 +-19 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-14 +-14 +18 +73 +89 +88 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-11 +-8 +-3 +-1 +0 +-1 +-1 +-2 +-2 +-3 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-20 +-19 +-17 +-12 +-7 +-4 +-1 +0 +-1 +0 +-1 +-3 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-16 +-16 +-19 +-20 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +88 +72 +51 +27 +7 +-7 +-17 +-21 +-20 +-17 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-7 +-33 +-70 +-96 +-80 +-82 +-64 +-47 +-32 +-22 +-16 +-13 +-13 +-15 +-17 +-18 +-19 +-20 +-19 +-21 +-19 +-18 +-17 +-16 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +50 +26 +7 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-8 +-33 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-12 +20 +74 +90 +89 +72 +51 +27 +7 +-9 +-17 +-20 +-20 +-16 +-11 +-8 +-3 +-2 +0 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-21 +-15 +-13 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-17 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-14 +19 +73 +90 +89 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-7 +-3 +-2 +0 +0 +-1 +-2 +-2 +-5 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-8 +-6 +-33 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-17 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-12 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +7 +-9 +-17 +-21 +-19 +-17 +-11 +-7 +-4 +-1 +0 +-1 +-1 +-2 +-3 +-4 +-4 +-5 +-6 +-7 +-6 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-20 +-21 +-20 +-19 +-18 +-17 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +87 +71 +50 +26 +7 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-5 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-10 +-9 +-10 +-10 +-11 +-10 +21 +75 +92 +90 +74 +53 +28 +9 +-7 +-15 +-20 +-18 +-15 +-11 +-6 +-2 +-1 +1 +1 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-33 +-23 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +19 +72 +89 +89 +71 +51 +27 +8 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-3 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-16 +-17 +-18 +-20 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +26 +8 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +1 +0 +-1 +-1 +-2 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-18 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-14 +-13 +-13 +19 +73 +89 +89 +71 +50 +26 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-19 +-18 +-17 +-17 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-5 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-19 +-18 +-18 +-16 +-15 +-15 +-15 +-14 +-15 +-14 +-13 +-13 +-13 +-12 +19 +73 +89 +89 +71 +51 +27 +7 +-7 +-16 +-21 +-20 +-17 +-11 +-8 +-3 +-1 +1 +0 +0 +-2 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-8 +-10 +-9 +-9 +-9 +-9 +-8 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-23 +-17 +-16 +-15 +-17 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-12 +-10 +-10 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +22 +76 +92 +91 +73 +52 +28 +8 +-7 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +0 +0 +1 +-1 +-1 +-3 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-32 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-21 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-17 +-15 +-14 +-13 +-14 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +-1 +0 +0 +-1 +-1 +-3 +-5 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-8 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-98 +-86 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-18 +-19 +-20 +-21 +-21 +-21 +-19 +-19 +-17 +-17 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-13 +-12 +-12 +-13 +-12 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +22 +76 +92 +91 +73 +52 +29 +9 +-6 +-15 +-19 +-19 +-16 +-12 +-7 +-2 +-1 +1 +1 +1 +-1 +-2 +-3 +-5 +-5 +-5 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-33 +-23 +-16 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-15 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +19 +73 +89 +88 +71 +51 +27 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +1 +1 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-14 +-14 +-12 +20 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +1 +-1 +-2 +-3 +-5 +-6 +-5 +-7 +-7 +-7 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-16 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +89 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-7 +-2 +-2 +0 +0 +-1 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +7 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-2 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-12 +-12 +-12 +19 +73 +90 +88 +72 +50 +27 +8 +-7 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-14 +-13 +20 +73 +89 +89 +71 +51 +27 +8 +-8 +-16 +-20 +-20 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-21 +-19 +-18 +-17 +-15 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +74 +90 +89 +71 +50 +27 +7 +-7 +-16 +-20 +-19 +-16 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-13 +-13 +20 +73 +90 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-17 +-17 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-8 +-3 +-2 +0 +0 +0 +-1 +-1 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-16 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-11 +-7 +-3 +-1 +1 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +20 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +50 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-8 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-24 +-17 +-15 +-15 +-17 +-17 +-20 +-21 +-21 +-21 +-21 +-19 +-18 +-17 +-16 +-15 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +50 +27 +8 +-8 +-17 +-20 +-20 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-14 +19 +73 +90 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-13 +-12 +-12 +-11 +-12 +-11 +-10 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +22 +76 +92 +91 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-1 +-4 +-5 +-6 +-6 +-6 +-6 +-8 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +74 +89 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-7 +-3 +-2 +0 +-1 +0 +-1 +-2 +-3 +-3 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-11 +-35 +-73 +-98 +-98 +-85 +-67 +-49 +-34 +-23 +-17 +-15 +-14 +-17 +-17 +-19 +-20 +-22 +-21 +-20 +-20 +-18 +-17 +-17 +-15 +-15 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-10 +-10 +22 +76 +91 +91 +74 +52 +29 +10 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +0 +1 +1 +1 +-1 +-2 +-3 +-3 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-20 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +72 +51 +27 +8 +-7 +-17 +-21 +-20 +-17 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-5 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-65 +-48 +-33 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +74 +90 +89 +72 +49 +26 +7 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +0 +-1 +0 +-1 +-2 +-3 +-4 +-5 +-7 +-7 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-8 +-7 +-7 +-9 +-8 +-8 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-50 +-34 +-24 +-17 +-15 +-14 +-15 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-19 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-14 +-13 +-13 +18 +73 +89 +88 +71 +50 +26 +8 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-5 +-2 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-8 +-6 +-7 +-7 +-33 +-71 +-97 +-97 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-19 +-20 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-15 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +89 +74 +53 +29 +10 +-6 +-15 +-20 +-19 +-16 +-11 +-6 +-3 +-1 +1 +1 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-9 +-8 +-9 +-10 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-98 +-99 +-86 +-66 +-49 +-33 +-23 +-17 +-15 +-14 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +18 +73 +89 +88 +71 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +-1 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-18 +-19 +-20 +-21 +-20 +-19 +-17 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-13 +-12 +-12 +-11 +-11 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-11 +-10 +21 +76 +92 +91 +74 +53 +28 +9 +-6 +-16 +-20 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +0 +-1 +-1 +-4 +-4 +-6 +-5 +-7 +-6 +-6 +-7 +-7 +-6 +-32 +-70 +-96 +-97 +-83 +-65 +-47 +-31 +-21 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +-1 +-1 +0 +-2 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-21 +-19 +-19 +-19 +-18 +-16 +-17 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +18 +73 +89 +89 +72 +51 +26 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-8 +-3 +-2 +0 +0 +-1 +-1 +-2 +-3 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-98 +-98 +-85 +-66 +-49 +-34 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-9 +22 +76 +92 +90 +74 +52 +28 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-2 +-1 +1 +1 +0 +-1 +-2 +-3 +-5 +-5 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-9 +-7 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-9 +-9 +-8 +-9 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-23 +-17 +-15 +-15 +-16 +-17 +-20 +-21 +-22 +-21 +-20 +-19 +-18 +-17 +-17 +-16 +-15 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +18 +73 +89 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-7 +-3 +-2 +0 +-1 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-18 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-15 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +71 +51 +27 +7 +-7 +-16 +-20 +-19 +-16 +-12 +-9 +-3 +-1 +0 +0 +1 +-2 +-2 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-7 +-33 +-71 +-97 +-80 +-83 +-64 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-14 +-13 +-12 +20 +74 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +-1 +0 +0 +-1 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-6 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-84 +-65 +-47 +-32 +-21 +-15 +-15 +-14 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-12 +20 +73 +90 +89 +71 +51 +27 +8 +-8 +-16 +-20 +-20 +-16 +-11 +-7 +-4 +-1 +-1 +-1 +0 +-2 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-97 +-80 +-84 +-66 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-19 +-19 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-12 +18 +73 +89 +89 +72 +51 +27 +7 +-7 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +-1 +-2 +-2 +-3 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-79 +-83 +-65 +-47 +-33 +-23 +-16 +-14 +-13 +-15 +-17 +-19 +-20 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-12 +-12 +-13 +-13 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-11 +-11 +-10 +22 +76 +92 +91 +74 +52 +28 +9 +-7 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-6 +-6 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-98 +-86 +-67 +-49 +-33 +-23 +-17 +-15 +-15 +-16 +-17 +-20 +-20 +-20 +-21 +-21 +-19 +-18 +-17 +-16 +-15 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-13 +-12 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +22 +76 +91 +90 +74 +51 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-11 +-10 +-10 +-11 +-10 +-34 +-73 +-99 +-99 +-85 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-18 +-21 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-2 +-3 +-4 +-4 +-5 +-5 +-6 +-6 +-8 +-7 +-8 +-8 +-33 +-71 +-97 +-97 +-83 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-17 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-9 +-10 +-9 +-10 +-9 +-11 +-10 +22 +76 +92 +91 +74 +52 +29 +9 +-7 +-15 +-20 +-19 +-16 +-10 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-31 +-21 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-8 +-16 +-21 +-20 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-8 +-7 +-7 +-8 +-8 +-7 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-20 +-20 +-19 +-18 +-18 +-17 +-15 +-15 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-11 +-7 +-5 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-11 +-8 +-4 +-1 +1 +-1 +-1 +-2 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-8 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-21 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-7 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +1 +0 +-1 +-1 +-2 +-5 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-33 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-13 +-15 +-17 +-18 +-20 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +90 +88 +72 +51 +27 +8 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-6 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +88 +71 +50 +26 +7 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-3 +-1 +0 +-1 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +18 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-33 +-70 +-96 +-79 +-82 +-64 +-47 +-32 +-23 +-15 +-13 +-13 +-15 +-16 +-18 +-20 +-21 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-12 +19 +73 +89 +88 +71 +50 +27 +8 +-8 +-17 +-20 +-19 +-16 +-11 +-8 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-97 +-83 +-64 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-18 +-19 +-21 +-19 +-19 +-19 +-18 +-16 +-17 +-15 +-14 +-14 +-14 +-13 +-13 +-14 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +22 +76 +91 +91 +74 +52 +29 +10 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-8 +-32 +-70 +-96 +-80 +-82 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +71 +51 +26 +7 +-7 +-16 +-20 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +73 +51 +26 +8 +-8 +-17 +-21 +-19 +-17 +-11 +-8 +-5 +-2 +0 +-1 +-1 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-8 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-16 +-17 +-19 +-19 +-21 +-19 +-19 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +90 +88 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-7 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-14 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +73 +51 +27 +8 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +71 +51 +27 +7 +-7 +-16 +-21 +-19 +-16 +-13 +-8 +-4 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-7 +-7 +-7 +-8 +-7 +-8 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-50 +-34 +-23 +-17 +-14 +-14 +-17 +-18 +-20 +-21 +-22 +-20 +-20 +-19 +-18 +-17 +-17 +-16 +-16 +-15 +-15 +-13 +-14 +-14 +-13 +-13 +-14 +-12 +-12 +-13 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-11 +-10 +22 +76 +92 +91 +74 +52 +28 +8 +-7 +-15 +-20 +-18 +-15 +-11 +-7 +-3 +-1 +0 +1 +1 +-1 +-1 +-3 +-5 +-6 +-5 +-7 +-7 +-7 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-12 +19 +73 +90 +89 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-8 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-4 +-6 +-6 +-8 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-8 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-9 +-10 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-11 +-10 +-10 +-11 +-9 +-10 +-10 +-10 +-9 +-35 +-73 +-99 +-98 +-86 +-66 +-49 +-34 +-24 +-17 +-16 +-15 +-16 +-17 +-20 +-20 +-21 +-21 +-21 +-19 +-19 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-10 +-9 +-11 +-10 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +90 +73 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-2 +1 +1 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +20 +73 +90 +89 +71 +50 +26 +7 +-8 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-1 +0 +0 +1 +-1 +-2 +-4 +-5 +-7 +-6 +-6 +-7 +-7 +-6 +-7 +-6 +-32 +-71 +-97 +-80 +-84 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-17 +-18 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +88 +71 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-2 +0 +0 +1 +-1 +-1 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-12 +20 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-20 +-19 +-16 +-11 +-8 +-3 +-2 +0 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +18 +73 +89 +89 +72 +51 +27 +7 +-8 +-17 +-22 +-19 +-16 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-7 +-7 +-8 +-7 +-8 +-7 +-32 +-70 +-96 +-79 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-13 +-13 +-13 +-12 +-14 +-13 +19 +73 +89 +89 +72 +51 +28 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-8 +-3 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-14 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +20 +73 +89 +88 +71 +51 +27 +7 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-6 +-6 +-6 +-6 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +20 +74 +90 +89 +72 +50 +27 +7 +-8 +-16 +-20 +-20 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-19 +-19 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +89 +89 +71 +51 +27 +7 +-9 +-17 +-21 +-20 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-19 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-17 +-21 +-19 +-17 +-11 +-8 +-4 +-1 +0 +-1 +-1 +-1 +-3 +-4 +-4 +-5 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-32 +-70 +-95 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-21 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-14 +-13 +19 +73 +89 +89 +71 +51 +27 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-8 +-3 +-1 +0 +0 +0 +-2 +-3 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-48 +-32 +-23 +-16 +-14 +-14 +-16 +-17 +-19 +-20 +-20 +-20 +-20 +-19 +-17 +-17 +-16 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +50 +27 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-7 +-4 +-2 +0 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-16 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-14 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +20 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-20 +-20 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-9 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-85 +-66 +-50 +-34 +-24 +-17 +-15 +-14 +-16 +-17 +-19 +-21 +-22 +-21 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-15 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +50 +26 +7 +-8 +-16 +-20 +-20 +-17 +-11 +-8 +-4 +-2 +-1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-7 +-7 +-7 +-6 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-16 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +74 +89 +89 +72 +50 +26 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +0 +-1 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-84 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-19 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-10 +-10 +22 +76 +92 +91 +73 +51 +29 +9 +-7 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-1 +-3 +-4 +-5 +-6 +-6 +-5 +-7 +-6 +-6 +-7 +-33 +-71 +-97 +-80 +-83 +-64 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-18 +-20 +-20 +-19 +-19 +-19 +-18 +-16 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-6 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-8 +-8 +-7 +-9 +-8 +-9 +-9 +-10 +-10 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-14 +-16 +-17 +-19 +-21 +-21 +-21 +-21 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-13 +-12 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +21 +76 +92 +90 +74 +53 +28 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-2 +-1 +1 +0 +1 +-1 +-2 +-3 +-3 +-5 +-5 +-6 +-7 +-7 +-6 +-7 +-7 +-31 +-69 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-18 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +89 +88 +72 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-7 +-4 +-2 +0 +0 +0 +-2 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-18 +-19 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +72 +51 +27 +8 +-7 +-17 +-21 +-20 +-17 +-12 +-8 +-4 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-11 +-35 +-73 +-99 +-99 +-85 +-67 +-50 +-34 +-23 +-17 +-15 +-14 +-17 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +18 +73 +89 +88 +72 +51 +26 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-23 +-15 +-13 +-13 +-16 +-17 +-18 +-20 +-21 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-13 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +22 +76 +92 +91 +74 +53 +28 +9 +-7 +-16 +-20 +-18 +-15 +-11 +-6 +-2 +-1 +1 +1 +0 +-1 +-1 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-7 +-8 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-8 +-9 +-10 +-10 +-9 +-11 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-85 +-66 +-49 +-34 +-23 +-17 +-15 +-14 +-17 +-17 +-19 +-21 +-21 +-21 +-21 +-19 +-19 +-17 +-17 +-15 +-15 +-15 +-14 +-14 +-15 +-14 +-13 +-13 +19 +73 +90 +89 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +-1 +-1 +-1 +-4 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-97 +-83 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-14 +-12 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +91 +74 +53 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-4 +-1 +1 +1 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-6 +-6 +-6 +-32 +-70 +-96 +-97 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-19 +-18 +-17 +-17 +-15 +-14 +-13 +-14 +-13 +-13 +-14 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-4 +-2 +0 +0 +0 +-2 +-1 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-8 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-8 +-7 +-7 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-10 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-36 +-74 +-99 +-98 +-85 +-66 +-49 +-34 +-24 +-17 +-15 +-15 +-16 +-18 +-20 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +90 +74 +53 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-2 +1 +1 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-6 +-6 +-6 +-7 +-8 +-7 +-8 +-8 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-11 +-10 +-9 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-24 +-17 +-15 +-15 +-17 +-17 +-20 +-21 +-21 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +50 +27 +8 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-3 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +88 +71 +51 +27 +7 +-8 +-16 +-21 +-19 +-17 +-13 +-8 +-4 +-2 +0 +1 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-23 +-16 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-12 +19 +73 +89 +89 +72 +50 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-1 +-3 +-4 +-5 +-6 +-7 +-7 +-6 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-17 +-16 +-16 +-16 +-14 +-14 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-8 +-17 +-22 +-20 +-17 +-12 +-8 +-4 +-1 +-1 +0 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-7 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-16 +-19 +-20 +-20 +-20 +-19 +-17 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-7 +-3 +-1 +0 +-1 +0 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-20 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-11 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-11 +22 +75 +91 +91 +75 +53 +29 +9 +-7 +-15 +-19 +-19 +-16 +-10 +-7 +-3 +-1 +0 +0 +1 +-1 +-2 +-3 +-3 +-5 +-5 +-6 +-7 +-7 +-6 +-6 +-6 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-86 +-67 +-49 +-34 +-23 +-17 +-16 +-15 +-16 +-18 +-21 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-16 +-16 +-15 +-14 +-15 +-14 +-14 +-13 +-15 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +22 +75 +91 +91 +74 +52 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +0 +1 +0 +1 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-6 +-6 +-6 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-35 +-24 +-17 +-15 +-14 +-17 +-18 +-20 +-21 +-21 +-21 +-20 +-19 +-19 +-17 +-17 +-16 +-16 +-15 +-14 +-14 +-13 +-13 +-14 +-13 +18 +72 +89 +88 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-11 +-8 +-3 +-1 +1 +-1 +0 +-2 +-3 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-13 +-15 +-16 +-19 +-20 +-20 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-13 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +22 +75 +92 +91 +74 +53 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-2 +0 +0 +0 +1 +-1 +-1 +-3 +-3 +-5 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-17 +-17 +-16 +-15 +-16 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-17 +-21 +-19 +-17 +-11 +-7 +-3 +-1 +0 +-1 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-11 +-9 +-10 +-9 +-10 +-10 +-10 +-11 +-10 +-9 +-10 +-9 +-35 +-73 +-99 +-98 +-85 +-66 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-20 +-21 +-19 +-19 +-18 +-17 +-15 +-15 +-14 +-14 +-15 +-15 +-14 +-14 +-13 +19 +73 +89 +89 +72 +51 +26 +8 +-9 +-17 +-21 +-19 +-17 +-11 +-7 +-4 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-5 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-21 +-20 +-19 +-18 +-17 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-20 +-16 +-11 +-7 +-3 +-1 +-1 +-1 +-1 +-2 +-3 +-3 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-33 +-70 +-96 +-79 +-83 +-65 +-48 +-33 +-23 +-15 +-13 +-13 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-13 +19 +74 +89 +89 +72 +50 +26 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-7 +-3 +-1 +0 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-33 +-71 +-96 +-80 +-83 +-64 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-14 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +73 +90 +89 +71 +50 +26 +7 +-8 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-6 +-6 +-7 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-16 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-1 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-97 +-84 +-65 +-48 +-32 +-21 +-15 +-14 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-20 +-16 +-11 +-7 +-3 +-2 +0 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-66 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +26 +8 +-8 +-17 +-21 +-19 +-17 +-12 +-7 +-3 +-1 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-83 +-65 +-48 +-32 +-21 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +88 +71 +50 +27 +7 +-9 +-17 +-20 +-19 +-17 +-11 +-8 +-4 +-1 +1 +0 +0 +-2 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-18 +-20 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +21 +76 +92 +90 +73 +52 +29 +9 +-6 +-15 +-20 +-18 +-16 +-11 +-7 +-2 +-1 +1 +1 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +-12 +-13 +19 +73 +89 +88 +71 +51 +26 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-1 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-64 +-48 +-33 +-23 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +19 +74 +90 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-13 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-18 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-14 +-14 +-14 +-13 +-14 +-14 +-14 +-13 +19 +74 +90 +88 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-16 +-11 +-7 +-4 +-2 +0 +1 +0 +-1 +-1 +-4 +-4 +-6 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-22 +-20 +-17 +-11 +-7 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-7 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-6 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-10 +-9 +-9 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-98 +-86 +-67 +-49 +-35 +-24 +-17 +-15 +-15 +-17 +-17 +-20 +-21 +-21 +-21 +-21 +-19 +-19 +-17 +-17 +-15 +-15 +-14 +-14 +-14 +-15 +-14 +-14 +-13 +-13 +-12 +-12 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +90 +73 +53 +29 +9 +-6 +-15 +-20 +-18 +-16 +-11 +-7 +-2 +-1 +1 +1 +0 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-14 +-16 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +20 +73 +90 +89 +71 +50 +26 +7 +-7 +-16 +-20 +-20 +-16 +-12 +-8 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-9 +-11 +-10 +-11 +-10 +-11 +-10 +-36 +-73 +-98 +-98 +-85 +-67 +-49 +-34 +-23 +-17 +-15 +-14 +-16 +-19 +-20 +-20 +-21 +-21 +-20 +-19 +-18 +-17 +-17 +-16 +-15 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +22 +75 +92 +91 +74 +52 +28 +9 +-7 +-15 +-19 +-18 +-15 +-11 +-7 +-3 +-2 +1 +1 +0 +-1 +-1 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-97 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-19 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-20 +-16 +-11 +-8 +-4 +-2 +-1 +0 +0 +-1 +-1 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-20 +-20 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +19 +73 +89 +88 +72 +51 +27 +8 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +89 +71 +50 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-1 +0 +0 +0 +-2 +-2 +-4 +-4 +-6 +-5 +-7 +-7 +-7 +-6 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-16 +-19 +-20 +-20 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +89 +72 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-84 +-64 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-16 +-15 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +71 +51 +26 +7 +-8 +-17 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-1 +-1 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-16 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-6 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-20 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +19 +73 +89 +88 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-17 +-11 +-8 +-3 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-23 +-16 +-13 +-13 +-15 +-17 +-18 +-20 +-20 +-19 +-20 +-17 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +71 +51 +27 +7 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-4 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-6 +-6 +-8 +-7 +-32 +-71 +-96 +-80 +-84 +-65 +-47 +-33 +-22 +-16 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-21 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +74 +90 +89 +72 +50 +26 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-8 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-4 +-2 +-1 +0 +0 +-2 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-16 +-17 +-20 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +19 +74 +90 +89 +72 +51 +27 +8 +-9 +-17 +-21 +-20 +-16 +-11 +-7 +-4 +-2 +0 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-6 +-6 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +90 +89 +71 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-11 +-8 +-3 +-1 +0 +-1 +0 +-2 +-3 +-3 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-7 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-98 +-86 +-67 +-49 +-34 +-24 +-17 +-15 +-14 +-17 +-18 +-19 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +18 +72 +89 +88 +71 +51 +26 +7 +-7 +-17 +-21 +-19 +-17 +-12 +-7 +-3 +-2 +0 +-1 +0 +-1 +-3 +-3 +-4 +-6 +-5 +-7 +-7 +-7 +-7 +-8 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-19 +-20 +-20 +-20 +-20 +-17 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +28 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-7 +-4 +-1 +1 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-18 +-20 +-21 +-20 +-20 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-13 +-12 +-12 +-11 +-11 +-12 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +22 +75 +92 +91 +74 +52 +29 +9 +-7 +-15 +-19 +-19 +-16 +-10 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-20 +-21 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-7 +-4 +-1 +0 +0 +-1 +-1 +-2 +-5 +-5 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-8 +-7 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-98 +-86 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-20 +-20 +-19 +-18 +-18 +-17 +-15 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +21 +76 +92 +90 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-2 +1 +1 +0 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-33 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-14 +-15 +-14 +-13 +-14 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +50 +27 +7 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-4 +-2 +0 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-21 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +89 +73 +51 +27 +8 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-33 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-20 +-21 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-14 +-14 +18 +73 +89 +88 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-7 +-3 +-2 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +22 +76 +91 +91 +74 +52 +27 +8 +-6 +-16 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +0 +-1 +-1 +-3 +-3 +-5 +-6 +-6 +-6 +-7 +-6 +-6 +-6 +-7 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-36 +-74 +-99 +-99 +-86 +-67 +-49 +-34 +-23 +-17 +-15 +-14 +-16 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +50 +26 +8 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-33 +-71 +-97 +-97 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +22 +76 +92 +91 +73 +52 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-2 +-3 +-5 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-20 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-12 +20 +73 +90 +89 +72 +51 +26 +8 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-19 +-17 +-16 +-16 +-15 +-14 +-14 +-14 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-9 +-9 +-8 +-9 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-35 +-73 +-98 +-99 +-85 +-66 +-49 +-34 +-24 +-17 +-16 +-14 +-16 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-12 +-13 +-12 +-13 +-12 +-13 +-11 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-12 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-9 +-11 +-10 +22 +75 +91 +91 +74 +52 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +0 +1 +1 +1 +-1 +-2 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-9 +-10 +-10 +-10 +-9 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-34 +-23 +-17 +-16 +-15 +-17 +-18 +-20 +-20 +-22 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-14 +-14 +-13 +19 +73 +89 +89 +71 +51 +27 +7 +-8 +-17 +-22 +-20 +-17 +-12 +-8 +-4 +-2 +-1 +-1 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +18 +72 +89 +88 +72 +51 +27 +8 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +-1 +-1 +-2 +-3 +-4 +-5 +-5 +-5 +-7 +-7 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-3 +-3 +-4 +-5 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-23 +-16 +-14 +-13 +-15 +-16 +-18 +-19 +-20 +-19 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +88 +71 +51 +27 +7 +-7 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-2 +0 +0 +0 +-2 +-2 +-3 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +-14 +-12 +20 +73 +90 +89 +71 +51 +27 +8 +-8 +-16 +-20 +-20 +-16 +-11 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-14 +-13 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +22 +76 +92 +91 +74 +53 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-8 +-3 +-1 +0 +1 +1 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-8 +-7 +-8 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-15 +-16 +-17 +-19 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-16 +-16 +-15 +-14 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +22 +75 +92 +91 +74 +53 +28 +9 +-7 +-15 +-19 +-19 +-15 +-10 +-7 +-2 +-1 +0 +0 +0 +-1 +-2 +-3 +-3 +-5 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-66 +-49 +-34 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-19 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +19 +72 +89 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +-1 +-1 +0 +-2 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-8 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-20 +-20 +-20 +-19 +-19 +-18 +-17 +-17 +-16 +-15 +-16 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-11 +-11 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +22 +76 +92 +91 +74 +53 +28 +9 +-7 +-15 +-19 +-18 +-15 +-11 +-7 +-3 +-1 +0 +0 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-6 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-16 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-13 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-17 +-20 +-20 +-16 +-11 +-7 +-4 +-1 +0 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-85 +-66 +-49 +-34 +-24 +-17 +-15 +-15 +-16 +-17 +-20 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +50 +26 +7 +-9 +-17 +-20 +-20 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-14 +-13 +-14 +-13 +-14 +-13 +-14 +-13 +20 +73 +89 +89 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-1 +-4 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-20 +-20 +-21 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-9 +-17 +-21 +-20 +-17 +-11 +-7 +-4 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +18 +73 +90 +88 +72 +51 +26 +7 +-7 +-16 +-20 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-20 +-20 +-21 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +73 +89 +89 +72 +50 +27 +7 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-4 +-1 +1 +0 +-1 +-1 +-3 +-5 +-5 +-6 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-13 +-16 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +88 +72 +51 +27 +8 +-7 +-16 +-20 +-19 +-16 +-12 +-7 +-3 +-2 +1 +1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-31 +-22 +-15 +-13 +-14 +-16 +-17 +-18 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +74 +90 +89 +72 +50 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +-1 +0 +-1 +-2 +-4 +-4 +-5 +-7 +-7 +-6 +-7 +-6 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-14 +-17 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +26 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-71 +-97 +-97 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-16 +-17 +-18 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-9 +-11 +-11 +-11 +-10 +22 +76 +92 +90 +74 +53 +28 +9 +-6 +-16 +-19 +-18 +-15 +-11 +-7 +-3 +-2 +1 +1 +0 +-1 +-1 +-4 +-4 +-5 +-5 +-6 +-6 +-6 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +19 +74 +90 +89 +72 +50 +27 +8 +-8 +-17 +-21 +-19 +-17 +-11 +-7 +-4 +-1 +0 +-1 +-1 +-1 +-2 +-4 +-3 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-7 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-5 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-7 +-17 +-21 +-19 +-16 +-11 +-7 +-3 +-1 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-15 +-16 +-19 +-19 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-14 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +90 +88 +71 +51 +27 +8 +-7 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-2 +0 +1 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-84 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-16 +-16 +-14 +-14 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-1 +-4 +-4 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-36 +-73 +-98 +-98 +-85 +-66 +-49 +-34 +-24 +-17 +-16 +-15 +-16 +-18 +-20 +-20 +-21 +-21 +-21 +-19 +-19 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +21 +76 +92 +90 +74 +53 +29 +9 +-6 +-16 +-20 +-18 +-16 +-11 +-7 +-2 +-1 +1 +1 +0 +-1 +-1 +-4 +-4 +-5 +-5 +-6 +-5 +-6 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-18 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-15 +-15 +-14 +-13 +-15 +-14 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +71 +51 +27 +7 +-7 +-16 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-11 +-10 +-9 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-50 +-34 +-24 +-17 +-15 +-14 +-16 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-12 +-14 +-13 +-13 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-12 +-11 +-11 +-10 +-10 +-9 +-11 +-10 +-11 +-10 +-11 +-10 +22 +75 +92 +92 +74 +53 +29 +8 +-7 +-15 +-19 +-19 +-15 +-10 +-7 +-3 +-1 +1 +1 +1 +-2 +-1 +-3 +-3 +-5 +-5 +-6 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +27 +7 +-8 +-17 +-22 +-19 +-17 +-12 +-7 +-3 +-2 +0 +0 +0 +-1 +-2 +-3 +-5 +-5 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-84 +-65 +-47 +-33 +-23 +-16 +-14 +-13 +-15 +-17 +-18 +-19 +-20 +-21 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +89 +71 +51 +27 +8 +-7 +-16 +-20 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-18 +-19 +-20 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-14 +-13 +-12 +19 +73 +89 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-4 +-1 +1 +0 +1 +-1 +-2 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-71 +-96 +-79 +-83 +-64 +-47 +-33 +-22 +-16 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-14 +-14 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-8 +-15 +-20 +-19 +-16 +-11 +-9 +-4 +-1 +0 +0 +0 +-1 +-2 +-3 +-4 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-18 +-18 +-17 +-16 +-16 +-15 +-14 +-14 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +8 +-8 +-16 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +-1 +0 +0 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-21 +-20 +-18 +-18 +-17 +-16 +-15 +-16 +-14 +-14 +-13 +-13 +-12 +-14 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +-1 +0 +-1 +-3 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-95 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-14 +-14 +-15 +-14 +-13 +-13 +-13 +-12 +20 +73 +89 +89 +71 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-1 +0 +0 +0 +-2 +-2 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-80 +-82 +-64 +-47 +-32 +-23 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-14 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +19 +74 +89 +89 +72 +50 +26 +7 +-9 +-17 +-21 +-19 +-16 +-11 +-7 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-15 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-17 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +-1 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-7 +-6 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-14 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +74 +89 +89 +73 +51 +27 +8 +-8 +-17 +-21 +-19 +-17 +-12 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-33 +-23 +-16 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +72 +89 +89 +72 +50 +27 +8 +-8 +-17 +-20 +-19 +-16 +-11 +-8 +-4 +-1 +1 +0 +0 +-1 +-3 +-3 +-4 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-18 +-17 +-17 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +20 +74 +89 +89 +72 +51 +26 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-24 +-17 +-14 +-15 +-16 +-18 +-20 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +49 +26 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +0 +-1 +-1 +-2 +-3 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-8 +-8 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-15 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +19 +73 +89 +88 +71 +51 +27 +8 +-8 +-16 +-20 +-19 +-17 +-12 +-9 +-4 +-2 +0 +0 +1 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-7 +-7 +-6 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-12 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-10 +22 +76 +92 +90 +74 +53 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +-1 +0 +0 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-6 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-16 +-18 +-19 +-20 +-19 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +50 +26 +8 +-7 +-16 +-20 +-19 +-17 +-11 +-8 +-4 +-2 +0 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-7 +-7 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-35 +-73 +-98 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-14 +-16 +-18 +-21 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +22 +76 +91 +90 +74 +52 +28 +9 +-6 +-15 +-20 +-18 +-15 +-10 +-7 +-3 +-1 +1 +0 +0 +-1 +-1 +-3 +-3 +-4 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-13 +-15 +-17 +-18 +-20 +-21 +-19 +-19 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +89 +72 +51 +27 +8 +-7 +-16 +-20 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-8 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-15 +-16 +-18 +-19 +-20 +-19 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +26 +7 +-7 +-17 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-7 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-11 +-10 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-14 +-16 +-17 +-20 +-21 +-21 +-21 +-21 +-19 +-18 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +19 +73 +88 +88 +71 +50 +27 +7 +-7 +-16 +-20 +-20 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-8 +-8 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-15 +-17 +-18 +-19 +-21 +-20 +-20 +-19 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-14 +-13 +-13 +-13 +-12 +-12 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +21 +75 +91 +90 +74 +52 +29 +9 +-6 +-15 +-19 +-18 +-16 +-10 +-6 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-3 +-5 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-8 +-7 +-9 +-8 +-9 +-8 +-9 +-8 +-10 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-98 +-99 +-86 +-67 +-50 +-34 +-23 +-17 +-15 +-14 +-17 +-19 +-20 +-20 +-22 +-20 +-20 +-19 +-19 +-17 +-17 +-16 +-15 +-14 +-15 +-13 +-14 +-13 +-14 +-13 +18 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-7 +-3 +-2 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-20 +-21 +-19 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +21 +76 +92 +90 +74 +52 +28 +9 +-6 +-15 +-20 +-19 +-15 +-11 +-8 +-3 +-1 +1 +0 +0 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-6 +-6 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-7 +-17 +-21 +-20 +-17 +-12 +-8 +-4 +-2 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-15 +-15 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +88 +71 +51 +28 +8 +-7 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-2 +0 +0 +0 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-98 +-99 +-85 +-66 +-49 +-33 +-23 +-17 +-16 +-15 +-17 +-19 +-20 +-20 +-21 +-20 +-20 +-19 +-18 +-17 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +22 +76 +92 +91 +73 +52 +29 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-2 +-3 +-5 +-6 +-5 +-6 +-5 +-6 +-6 +-7 +-6 +-7 +-8 +-8 +-7 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-11 +-10 +-10 +-9 +-9 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-35 +-73 +-99 +-99 +-86 +-67 +-50 +-34 +-24 +-17 +-15 +-14 +-16 +-18 +-20 +-21 +-22 +-21 +-20 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +18 +72 +89 +88 +71 +51 +27 +8 +-8 +-16 +-21 +-19 +-16 +-13 +-8 +-3 +-1 +0 +0 +0 +-2 +-3 +-4 +-5 +-5 +-5 +-7 +-6 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-21 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +89 +71 +50 +27 +8 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-5 +-5 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-14 +-13 +-15 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-7 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-3 +-5 +-5 +-5 +-7 +-7 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-9 +-17 +-21 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-20 +-20 +-21 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +72 +89 +89 +71 +51 +27 +8 +-7 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-7 +-7 +-6 +-8 +-7 +-32 +-71 +-96 +-79 +-83 +-65 +-47 +-32 +-23 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-17 +-17 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +22 +75 +92 +91 +74 +53 +29 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +0 +1 +1 +-1 +-1 +-3 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-9 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-17 +-20 +-21 +-21 +-20 +-21 +-19 +-19 +-18 +-17 +-15 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-12 +-11 +-10 +-10 +-10 +-9 +22 +75 +91 +90 +74 +53 +29 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-2 +-4 +-4 +-5 +-5 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-8 +-10 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-11 +-10 +-10 +-10 +-9 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-35 +-72 +-99 +-98 +-86 +-67 +-50 +-34 +-23 +-17 +-15 +-14 +-17 +-18 +-19 +-21 +-21 +-20 +-21 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +18 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +-1 +-1 +0 +-2 +-2 +-3 +-4 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-79 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-21 +-20 +-19 +-17 +-16 +-15 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +21 +76 +92 +91 +74 +53 +28 +9 +-7 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-1 +-3 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-12 +-13 +-12 +20 +73 +89 +89 +72 +51 +27 +8 +-8 +-16 +-21 +-20 +-16 +-12 +-9 +-3 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-7 +-7 +-8 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-98 +-99 +-86 +-67 +-50 +-33 +-23 +-17 +-15 +-14 +-17 +-17 +-20 +-20 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +18 +73 +89 +88 +71 +51 +27 +7 +-8 +-16 +-20 +-20 +-16 +-11 +-8 +-3 +-1 +-1 +-1 +-1 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-8 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-65 +-48 +-33 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +20 +73 +89 +89 +72 +50 +27 +8 +-7 +-17 +-20 +-19 +-17 +-11 +-7 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-8 +-33 +-71 +-97 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-16 +-18 +-19 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +88 +71 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-7 +-3 +-2 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-6 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-33 +-22 +-16 +-15 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-8 +-4 +-2 +0 +0 +1 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-4 +-1 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-8 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +73 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-7 +-3 +-1 +0 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-8 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-13 +-15 +-16 +-18 +-20 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-7 +-3 +-1 +0 +0 +-1 +-1 +-2 +-5 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-11 +21 +76 +91 +91 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-15 +-10 +-6 +-3 +-1 +1 +0 +0 +-1 +-1 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-95 +-80 +-83 +-65 +-48 +-33 +-22 +-16 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +88 +71 +51 +27 +8 +-7 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-3 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-16 +-18 +-19 +-20 +-19 +-21 +-19 +-18 +-17 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +90 +88 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-16 +-11 +-7 +-3 +-2 +1 +0 +0 +-1 +-1 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-18 +-19 +-20 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-2 +0 +-1 +0 +-1 +-3 +-4 +-4 +-5 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-16 +-17 +-19 +-20 +-21 +-19 +-19 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +26 +8 +-7 +-17 +-21 +-19 +-16 +-11 +-7 +-3 +-2 +0 +0 +-1 +-2 +-2 +-5 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-83 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-12 +20 +73 +90 +89 +71 +51 +27 +8 +-7 +-17 +-21 +-19 +-17 +-12 +-8 +-4 +-1 +1 +-1 +-1 +-2 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-8 +-8 +-8 +-7 +-8 +-7 +-8 +-7 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-9 +-35 +-73 +-98 +-99 +-86 +-67 +-50 +-34 +-24 +-17 +-15 +-14 +-16 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-19 +-17 +-17 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-11 +-10 +-10 +-11 +-9 +22 +76 +92 +91 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-4 +-1 +1 +1 +0 +-1 +-1 +-3 +-4 +-5 +-6 +-6 +-6 +-7 +-6 +-7 +-6 +-32 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-18 +-19 +-20 +-19 +-19 +-19 +-18 +-16 +-17 +-15 +-15 +-13 +-14 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-1 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-85 +-66 +-49 +-34 +-24 +-18 +-16 +-15 +-17 +-18 +-19 +-20 +-21 +-21 +-20 +-20 +-19 +-17 +-17 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-12 +-13 +-13 +-13 +-12 +-13 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +21 +75 +92 +91 +74 +53 +29 +9 +-6 +-15 +-20 +-18 +-15 +-11 +-7 +-2 +0 +2 +1 +1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-20 +-20 +-21 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-12 +-12 +-12 +20 +73 +89 +89 +71 +51 +26 +8 +-7 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-5 +-5 +-5 +-6 +-5 +-6 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-65 +-47 +-33 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-19 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-14 +-14 +-13 +20 +73 +90 +89 +71 +51 +27 +7 +-7 +-16 +-21 +-20 +-16 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-2 +1 +0 +-1 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-6 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +19 +72 +89 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +0 +-1 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-6 +-7 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-23 +-16 +-13 +-14 +-16 +-17 +-20 +-20 +-21 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +27 +7 +-8 +-17 +-22 +-19 +-17 +-12 +-7 +-3 +-2 +0 +0 +0 +-2 +-2 +-4 +-5 +-5 +-5 +-7 +-7 +-7 +-8 +-8 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +88 +71 +51 +27 +8 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-79 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-14 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-13 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-6 +-6 +-6 +-7 +-7 +-32 +-71 +-97 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-17 +-18 +-17 +-16 +-15 +-15 +-13 +-13 +-14 +-13 +-13 +-14 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +0 +-1 +-1 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-14 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-17 +-22 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-5 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-33 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-7 +-3 +-1 +0 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-16 +-18 +-19 +-20 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +20 +73 +90 +89 +71 +51 +26 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +74 +89 +89 +73 +51 +27 +8 +-9 +-17 +-21 +-19 +-16 +-11 +-7 +-4 +-1 +0 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-8 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-9 +-9 +-10 +-10 +-11 +-11 +-35 +-73 +-99 +-98 +-86 +-66 +-49 +-34 +-24 +-17 +-15 +-15 +-16 +-17 +-20 +-20 +-21 +-21 +-21 +-19 +-19 +-17 +-16 +-15 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +49 +26 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +-1 +0 +-1 +-2 +-3 +-4 +-7 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +74 +90 +89 +73 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-7 +-4 +-2 +-1 +0 +0 +-2 +-2 +-3 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-17 +-20 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +-13 +-11 +-12 +-12 +-12 +-11 +-13 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +22 +77 +92 +91 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-1 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-64 +-46 +-31 +-21 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-19 +-17 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-9 +-17 +-21 +-20 +-17 +-11 +-7 +-4 +-1 +0 +-1 +-1 +-2 +-2 +-4 +-3 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-9 +-9 +-8 +-9 +-9 +-9 +-8 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-11 +-9 +-10 +-11 +-36 +-73 +-98 +-98 +-85 +-66 +-49 +-34 +-23 +-17 +-15 +-15 +-17 +-18 +-19 +-20 +-21 +-20 +-20 +-19 +-19 +-17 +-17 +-15 +-15 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-12 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-10 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +22 +76 +91 +90 +74 +52 +29 +10 +-7 +-15 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-16 +-18 +-20 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-15 +-13 +-13 +-12 +20 +74 +90 +89 +72 +50 +26 +7 +-8 +-17 +-20 +-19 +-16 +-12 +-8 +-3 +-2 +0 +1 +1 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-6 +-6 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-23 +-15 +-13 +-14 +-15 +-16 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +19 +74 +90 +89 +73 +50 +26 +7 +-7 +-16 +-21 +-19 +-16 +-11 +-7 +-4 +-2 +0 +-1 +-1 +-1 +-2 +-4 +-4 +-5 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-8 +-8 +-9 +-8 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-36 +-73 +-98 +-98 +-85 +-66 +-50 +-34 +-24 +-17 +-15 +-14 +-16 +-18 +-19 +-19 +-21 +-21 +-20 +-19 +-19 +-16 +-16 +-15 +-14 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +19 +73 +90 +88 +71 +49 +26 +7 +-9 +-17 +-21 +-19 +-16 +-11 +-8 +-4 +-2 +0 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-19 +-20 +-21 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-14 +-14 +-14 +-13 +-15 +-13 +-13 +-13 +-13 +-12 +-12 +-13 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-11 +-10 +-9 +22 +76 +92 +90 +73 +53 +29 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-2 +-1 +1 +1 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-10 +-10 +-9 +-10 +-10 +-9 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-99 +-86 +-67 +-50 +-34 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +18 +73 +89 +89 +72 +51 +26 +7 +-8 +-17 +-21 +-20 +-17 +-12 +-7 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-6 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-17 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-12 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-11 +-10 +22 +76 +93 +91 +74 +53 +28 +9 +-6 +-16 +-20 +-19 +-16 +-11 +-7 +-2 +-1 +1 +0 +0 +-1 +-1 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-97 +-83 +-65 +-47 +-31 +-21 +-15 +-14 +-13 +-15 +-17 +-18 +-19 +-21 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +90 +88 +71 +51 +27 +7 +-8 +-16 +-21 +-20 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +26 +7 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-2 +1 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-9 +-10 +-9 +-34 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-19 +-17 +-17 +-15 +-16 +-15 +-14 +-13 +-15 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +22 +77 +93 +91 +74 +52 +29 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-2 +-1 +1 +1 +1 +0 +-1 +-3 +-4 +-5 +-5 +-7 +-6 +-6 +-7 +-7 +-6 +-7 +-7 +-8 +-7 +-9 +-8 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-9 +-10 +-9 +-10 +-11 +-10 +-9 +-9 +-9 +-10 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-86 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-17 +-19 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +19 +73 +89 +88 +72 +51 +26 +8 +-8 +-17 +-21 +-19 +-17 +-13 +-8 +-4 +-2 +0 +0 +-1 +-1 +-2 +-4 +-4 +-6 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-19 +-16 +-16 +-15 +-14 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +20 +73 +89 +89 +71 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +88 +72 +51 +27 +8 +-7 +-17 +-21 +-19 +-16 +-12 +-7 +-3 +-3 +0 +0 +0 +-1 +-1 +-3 +-5 +-6 +-6 +-7 +-7 +-8 +-8 +-8 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-16 +-15 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +72 +52 +28 +8 +-7 +-16 +-21 +-20 +-17 +-12 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-9 +-8 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-19 +-19 +-17 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +88 +72 +51 +27 +7 +-8 +-16 +-21 +-20 +-17 +-13 +-8 +-4 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-23 +-16 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +-12 +-13 +-13 +-12 +-12 +-12 +-11 +-11 +-12 +-10 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +22 +76 +91 +91 +74 +53 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-2 +-1 +1 +1 +0 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-9 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-35 +-73 +-98 +-98 +-87 +-67 +-49 +-33 +-23 +-17 +-16 +-15 +-17 +-18 +-20 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-17 +-15 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-14 +-14 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-12 +-12 +-10 +-11 +-11 +-11 +-10 +-12 +-11 +-11 +-11 +-10 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +22 +77 +92 +91 +73 +52 +28 +9 +-6 +-15 +-20 +-18 +-15 +-11 +-7 +-3 +-1 +1 +0 +1 +-1 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-11 +-10 +-34 +-73 +-98 +-98 +-85 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-16 +-17 +-21 +-21 +-21 +-21 +-21 +-19 +-18 +-17 +-16 +-15 +-16 +-14 +-15 +-15 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +50 +27 +7 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +-12 +-12 +-12 +-11 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +91 +74 +52 +29 +10 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-18 +-20 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-14 +-14 +-14 +-15 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-9 +-4 +-1 +0 +1 +1 +-2 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-6 +-8 +-7 +-8 +-8 +-8 +-7 +-8 +-8 +-9 +-8 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-11 +-11 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-34 +-23 +-17 +-15 +-14 +-16 +-17 +-20 +-21 +-22 +-21 +-21 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +19 +74 +89 +88 +72 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-7 +-3 +-2 +0 +0 +-1 +-2 +-2 +-5 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-16 +-19 +-20 +-20 +-21 +-20 +-18 +-18 +-16 +-16 +-14 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +50 +27 +8 +-8 +-16 +-20 +-19 +-17 +-11 +-8 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-21 +-19 +-18 +-17 +-16 +-14 +-14 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +50 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-1 +-3 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-13 +-13 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-7 +-4 +-1 +0 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-19 +-17 +-11 +-7 +-3 +-2 +0 +0 +0 +-1 +-2 +-3 +-3 +-5 +-5 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-14 +-16 +-17 +-19 +-20 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-16 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +50 +27 +8 +-8 +-16 +-20 +-19 +-17 +-12 +-7 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-16 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-19 +-17 +-16 +-16 +-15 +-15 +-15 +-15 +-14 +-15 +-13 +-13 +-12 +19 +73 +90 +88 +72 +51 +26 +7 +-7 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-32 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +50 +27 +8 +-7 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-33 +-70 +-96 +-97 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +22 +76 +91 +91 +74 +51 +28 +9 +-7 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-4 +-5 +-6 +-6 +-5 +-7 +-6 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-14 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-17 +-16 +-16 +-15 +-14 +-15 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +90 +89 +72 +51 +26 +7 +-7 +-17 +-20 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-6 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-19 +-17 +-12 +-7 +-4 +-1 +0 +-1 +0 +-1 +-2 +-4 +-4 +-5 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-83 +-64 +-47 +-32 +-21 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +27 +8 +-8 +-17 +-20 +-19 +-16 +-12 +-7 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +89 +89 +72 +51 +27 +8 +-7 +-17 +-21 +-20 +-18 +-12 +-8 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-64 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-14 +-13 +-12 +19 +73 +90 +88 +71 +51 +27 +7 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-4 +-2 +0 +1 +1 +-1 +-2 +-3 +-5 +-5 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-50 +-34 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-22 +-21 +-20 +-19 +-18 +-16 +-17 +-15 +-16 +-15 +-15 +-13 +-13 +-13 +-13 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +21 +75 +92 +91 +74 +53 +29 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-2 +0 +1 +1 +1 +-1 +-1 +-3 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-95 +-79 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +72 +51 +26 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-7 +-7 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-9 +-35 +-73 +-98 +-99 +-86 +-67 +-49 +-34 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +22 +76 +92 +91 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-15 +-11 +-7 +-3 +-1 +1 +1 +0 +-1 +-1 +-3 +-4 +-6 +-5 +-7 +-6 +-6 +-6 +-7 +-6 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-17 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +-14 +-12 +20 +73 +89 +89 +71 +50 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +-1 +-1 +0 +-2 +-2 +-3 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-71 +-96 +-97 +-84 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-19 +-18 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +90 +88 +71 +51 +27 +8 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-95 +-79 +-84 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-16 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +89 +71 +51 +27 +8 +-7 +-16 +-20 +-20 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-18 +-19 +-21 +-20 +-19 +-19 +-18 +-16 +-16 +-15 +-14 +-13 +-15 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +88 +71 +50 +27 +7 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-5 +-6 +-5 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-71 +-96 +-79 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-12 +20 +73 +90 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-33 +-71 +-97 +-97 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-16 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-20 +-17 +-12 +-7 +-3 +-1 +0 +0 +0 +-2 +-1 +-3 +-4 +-6 +-6 +-7 +-7 +-8 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-19 +-19 +-20 +-21 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +88 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-79 +-83 +-64 +-47 +-33 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-14 +-13 +-13 +-13 +-12 +20 +73 +89 +89 +71 +50 +26 +7 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +0 +1 +1 +-1 +-2 +-4 +-5 +-7 +-6 +-7 +-7 +-7 +-6 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-20 +-21 +-19 +-18 +-17 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +50 +27 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-71 +-96 +-80 +-84 +-65 +-47 +-33 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-8 +-4 +-2 +-1 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-34 +-72 +-99 +-98 +-86 +-66 +-49 +-33 +-23 +-17 +-15 +-14 +-16 +-17 +-20 +-21 +-21 +-21 +-20 +-18 +-18 +-17 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +19 +72 +89 +88 +71 +51 +27 +8 +-8 +-16 +-21 +-20 +-17 +-11 +-8 +-3 +-1 +0 +-1 +-1 +-2 +-3 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-23 +-16 +-13 +-14 +-16 +-17 +-19 +-20 +-21 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +20 +73 +89 +89 +72 +50 +27 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +1 +0 +-1 +-2 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-8 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-12 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +91 +74 +53 +29 +9 +-7 +-15 +-20 +-18 +-16 +-11 +-6 +-3 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-18 +-20 +-20 +-19 +-19 +-18 +-18 +-16 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-16 +-21 +-20 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-9 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-72 +-99 +-98 +-85 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-20 +-21 +-19 +-19 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +-14 +-13 +-13 +-12 +-12 +-11 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-9 +22 +76 +91 +91 +74 +52 +29 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-8 +-3 +-1 +1 +1 +1 +0 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-6 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-19 +-17 +-12 +-7 +-4 +-2 +0 +0 +0 +-1 +-1 +-4 +-4 +-5 +-6 +-6 +-6 +-8 +-7 +-7 +-6 +-32 +-71 +-96 +-97 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-14 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +50 +26 +7 +-9 +-17 +-20 +-20 +-17 +-11 +-7 +-3 +-2 +0 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-8 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-99 +-85 +-66 +-49 +-33 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-21 +-20 +-20 +-18 +-17 +-17 +-15 +-15 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +19 +73 +90 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +-1 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-97 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-13 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-9 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +22 +76 +92 +90 +74 +53 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +0 +-1 +-2 +-4 +-5 +-5 +-6 +-7 +-6 +-6 +-6 +-6 +-6 +-8 +-7 +-8 +-8 +-8 +-7 +-8 +-8 +-9 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-11 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-50 +-34 +-23 +-17 +-14 +-14 +-16 +-17 +-20 +-21 +-22 +-21 +-21 +-19 +-18 +-17 +-16 +-15 +-15 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +1 +0 +0 +-2 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-18 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-13 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +22 +76 +91 +90 +74 +53 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-1 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-48 +-32 +-22 +-15 +-13 +-13 +-14 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-17 +-15 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +87 +71 +51 +27 +8 +-7 +-15 +-21 +-19 +-17 +-13 +-8 +-4 +-2 +0 +1 +1 +-1 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-10 +-10 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-11 +-10 +-11 +-10 +-36 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-24 +-17 +-15 +-14 +-16 +-18 +-20 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-12 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +22 +76 +92 +91 +74 +53 +28 +10 +-6 +-16 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +1 +1 +0 +-1 +-1 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-23 +-16 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-21 +-21 +-19 +-19 +-17 +-17 +-16 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-7 +-4 +-2 +-1 +-1 +-1 +-2 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-19 +-17 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +18 +72 +89 +88 +71 +51 +28 +7 +-7 +-16 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-7 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-20 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +88 +71 +51 +27 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +1 +1 +-1 +-1 +-2 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-12 +19 +73 +90 +89 +71 +51 +27 +7 +-7 +-16 +-21 +-20 +-17 +-12 +-8 +-4 +-1 +0 +0 +1 +-1 +-2 +-3 +-5 +-6 +-6 +-6 +-6 +-6 +-6 +-7 +-7 +-32 +-71 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-8 +-3 +-2 +0 +0 +-1 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-6 +-7 +-6 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-12 +-11 +-11 +-11 +-11 +-10 +-12 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-10 +-9 +22 +75 +92 +91 +74 +52 +29 +10 +-6 +-15 +-19 +-19 +-16 +-11 +-8 +-3 +-1 +1 +1 +1 +-1 +-2 +-3 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-11 +-11 +-9 +-34 +-72 +-98 +-98 +-86 +-67 +-49 +-34 +-23 +-16 +-15 +-15 +-16 +-17 +-20 +-20 +-21 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-12 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-11 +-11 +-12 +-12 +-11 +-11 +-11 +-10 +-10 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +22 +76 +92 +91 +74 +52 +28 +9 +-7 +-15 +-19 +-19 +-15 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-9 +-9 +-9 +-10 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-86 +-66 +-49 +-34 +-24 +-17 +-15 +-15 +-16 +-17 +-20 +-20 +-21 +-21 +-21 +-19 +-19 +-17 +-17 +-15 +-15 +-14 +-14 +-15 +-15 +-13 +-14 +-13 +19 +73 +89 +88 +71 +50 +26 +7 +-9 +-17 +-20 +-19 +-17 +-12 +-9 +-4 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-7 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-13 +-14 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-13 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-11 +-10 +22 +75 +92 +91 +73 +52 +28 +9 +-7 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +0 +1 +1 +1 +-1 +-2 +-3 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-18 +-19 +-21 +-20 +-20 +-19 +-17 +-16 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-8 +-8 +-8 +-9 +-8 +-8 +-9 +-9 +-8 +-9 +-10 +-9 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-11 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-14 +-14 +-16 +-17 +-21 +-21 +-21 +-21 +-21 +-19 +-18 +-17 +-16 +-15 +-15 +-15 +-15 +-15 +-15 +-13 +-14 +-13 +19 +73 +89 +88 +72 +50 +27 +8 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-3 +-4 +-5 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +20 +73 +89 +89 +71 +50 +26 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +-1 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-8 +-7 +-33 +-71 +-97 +-97 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-14 +-15 +-17 +-18 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-14 +-16 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +73 +50 +27 +7 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-3 +-1 +1 +-1 +0 +-2 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-6 +-6 +-7 +-32 +-71 +-96 +-80 +-84 +-65 +-48 +-32 +-21 +-15 +-14 +-13 +-16 +-17 +-19 +-19 +-21 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +19 +72 +89 +88 +72 +51 +27 +8 +-8 +-17 +-20 +-19 +-16 +-11 +-8 +-3 +-2 +0 +-1 +0 +-2 +-3 +-4 +-4 +-6 +-6 +-6 +-7 +-8 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-20 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +51 +27 +8 +-7 +-17 +-21 +-19 +-17 +-12 +-7 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-16 +-14 +-13 +-15 +-16 +-19 +-19 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-4 +-1 +1 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-82 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-16 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +51 +26 +7 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +1 +0 +0 +-1 +-2 +-4 +-4 +-6 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +7 +-9 +-16 +-20 +-19 +-16 +-11 +-7 +-4 +-1 +0 +-1 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-71 +-97 +-97 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-14 +-17 +-17 +-19 +-20 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +22 +76 +92 +90 +74 +53 +28 +9 +-6 +-15 +-19 +-18 +-15 +-11 +-7 +-3 +-1 +1 +0 +1 +0 +-2 +-3 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-7 +-3 +-2 +0 +0 +0 +-1 +-1 +-3 +-4 +-5 +-6 +-6 +-6 +-7 +-6 +-7 +-6 +-32 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-16 +-16 +-15 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +18 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-7 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-17 +-16 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +27 +8 +-7 +-17 +-21 +-20 +-17 +-11 +-7 +-3 +-2 +0 +0 +-1 +-1 +-2 +-5 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-83 +-65 +-48 +-33 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-22 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-12 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-21 +-19 +-17 +-11 +-7 +-3 +-1 +1 +0 +0 +-2 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-8 +-8 +-33 +-71 +-97 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-12 +-15 +-17 +-18 +-20 +-21 +-20 +-20 +-19 +-17 +-16 +-16 +-15 +-14 +-15 +-15 +-13 +-14 +-13 +-13 +-12 +19 +74 +90 +89 +72 +51 +26 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-4 +-2 +0 +1 +0 +-1 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-6 +-7 +-7 +-6 +-8 +-7 +-8 +-8 +-9 +-8 +-8 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-9 +-9 +-10 +-9 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-34 +-23 +-17 +-15 +-14 +-16 +-18 +-20 +-21 +-22 +-21 +-20 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-12 +-13 +-13 +-13 +-12 +-12 +-11 +-11 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-12 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +21 +76 +92 +91 +74 +53 +28 +9 +-7 +-15 +-20 +-18 +-15 +-11 +-7 +-2 +-1 +0 +1 +1 +-1 +-1 +-3 +-4 +-5 +-5 +-7 +-6 +-6 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-16 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-13 +19 +73 +89 +89 +72 +51 +26 +8 +-7 +-17 +-20 +-19 +-17 +-11 +-7 +-3 +-1 +1 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-8 +-7 +-7 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-34 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-17 +-16 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +22 +76 +92 +90 +74 +52 +28 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +1 +0 +-1 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-33 +-71 +-96 +-97 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-19 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-16 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-19 +-16 +-12 +-7 +-3 +-2 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-6 +-33 +-71 +-96 +-97 +-84 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-3 +-4 +-5 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-79 +-83 +-65 +-48 +-32 +-23 +-16 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +20 +74 +90 +88 +72 +51 +27 +8 +-7 +-16 +-20 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-3 +-5 +-6 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +20 +73 +90 +89 +71 +51 +26 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +-1 +0 +0 +-2 +-2 +-4 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-12 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-7 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-79 +-84 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-12 +19 +73 +89 +88 +71 +51 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-13 +-13 +-15 +-16 +-19 +-20 +-21 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +89 +71 +51 +26 +7 +-7 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-6 +-6 +-7 +-7 +-32 +-71 +-96 +-80 +-84 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-31 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-19 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +19 +74 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-7 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-20 +-20 +-21 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-20 +-20 +-17 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-17 +-18 +-15 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +71 +51 +27 +7 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-8 +-7 +-7 +-8 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-33 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-20 +-21 +-19 +-19 +-17 +-17 +-16 +-15 +-15 +-14 +-13 +-14 +-13 +-14 +-13 +18 +73 +89 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-79 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-17 +-20 +-20 +-21 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-16 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +73 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-7 +-3 +-1 +1 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-15 +-17 +-18 +-20 +-20 +-19 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +22 +75 +92 +91 +75 +53 +29 +9 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-3 +-5 +-5 +-6 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-12 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-12 +-7 +-4 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-8 +-9 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-33 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-16 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-12 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +22 +76 +92 +91 +74 +53 +28 +9 +-6 +-16 +-19 +-18 +-16 +-11 +-7 +-3 +-1 +1 +1 +0 +-1 +-1 +-4 +-4 +-5 +-6 +-6 +-6 +-6 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-16 +-16 +-19 +-19 +-20 +-19 +-20 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +7 +-9 +-17 +-20 +-19 +-17 +-11 +-7 +-4 +-1 +0 +-1 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-15 +-17 +-19 +-20 +-20 +-19 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +90 +88 +72 +51 +27 +8 +-7 +-17 +-21 +-20 +-17 +-12 +-7 +-3 +-2 +0 +0 +-1 +-1 +-2 +-4 +-5 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-7 +-8 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-99 +-99 +-85 +-67 +-50 +-34 +-23 +-17 +-15 +-14 +-17 +-18 +-20 +-21 +-21 +-20 +-21 +-19 +-18 +-17 +-17 +-16 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +18 +72 +89 +88 +72 +51 +27 +8 +-8 +-17 +-21 +-20 +-17 +-12 +-7 +-3 +-2 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-10 +-11 +-11 +22 +76 +92 +91 +74 +53 +29 +9 +-6 +-15 +-19 +-17 +-16 +-11 +-6 +-3 +-1 +1 +0 +0 +-1 +-1 +-3 +-3 +-5 +-6 +-7 +-6 +-8 +-7 +-7 +-6 +-7 +-7 +-7 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-85 +-66 +-49 +-34 +-24 +-17 +-15 +-14 +-16 +-17 +-19 +-20 +-22 +-21 +-21 +-19 +-18 +-17 +-17 +-15 +-15 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +-1 +-1 +-1 +-2 +-3 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-97 +-97 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-12 +-13 +-12 +-12 +-11 +-12 +-10 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-11 +-10 +-10 +-10 +-9 +22 +76 +93 +91 +74 +53 +29 +9 +-6 +-15 +-19 +-18 +-16 +-12 +-8 +-3 +-1 +1 +1 +1 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-16 +-16 +-18 +-20 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-14 +-14 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +74 +90 +88 +72 +51 +27 +8 +-7 +-17 +-21 +-19 +-16 +-12 +-8 +-3 +-3 +0 +0 +0 +-1 +-1 +-4 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-6 +-33 +-71 +-96 +-97 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +-14 +-13 +20 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-8 +-9 +-8 +-9 +-8 +-8 +-9 +-9 +-8 +-10 +-10 +-10 +-9 +-10 +-9 +-9 +-10 +-10 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-36 +-74 +-99 +-99 +-85 +-66 +-49 +-34 +-24 +-17 +-15 +-15 +-16 +-18 +-20 +-20 +-21 +-21 +-20 +-19 +-19 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-14 +-13 +-12 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-10 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +22 +75 +91 +90 +73 +53 +29 +9 +-6 +-15 +-19 +-18 +-16 +-11 +-7 +-2 +0 +2 +1 +0 +-1 +-2 +-4 +-3 +-5 +-6 +-6 +-6 +-7 +-7 +-8 +-7 +-8 +-7 +-7 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-33 +-23 +-17 +-15 +-15 +-16 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-19 +-17 +-17 +-16 +-16 +-14 +-15 +-13 +-14 +-14 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-22 +-20 +-16 +-11 +-8 +-3 +-2 +-1 +-1 +-1 +-2 +-2 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-21 +-19 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-7 +-16 +-21 +-19 +-17 +-12 +-7 +-3 +-1 +0 +0 +-1 +-2 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-19 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-12 +20 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-4 +-2 +0 +1 +1 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-7 +-7 +-6 +-7 +-7 +-32 +-71 +-97 +-80 +-83 +-65 +-48 +-33 +-23 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-14 +-14 +-14 +-14 +-14 +-14 +-14 +-12 +19 +73 +90 +89 +72 +51 +27 +8 +-7 +-16 +-20 +-19 +-16 +-12 +-8 +-4 +-3 +0 +0 +0 +-1 +-1 +-3 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-32 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-14 +-13 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-20 +-20 +-16 +-12 +-8 +-4 +-2 +-1 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-6 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +-14 +-13 +-13 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-12 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +22 +76 +92 +92 +74 +52 +28 +8 +-7 +-15 +-19 +-19 +-15 +-10 +-7 +-3 +-1 +0 +0 +1 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-11 +-10 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-49 +-35 +-24 +-17 +-16 +-14 +-16 +-18 +-20 +-20 +-22 +-21 +-21 +-19 +-19 +-17 +-16 +-16 +-15 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +-12 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-11 +-11 +-10 +-9 +-10 +-10 +22 +75 +92 +91 +73 +52 +29 +10 +-6 +-15 +-19 +-19 +-16 +-11 +-7 +-2 +0 +1 +1 +1 +-1 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-6 +-8 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-11 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-23 +-17 +-16 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-19 +-17 +-17 +-16 +-16 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +19 +72 +89 +89 +71 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +-1 +-1 +0 +-2 +-2 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-66 +-48 +-32 +-23 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-12 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +91 +74 +53 +29 +9 +-6 +-15 +-20 +-18 +-15 +-11 +-7 +-3 +-1 +0 +0 +1 +-1 +-1 +-3 +-5 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-6 +-31 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-21 +-20 +-18 +-17 +-16 +-16 +-15 +-16 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-17 +-20 +-20 +-17 +-11 +-7 +-3 +-1 +0 +-1 +0 +-1 +-3 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-10 +-9 +-9 +-9 +-10 +-9 +-11 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-24 +-17 +-15 +-15 +-17 +-18 +-20 +-21 +-21 +-21 +-20 +-19 +-19 +-17 +-17 +-16 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +89 +72 +50 +27 +7 +-9 +-17 +-21 +-20 +-17 +-11 +-8 +-3 +-1 +1 +0 +0 +-1 +-3 +-3 +-4 +-6 +-6 +-7 +-7 +-8 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-20 +-21 +-19 +-20 +-18 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +72 +51 +27 +8 +-8 +-17 +-21 +-19 +-17 +-11 +-7 +-4 +-1 +0 +0 +0 +-2 +-2 +-4 +-4 +-5 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-20 +-21 +-21 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-4 +-1 +0 +-1 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-7 +-8 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-20 +-20 +-18 +-17 +-16 +-16 +-14 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +51 +26 +8 +-7 +-16 +-20 +-19 +-17 +-11 +-8 +-3 +-1 +0 +0 +1 +-1 +-2 +-4 +-5 +-7 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-16 +-19 +-19 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +74 +89 +89 +72 +50 +27 +7 +-8 +-17 +-20 +-19 +-16 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-16 +-17 +-18 +-20 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-11 +-7 +-3 +-2 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-16 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +73 +51 +27 +8 +-8 +-17 +-20 +-19 +-17 +-11 +-7 +-4 +-1 +0 +-1 +-1 +-1 +-1 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-19 +-17 +-16 +-16 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-12 +19 +73 +89 +88 +72 +51 +26 +7 +-8 +-17 +-20 +-19 +-16 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-7 +-7 +-7 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-13 +-15 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +-12 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +-11 +-11 +-11 +-10 +22 +76 +92 +90 +74 +53 +28 +9 +-6 +-16 +-20 +-18 +-15 +-11 +-7 +-3 +-1 +0 +1 +1 +-1 +-1 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-97 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-17 +-20 +-19 +-17 +-12 +-7 +-3 +-1 +0 +-1 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-17 +-16 +-16 +-15 +-15 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +19 +73 +90 +88 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-7 +-3 +-1 +1 +1 +0 +-2 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +51 +27 +8 +-8 +-17 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-5 +-5 +-6 +-6 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-15 +-14 +-14 +-15 +-13 +-13 +-14 +-14 +-12 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-16 +-12 +-7 +-3 +-2 +0 +0 +0 +-1 +-1 +-3 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +51 +26 +7 +-8 +-17 +-21 +-19 +-17 +-11 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-35 +-73 +-98 +-98 +-86 +-67 +-49 +-34 +-23 +-17 +-15 +-14 +-17 +-19 +-20 +-20 +-21 +-20 +-20 +-19 +-19 +-17 +-17 +-16 +-15 +-14 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-10 +22 +77 +92 +90 +74 +52 +28 +9 +-6 +-16 +-19 +-18 +-16 +-11 +-7 +-3 +-2 +1 +1 +1 +-1 +-1 +-4 +-4 +-5 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-18 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-14 +-14 +-15 +-14 +-14 +-14 +-14 +-12 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +1 +-1 +-2 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-8 +-9 +-10 +-10 +-9 +-11 +-10 +-10 +-11 +-10 +-9 +-10 +-10 +-10 +-10 +-36 +-74 +-99 +-98 +-85 +-67 +-50 +-34 +-24 +-17 +-16 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-20 +-19 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-12 +-11 +-10 +-10 +-10 +-10 +22 +75 +92 +91 +74 +53 +29 +8 +-6 +-15 +-19 +-18 +-15 +-10 +-7 +-3 +-1 +1 +0 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-64 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-18 +-19 +-21 +-20 +-20 +-19 +-18 +-16 +-16 +-15 +-14 +-13 +-14 +-13 +-14 +-13 +-13 +-12 +20 +73 +90 +88 +71 +50 +26 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-8 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-21 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +74 +90 +90 +71 +51 +27 +8 +-8 +-17 +-20 +-19 +-16 +-11 +-8 +-3 +-2 +-1 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-6 +-33 +-71 +-96 +-80 +-83 +-64 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-19 +-18 +-17 +-16 +-15 +-15 +-13 +-14 +-13 +-14 +-13 +-14 +-12 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-21 +-19 +-16 +-12 +-8 +-4 +-2 +-1 +-1 +-1 +-2 +-2 +-3 +-5 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-48 +-33 +-22 +-16 +-14 +-14 +-15 +-17 +-20 +-19 +-20 +-20 +-19 +-17 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-14 +-13 +19 +72 +89 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-20 +-16 +-11 +-8 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-4 +-5 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-16 +-17 +-19 +-19 +-21 +-20 +-20 +-18 +-18 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +88 +71 +51 +27 +8 +-7 +-16 +-21 +-19 +-17 +-12 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-32 +-23 +-16 +-13 +-14 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-14 +-13 +20 +73 +90 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-20 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-4 +-5 +-6 +-6 +-7 +-6 +-6 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-16 +-17 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-17 +-16 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-14 +-12 +19 +73 +90 +89 +71 +51 +27 +7 +-8 +-16 +-20 +-19 +-17 +-12 +-9 +-4 +-2 +0 +0 +0 +-2 +-2 +-3 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-33 +-71 +-97 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-19 +-19 +-19 +-17 +-17 +-17 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +89 +89 +73 +51 +27 +7 +-9 +-17 +-21 +-19 +-16 +-11 +-8 +-3 +-2 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-5 +-7 +-6 +-7 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-18 +-18 +-17 +-16 +-16 +-15 +-14 +-14 +-13 +-13 +-12 +-14 +-13 +19 +73 +89 +89 +71 +51 +27 +8 +-8 +-17 +-21 +-20 +-16 +-12 +-8 +-3 +-1 +0 +-1 +0 +-2 +-3 +-4 +-4 +-6 +-5 +-7 +-7 +-8 +-7 +-8 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-48 +-32 +-23 +-15 +-13 +-14 +-15 +-16 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-16 +-16 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +50 +27 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-8 +-3 +-1 +1 +1 +0 +-2 +-2 +-4 +-5 +-5 +-5 +-7 +-7 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-80 +-84 +-65 +-47 +-33 +-22 +-16 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +20 +73 +89 +88 +72 +51 +27 +8 +-8 +-17 +-20 +-20 +-17 +-12 +-9 +-4 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-17 +-19 +-20 +-20 +-19 +-20 +-18 +-17 +-17 +-16 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +1 +-1 +-2 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-7 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-10 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-11 +-10 +-9 +-10 +-10 +-10 +-11 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-50 +-34 +-24 +-17 +-14 +-15 +-16 +-17 +-20 +-21 +-21 +-21 +-21 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +19 +73 +89 +88 +71 +49 +27 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-4 +-1 +1 +-1 +0 +-2 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-33 +-71 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-19 +-17 +-16 +-14 +-14 +-13 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-9 +-17 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-32 +-71 +-97 +-80 +-83 +-65 +-47 +-31 +-22 +-16 +-14 +-13 +-16 +-17 +-19 +-19 +-20 +-19 +-20 +-19 +-18 +-17 +-17 +-15 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-10 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-12 +-10 +-10 +-10 +22 +77 +92 +91 +74 +52 +28 +9 +-7 +-15 +-19 +-19 +-16 +-11 +-8 +-3 +-1 +0 +1 +1 +-1 +-1 +-3 +-4 +-6 +-5 +-6 +-6 +-7 +-6 +-8 +-7 +-32 +-70 +-96 +-80 +-83 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-15 +-16 +-18 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +51 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-7 +-4 +-2 +0 +-1 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-8 +-7 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-9 +-9 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-15 +-16 +-17 +-20 +-20 +-21 +-20 +-21 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-15 +-15 +-14 +-13 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-13 +-13 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +22 +76 +91 +91 +74 +52 +29 +9 +-6 +-16 +-19 +-18 +-16 +-10 +-6 +-3 +-1 +1 +0 +0 +-1 +-2 +-4 +-3 +-5 +-5 +-6 +-6 +-8 +-7 +-7 +-7 +-33 +-70 +-96 +-80 +-83 +-65 +-48 +-32 +-22 +-16 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +19 +73 +89 +89 +72 +50 +27 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-32 +-22 +-16 +-13 +-13 +-15 +-16 +-18 +-19 +-20 +-19 +-20 +-18 +-17 +-16 +-16 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +74 +90 +89 +72 +51 +26 +7 +-8 +-16 +-20 +-19 +-17 +-12 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-5 +-6 +-7 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-8 +-8 +-7 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-98 +-85 +-67 +-49 +-34 +-24 +-17 +-15 +-14 +-16 +-17 +-19 +-21 +-21 +-21 +-21 +-19 +-18 +-17 +-17 +-15 +-16 +-15 +-15 +-14 +-15 +-13 +-13 +-13 +19 +73 +88 +88 +71 +50 +27 +8 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-1 +-2 +-5 +-5 +-5 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-83 +-64 +-47 +-32 +-22 +-16 +-14 +-13 +-15 +-16 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-16 +-17 +-15 +-14 +-14 +-14 +-14 +-14 +-13 +-13 +-12 +-13 +-12 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-11 +-11 +-10 +-10 +-9 +-10 +-10 +22 +76 +91 +91 +74 +52 +29 +9 +-7 +-15 +-19 +-18 +-16 +-11 +-7 +-2 +0 +1 +0 +0 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-9 +-35 +-73 +-98 +-99 +-86 +-67 +-49 +-34 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-22 +-20 +-20 +-19 +-18 +-17 +-17 +-16 +-15 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +18 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-20 +-16 +-12 +-7 +-3 +-1 +0 +0 +-1 +-2 +-2 +-4 +-4 +-6 +-6 +-6 +-6 +-8 +-7 +-7 +-7 +-32 +-70 +-97 +-80 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-20 +-21 +-20 +-20 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-11 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-10 +-11 +-10 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +22 +76 +92 +90 +74 +52 +28 +9 +-6 +-15 +-20 +-18 +-15 +-11 +-7 +-3 +-2 +0 +0 +0 +-1 +-1 +-3 +-4 +-5 +-5 +-7 +-6 +-6 +-7 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +90 +89 +73 +51 +27 +8 +-7 +-17 +-20 +-19 +-17 +-11 +-7 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-7 +-7 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-97 +-83 +-65 +-48 +-32 +-22 +-15 +-13 +-13 +-16 +-17 +-19 +-19 +-21 +-19 +-19 +-19 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +88 +72 +51 +27 +8 +-7 +-16 +-21 +-20 +-17 +-12 +-8 +-3 +-1 +0 +0 +0 +-2 +-2 +-3 +-4 +-5 +-5 +-7 +-7 +-7 +-7 +-8 +-7 +-7 +-7 +-8 +-7 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-9 +-9 +-10 +-9 +-10 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-33 +-23 +-17 +-15 +-15 +-17 +-18 +-20 +-20 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-16 +-15 +-15 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-12 +-11 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +22 +76 +92 +91 +74 +53 +28 +8 +-6 +-14 +-19 +-18 +-15 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-1 +-3 +-5 +-6 +-5 +-7 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-9 +-10 +-10 +-10 +-10 +-11 +-11 +-10 +-10 +-35 +-73 +-98 +-99 +-86 +-67 +-50 +-34 +-24 +-17 +-15 +-14 +-16 +-18 +-20 +-20 +-22 +-21 +-20 +-19 +-18 +-17 +-17 +-16 +-15 +-15 +-15 +-14 +-14 +-13 +-13 +-12 +19 +73 +89 +88 +71 +51 +27 +7 +-7 +-16 +-21 +-19 +-17 +-13 +-8 +-4 +-2 +0 +0 +0 +-2 +-2 +-4 +-5 +-6 +-5 +-7 +-6 +-7 +-7 +-8 +-7 +-32 +-71 +-96 +-80 +-83 +-64 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-16 +-19 +-19 +-20 +-21 +-20 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +89 +88 +71 +51 +27 +8 +-7 +-16 +-20 +-19 +-17 +-12 +-7 +-4 +-2 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-7 +-6 +-7 +-7 +-7 +-7 +-33 +-71 +-96 +-97 +-84 +-65 +-48 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-20 +-19 +-19 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-14 +-13 +-13 +-13 +-13 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-17 +-21 +-19 +-17 +-12 +-8 +-3 +-2 +0 +0 +0 +-2 +-2 +-3 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-6 +-32 +-70 +-96 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-17 +-16 +-15 +-16 +-14 +-14 +-14 +-13 +-12 +-13 +-13 +19 +73 +89 +89 +72 +51 +27 +8 +-8 +-17 +-21 +-19 +-17 +-12 +-7 +-3 +-2 +0 +0 +-1 +-1 +-2 +-4 +-4 +-5 +-5 +-7 +-6 +-7 +-7 +-7 +-6 +-33 +-71 +-96 +-97 +-83 +-65 +-47 +-32 +-22 +-15 +-14 +-13 +-15 +-17 +-19 +-19 +-21 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-15 +-14 +-13 +-13 +-13 +-12 +19 +73 +89 +89 +71 +51 +27 +7 +-7 +-16 +-21 +-19 +-17 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-2 +-3 +-5 +-6 +-5 +-6 +-6 +-6 +-7 +-8 +-7 +-33 +-71 +-97 +-80 +-84 +-65 +-47 +-32 +-22 +-15 +-14 +-14 +-15 +-17 +-19 +-20 +-20 +-21 +-20 +-19 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-10 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-9 +22 +76 +92 +91 +73 +52 +29 +9 +-6 +-15 +-20 +-19 +-16 +-11 +-7 +-2 +0 +1 +0 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-6 +-6 +-6 +-8 +-7 +-7 +-7 +-7 +-7 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-8 +-10 +-9 +-10 +-10 +-10 +-9 +-9 +-9 +-10 +-9 +-11 +-10 +-10 +-11 +-10 +-10 +-10 +-10 +-35 +-73 +-99 +-99 +-86 +-67 +-49 +-33 +-24 +-17 +-15 +-14 +-17 +-18 +-20 +-21 +-21 +-20 +-21 +-19 +-18 +-18 +-17 +-16 +-16 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-11 +-12 +-12 +-12 +-11 +-12 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-10 +-9 +-10 +-10 +22 +75 +92 +91 +73 +52 +28 +8 +-7 +-15 +-19 +-18 +-15 +-11 +-7 +-3 +-1 +1 +1 +1 +-1 +-2 +-3 +-4 +-5 +-5 +-6 +-7 +-7 +-6 +-7 +-6 +-7 +-7 +-8 +-7 +-8 +-9 +-8 +-8 +-9 +-8 +-9 +-9 +-10 +-9 +-10 +-10 +-9 +-9 +-10 +-9 +-10 +-10 +-11 +-10 +-11 +-10 +-10 +-9 +-11 +-10 +-10 +-10 +-35 +-72 +-99 +-98 +-85 +-67 +-50 +-34 +-24 +-17 +-15 +-14 +-16 +-17 +-19 +-21 +-22 +-21 +-21 +-19 +-18 +-17 +-17 +-15 +-15 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +19 +72 +89 +88 +71 +50 +27 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-4 +-2 +0 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 +-6 +-6 +-6 +-6 +-7 +-7 +-32 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-23 +-16 +-14 +-14 +-15 +-16 +-18 +-19 +-20 +-19 +-20 +-19 +-18 +-16 +-16 +-14 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-13 +-13 +-12 +-12 +-12 +-12 +-12 +-13 +-11 +-12 +-11 +-12 +-10 +-12 +-11 +-11 +-11 +-11 +-10 +-11 +-10 +-10 +-10 +-11 +-10 +-10 +-11 +-11 +-10 +-10 +-10 +-10 +-10 +21 +75 +92 +90 +74 +53 +29 +9 +-6 +-15 +-20 +-19 +-16 +-12 +-7 +-3 +-1 +2 +1 +0 +-1 +-2 +-4 +-4 +-5 +-5 +-6 +-6 +-7 +-7 +-7 +-7 +-32 +-70 +-96 +-79 +-83 +-65 +-47 +-33 +-22 +-15 +-14 +-13 +-14 +-16 +-19 +-19 +-20 +-20 +-20 +-18 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-13 +-13 +-13 +-12 +20 +73 +89 +88 +71 +50 +26 +8 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +0 +0 +0 +-1 +-2 +-4 +-4 +-6 +-6 +-6 +-7 +-7 +-6 +-8 +-7 +-8 +-7 +-9 +-8 +-8 +-8 +-8 +-8 +-9 +-9 +-10 +-10 +-10 +-9 +-10 +-9 +-9 +-9 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-10 +-11 +-10 +-11 +-10 +-35 +-73 +-98 +-98 +-85 +-67 +-50 +-34 +-24 +-17 +-15 +-14 +-17 +-18 +-19 +-21 +-22 +-21 +-20 +-18 +-18 +-17 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-13 +-14 +-12 +19 +73 +89 +89 +71 +50 +26 +7 +-8 +-16 +-21 +-20 +-17 +-12 +-8 +-4 +-1 +0 +0 +0 +-2 +-3 +-4 +-5 +-6 +-6 +-7 +-7 +-7 +-6 +-8 +-7 +-33 +-71 +-97 +-80 +-83 +-65 +-47 +-32 +-23 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-20 +-19 +-18 +-17 +-16 +-14 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +74 +89 +89 +72 +50 +26 +7 +-8 +-17 +-20 +-19 +-17 +-12 +-8 +-5 +-2 +0 +-1 +0 +-1 +-2 +-3 +-4 +-5 +-6 +-6 +-6 +-7 +-6 +-7 +-7 +-32 +-71 +-97 +-97 +-84 +-65 +-48 +-32 +-22 +-16 +-13 +-13 +-16 +-17 +-18 +-19 +-20 +-19 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-14 +-13 +19 +73 +90 +89 +72 +51 +27 +7 +-8 +-16 +-20 +-19 +-16 +-11 +-8 +-3 +-1 +-1 +-1 +0 +-1 +-2 +-3 +-4 +-6 +-6 +-7 +-7 +-7 +-6 +-7 +-7 +-32 +-70 +-96 +-97 +-84 +-65 +-47 +-32 +-22 +-15 +-13 +-14 +-16 +-17 +-20 +-20 +-21 +-19 +-20 +-17 +-17 +-17 +-16 +-15 +-16 +-15 +-14 +-13 +-14 +-13 +-13 +-13 +19 +73 +89 +89 +72 +50 +27 +8 +-7 +-17 +-20 +-19 +-17 +-11 +-7 +-3 +-1 +1 +0 +-1 +-1 +-2 +-5 +-4 +-5 +-6 +-6 +-6 +-7 +-7 +-7 +-8 +-33 +-71 +-96 +-80 +-83 +-65 +-48 +-33 +-22 +-15 +-13 +-13 +-15 +-17 +-19 +-19 +-20 +-20 +-19 +-17 +-18 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-14 +-13 +-13 +-13 +20 +73 +89 +88 +71 +50 +27 +8 +-8 +-16 +-20 +-20 +-17 +-11 +-8 +-3 +-1 +1 +0 +0 +-1 +-3 +-4 +-4 +-6 +-6 \ No newline at end of file diff --git a/traces/indala-504278295.pm3 b/traces/indala-504278295.pm3 new file mode 100644 index 00000000..9383bab3 --- /dev/null +++ b/traces/indala-504278295.pm3 @@ -0,0 +1,20000 @@ +-22 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-21 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +29 +-6 +33 +-2 +10 +-22 +10 +-22 +8 +-23 +9 +-23 +9 +-22 +8 +-24 +9 +-22 +9 +-22 +9 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +120 +68 +28 +-9 +1 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +-51 +26 +-8 +30 +-5 +8 +-23 +7 +-24 +7 +-24 +8 +-24 +7 +-25 +8 +-24 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +120 +68 +27 +-9 +0 +-32 +-4 +-35 +-4 +-35 +-1 +-33 +0 +-32 +2 +-30 +2 +-30 +3 +-29 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +7 +-26 +8 +-25 +8 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-24 +11 +-23 +11 +-23 +11 +-23 +11 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-3 +10 +-21 +9 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +9 +-23 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-2 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +5 +-28 +5 +-27 +6 +-27 +7 +-26 +6 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +11 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +-49 +29 +-5 +33 +-2 +10 +-22 +9 +-22 +8 +-24 +9 +-22 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +120 +68 +27 +-9 +-1 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +1 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +11 +-23 +11 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +-49 +29 +-5 +32 +-3 +10 +-22 +9 +-22 +8 +-24 +9 +-22 +8 +-23 +8 +-23 +9 +-23 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +11 +-21 +9 +-22 +10 +-21 +10 +-22 +11 +-21 +11 +-21 +10 +-21 +10 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +11 +-21 +10 +-22 +11 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +11 +-22 +11 +-21 +11 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +10 +120 +68 +27 +-9 +1 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +5 +-28 +5 +-28 +5 +-27 +6 +-26 +7 +-26 +8 +-24 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-23 +9 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +9 +-23 +10 +-21 +10 +120 +69 +28 +-8 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +-51 +26 +-8 +30 +-5 +8 +-24 +8 +-24 +7 +-24 +8 +-24 +8 +-24 +8 +-24 +8 +-23 +8 +-23 +10 +-22 +9 +-23 +9 +-23 +10 +-22 +10 +-22 +10 +120 +68 +27 +-9 +0 +-32 +-4 +-35 +-4 +-35 +-2 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +4 +-28 +6 +-27 +6 +-27 +7 +-26 +8 +-25 +7 +-26 +9 +-24 +8 +-25 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-22 +8 +-24 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +9 +-23 +10 +120 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-35 +-2 +-33 +0 +-32 +2 +-30 +3 +-29 +5 +-28 +5 +-27 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +-51 +27 +-7 +31 +-5 +8 +-23 +8 +-24 +7 +-24 +7 +-24 +8 +-24 +8 +-23 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +8 +-23 +9 +-22 +9 +119 +68 +27 +-9 +0 +-31 +-3 +-35 +-3 +-35 +-2 +-33 +0 +-31 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +6 +-26 +6 +-26 +7 +-26 +7 +-25 +8 +-25 +-51 +27 +-7 +30 +-5 +8 +-23 +6 +-25 +7 +-25 +8 +-24 +8 +-24 +9 +-23 +8 +-23 +8 +-23 +9 +-22 +8 +-23 +10 +-22 +9 +-22 +9 +-23 +9 +119 +68 +27 +-9 +-1 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +1 +-31 +3 +-29 +4 +-28 +5 +-28 +6 +-27 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +10 +-23 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +32 +-3 +9 +-22 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +9 +-23 +10 +120 +68 +27 +-9 +0 +-31 +-3 +-35 +-4 +-35 +-1 +-33 +0 +-32 +2 +-30 +3 +-30 +4 +-28 +5 +-28 +6 +-26 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +-51 +28 +-7 +31 +-4 +8 +-24 +7 +-24 +7 +-25 +8 +-24 +8 +-23 +8 +-23 +8 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-22 +9 +-22 +9 +119 +68 +28 +-9 +-1 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +3 +-29 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +7 +-25 +9 +-24 +10 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-21 +9 +-23 +8 +-24 +9 +-22 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +-21 +10 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +3 +-29 +5 +-28 +6 +-27 +6 +-26 +7 +-26 +7 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +11 +-23 +11 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-23 +8 +-24 +9 +-23 +9 +-23 +8 +-23 +9 +-22 +10 +-22 +9 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-21 +9 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-32 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-25 +8 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +-49 +29 +-6 +33 +-3 +10 +-21 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +8 +-23 +10 +-22 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +9 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +11 +-21 +10 +-22 +9 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-21 +11 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +11 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +120 +69 +28 +-8 +-1 +-32 +-3 +-34 +-2 +-34 +-1 +-33 +1 +-31 +2 +-30 +3 +-29 +5 +-28 +5 +-27 +6 +-27 +6 +-26 +7 +-25 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-22 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +119 +68 +27 +-9 +1 +-31 +-4 +-35 +-3 +-34 +-2 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +6 +-26 +7 +-25 +8 +-26 +8 +-25 +-51 +27 +-8 +31 +-4 +8 +-23 +7 +-25 +7 +-24 +8 +-24 +8 +-24 +8 +-23 +8 +-24 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +9 +120 +68 +28 +-9 +0 +-32 +-3 +-34 +-4 +-35 +-2 +-33 +0 +-32 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +11 +-22 +9 +-24 +10 +-23 +11 +-23 +10 +-23 +11 +-23 +11 +-23 +11 +-23 +11 +-22 +-49 +29 +-5 +33 +-3 +10 +-22 +9 +-23 +8 +-24 +9 +-22 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-3 +-34 +-3 +-34 +-1 +-33 +0 +-32 +1 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-26 +6 +-27 +7 +-26 +8 +-25 +8 +-25 +-51 +28 +-7 +31 +-4 +8 +-24 +7 +-24 +6 +-25 +7 +-24 +8 +-24 +8 +-24 +8 +-23 +8 +-24 +8 +-23 +9 +-23 +9 +-22 +10 +-22 +9 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +2 +-30 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +7 +-26 +8 +-25 +-51 +28 +-7 +31 +-4 +8 +-23 +7 +-25 +6 +-25 +7 +-24 +8 +-24 +8 +-23 +8 +-23 +9 +-22 +8 +-23 +9 +-23 +10 +-22 +8 +-23 +10 +-22 +9 +119 +68 +28 +-9 +-1 +-32 +-4 +-35 +-4 +-35 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +6 +-26 +6 +-27 +7 +-25 +8 +-25 +8 +-25 +9 +-24 +8 +-25 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-24 +11 +-23 +11 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-21 +11 +-23 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +31 +-4 +33 +-2 +10 +-22 +8 +-23 +8 +-23 +8 +-24 +8 +-23 +9 +-22 +9 +-22 +9 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-9 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-32 +0 +-31 +1 +-30 +3 +-29 +3 +-29 +5 +-27 +6 +-27 +6 +-27 +7 +-25 +7 +-25 +7 +-25 +-52 +27 +-7 +31 +-5 +8 +-24 +8 +-24 +6 +-25 +8 +-24 +8 +-23 +8 +-24 +8 +-23 +8 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-22 +9 +-23 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-2 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +6 +-27 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-24 +9 +-24 +9 +-24 +10 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-8 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-32 +0 +-32 +1 +-30 +3 +-29 +3 +-29 +5 +-27 +5 +-27 +6 +-26 +7 +-25 +7 +-26 +8 +-24 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-24 +10 +-23 +10 +-24 +11 +-22 +11 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-21 +9 +-23 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +1 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-24 +8 +-25 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +-49 +29 +-5 +33 +-3 +10 +-22 +9 +-22 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +11 +-21 +11 +-21 +10 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +11 +-21 +11 +-21 +10 +120 +69 +28 +-8 +1 +-31 +-4 +-35 +-3 +-34 +-1 +-32 +0 +-31 +1 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +7 +-26 +7 +-26 +7 +-26 +8 +-24 +8 +-25 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-21 +9 +-23 +8 +-24 +9 +-23 +9 +-22 +10 +-22 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +68 +28 +-9 +-1 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +1 +-31 +1 +-31 +3 +-29 +4 +-28 +5 +-28 +6 +-26 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +-51 +28 +-7 +32 +-4 +8 +-23 +7 +-24 +6 +-26 +7 +-24 +8 +-24 +8 +-23 +9 +-23 +8 +-23 +8 +-23 +10 +-22 +9 +-22 +9 +-22 +9 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-35 +-1 +-33 +0 +-31 +1 +-30 +2 +-30 +4 +-28 +5 +-27 +6 +-27 +7 +-26 +7 +-26 +7 +-25 +8 +-25 +8 +-24 +8 +-25 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-23 +-49 +29 +-5 +34 +-2 +10 +-22 +9 +-23 +8 +-24 +8 +-24 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-8 +0 +-32 +-3 +-34 +-3 +-34 +-1 +-33 +0 +-31 +1 +-31 +3 +-29 +4 +-29 +5 +-28 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +-51 +27 +-7 +31 +-5 +9 +-23 +7 +-24 +7 +-25 +7 +-24 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +8 +-23 +8 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +120 +68 +28 +-8 +0 +-32 +-5 +-35 +-4 +-35 +-2 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +-52 +27 +-7 +32 +-4 +8 +-23 +8 +-24 +6 +-25 +8 +-24 +8 +-23 +7 +-25 +8 +-23 +8 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +9 +-22 +10 +119 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +7 +-26 +7 +-26 +7 +-26 +8 +-24 +9 +-24 +8 +-25 +9 +-24 +9 +-24 +10 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-21 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-22 +8 +-24 +8 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +9 +-22 +9 +-22 +10 +-22 +10 +120 +68 +28 +-9 +0 +-31 +-4 +-35 +-3 +-35 +-1 +-32 +0 +-32 +3 +-29 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +-51 +28 +-7 +31 +-4 +8 +-23 +7 +-24 +7 +-24 +7 +-24 +8 +-24 +8 +-23 +8 +-24 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-23 +9 +-22 +10 +120 +68 +27 +-9 +0 +-31 +-4 +-35 +-4 +-35 +-2 +-33 +-1 +-32 +1 +-31 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +6 +-27 +7 +-26 +8 +-25 +8 +-25 +8 +-24 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +11 +-23 +11 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +31 +-4 +32 +-3 +10 +-21 +9 +-23 +8 +-23 +9 +-22 +8 +-23 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-2 +-33 +1 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-24 +8 +-24 +9 +-24 +9 +-24 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +-48 +30 +-5 +33 +-3 +10 +-21 +9 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-9 +0 +-31 +-3 +-35 +-3 +-34 +-1 +-33 +0 +-32 +1 +-31 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +9 +-24 +8 +-24 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-3 +10 +-22 +9 +-23 +8 +-24 +9 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +10 +-22 +10 +-22 +11 +-21 +11 +-21 +9 +-22 +11 +-21 +10 +-22 +11 +-21 +10 +-21 +10 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +120 +69 +28 +-8 +0 +-32 +-3 +-34 +-3 +-34 +-1 +-33 +0 +-31 +1 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-25 +9 +-24 +8 +-25 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +-49 +29 +-5 +33 +-2 +10 +-21 +9 +-22 +8 +-23 +8 +-23 +8 +-23 +10 +-22 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +68 +28 +-9 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +1 +-30 +3 +-29 +4 +-29 +5 +-27 +5 +-28 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +-51 +28 +-7 +31 +-5 +8 +-24 +8 +-24 +7 +-25 +8 +-23 +7 +-24 +8 +-24 +8 +-23 +8 +-23 +9 +-22 +8 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +120 +68 +28 +-8 +-1 +-32 +-4 +-35 +-4 +-35 +-1 +-33 +1 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +6 +-27 +7 +-26 +8 +-25 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +-49 +29 +-5 +33 +-3 +10 +-22 +10 +-22 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +-51 +26 +-8 +32 +-4 +8 +-23 +8 +-24 +8 +-24 +7 +-24 +8 +-23 +8 +-24 +8 +-24 +9 +-23 +8 +-23 +9 +-22 +9 +-23 +9 +-23 +10 +-22 +9 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-4 +-35 +-2 +-33 +0 +-32 +1 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +6 +-26 +8 +-26 +9 +-24 +-51 +27 +-7 +30 +-5 +8 +-24 +7 +-24 +6 +-25 +8 +-24 +7 +-24 +8 +-24 +8 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +9 +-22 +9 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-30 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +8 +-25 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +12 +-22 +12 +-21 +12 +-22 +11 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +10 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +-49 +29 +-5 +32 +-3 +10 +-21 +9 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-3 +-34 +-3 +-34 +-1 +-33 +0 +-31 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +-51 +27 +-7 +31 +-4 +7 +-24 +7 +-24 +6 +-25 +8 +-24 +8 +-23 +8 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +9 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +3 +-29 +5 +-27 +5 +-27 +6 +-27 +7 +-26 +7 +-25 +8 +-25 +8 +-25 +9 +-24 +10 +-24 +10 +-24 +10 +-23 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-23 +12 +-21 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +-49 +29 +-6 +33 +-3 +10 +-22 +9 +-23 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-9 +0 +-32 +-4 +-35 +-3 +-35 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-29 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +29 +-5 +33 +-2 +10 +-22 +9 +-23 +8 +-24 +8 +-23 +10 +-22 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +68 +28 +-9 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +2 +-30 +4 +-28 +5 +-27 +6 +-27 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +10 +-23 +9 +-24 +10 +-23 +11 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +-49 +30 +-5 +33 +-3 +10 +-22 +9 +-23 +8 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +11 +-21 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +11 +-21 +10 +-21 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +10 +120 +69 +28 +-8 +0 +-32 +-3 +-34 +-3 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +7 +-26 +7 +-26 +7 +-26 +8 +-25 +9 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-22 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +9 +-23 +10 +119 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-2 +-33 +1 +-31 +1 +-30 +3 +-29 +5 +-27 +4 +-28 +6 +-27 +6 +-26 +7 +-26 +7 +-25 +8 +-25 +-51 +26 +-8 +30 +-5 +8 +-23 +7 +-24 +7 +-25 +8 +-24 +8 +-23 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +9 +-23 +10 +-22 +9 +119 +68 +27 +-9 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-30 +4 +-28 +5 +-27 +6 +-27 +6 +-26 +6 +-26 +7 +-25 +8 +-25 +8 +-25 +9 +-24 +8 +-25 +10 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +11 +-23 +11 +-23 +10 +-23 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +-49 +29 +-5 +33 +-2 +10 +-22 +9 +-22 +9 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +9 +-22 +9 +-22 +10 +-22 +10 +120 +69 +28 +-9 +1 +-31 +-3 +-34 +-4 +-35 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +6 +-26 +8 +-25 +9 +-24 +-51 +26 +-8 +30 +-5 +8 +-23 +7 +-24 +6 +-25 +7 +-24 +8 +-24 +8 +-24 +9 +-23 +8 +-23 +8 +-23 +10 +-22 +9 +-23 +10 +-22 +9 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +2 +-30 +2 +-30 +3 +-30 +3 +-29 +5 +-28 +6 +-27 +6 +-27 +6 +-26 +7 +-26 +8 +-25 +-51 +27 +-7 +31 +-4 +8 +-23 +7 +-25 +6 +-25 +7 +-25 +8 +-24 +8 +-23 +8 +-24 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-2 +-33 +0 +-31 +2 +-30 +2 +-30 +4 +-28 +5 +-28 +6 +-27 +7 +-26 +7 +-26 +7 +-25 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-23 +12 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +10 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-21 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +12 +-21 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +-49 +29 +-5 +34 +-2 +11 +-21 +9 +-23 +8 +-23 +8 +-24 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +11 +121 +69 +28 +-8 +0 +-32 +-4 +-35 +-4 +-35 +-1 +-32 +0 +-31 +1 +-31 +2 +-30 +4 +-28 +5 +-28 +6 +-27 +7 +-26 +7 +-25 +7 +-26 +8 +-26 +-52 +28 +-6 +31 +-5 +8 +-23 +7 +-24 +6 +-25 +7 +-24 +7 +-24 +8 +-23 +9 +-23 +8 +-23 +8 +-23 +9 +-22 +9 +-23 +9 +-23 +10 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-35 +-1 +-33 +0 +-32 +1 +-30 +3 +-29 +4 +-29 +5 +-28 +6 +-27 +6 +-27 +7 +-26 +8 +-25 +8 +-25 +8 +-24 +8 +-25 +10 +-24 +10 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-24 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +-49 +29 +-5 +34 +-2 +9 +-23 +9 +-23 +7 +-24 +9 +-23 +10 +-22 +9 +-23 +9 +-22 +9 +-23 +9 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-21 +10 +120 +68 +27 +-9 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-32 +0 +-32 +2 +-30 +3 +-29 +4 +-29 +5 +-27 +5 +-27 +7 +-26 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-24 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-3 +11 +-21 +9 +-23 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +8 +-23 +9 +-22 +10 +-22 +10 +-22 +11 +-21 +9 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +1 +-31 +2 +-30 +3 +-29 +4 +-28 +4 +-28 +6 +-27 +7 +-26 +7 +-26 +7 +-25 +8 +-25 +8 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-23 +-49 +29 +-6 +33 +-2 +10 +-22 +9 +-23 +8 +-24 +9 +-23 +9 +-22 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +11 +-21 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-21 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +120 +69 +28 +-8 +0 +-31 +-4 +-35 +-2 +-34 +-1 +-32 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +7 +-26 +7 +-26 +7 +-25 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +29 +-6 +33 +-3 +11 +-21 +8 +-23 +8 +-24 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-8 +-1 +-33 +-4 +-35 +-3 +-34 +-1 +-32 +1 +-31 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +5 +-28 +6 +-26 +7 +-25 +7 +-26 +9 +-24 +-51 +28 +-7 +31 +-4 +8 +-24 +7 +-24 +6 +-25 +8 +-24 +8 +-24 +8 +-23 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-5 +-35 +-3 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +7 +-26 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +9 +-24 +10 +-23 +10 +-24 +11 +-23 +11 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +-49 +29 +-6 +33 +-3 +10 +-21 +9 +-23 +7 +-24 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-32 +0 +-32 +2 +-30 +3 +-30 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +6 +-26 +7 +-25 +8 +-25 +-51 +28 +-7 +30 +-5 +8 +-23 +7 +-24 +6 +-25 +7 +-24 +8 +-24 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +1 +-31 +2 +-30 +4 +-28 +5 +-28 +6 +-27 +6 +-27 +7 +-26 +7 +-26 +7 +-26 +-52 +27 +-8 +31 +-4 +8 +-23 +8 +-24 +6 +-25 +8 +-24 +8 +-24 +7 +-24 +8 +-23 +9 +-23 +9 +-22 +9 +-22 +9 +-23 +9 +-22 +10 +-22 +9 +119 +68 +27 +-9 +0 +-32 +-5 +-36 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-29 +4 +-28 +5 +-27 +7 +-26 +7 +-26 +7 +-25 +9 +-24 +8 +-25 +9 +-24 +10 +-24 +9 +-24 +10 +-24 +10 +-24 +10 +-23 +11 +-23 +11 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-3 +10 +-22 +9 +-22 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-8 +0 +-31 +-4 +-35 +-3 +-35 +-1 +-32 +0 +-32 +3 +-29 +3 +-29 +4 +-29 +4 +-28 +5 +-28 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +-51 +27 +-7 +31 +-4 +8 +-24 +7 +-24 +7 +-24 +7 +-25 +7 +-24 +8 +-24 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-23 +9 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-35 +-1 +-33 +0 +-32 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +-49 +30 +-5 +33 +-3 +10 +-22 +9 +-23 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +119 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-30 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +7 +-25 +8 +-25 +8 +-25 +8 +-24 +8 +-25 +9 +-24 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +10 +-24 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +29 +-5 +33 +-2 +10 +-22 +9 +-22 +9 +-23 +8 +-24 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +120 +69 +28 +-8 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +4 +-28 +5 +-27 +6 +-27 +7 +-25 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +-49 +29 +-6 +32 +-3 +10 +-22 +9 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +9 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +11 +-21 +10 +-22 +11 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +9 +-22 +10 +-21 +10 +-22 +11 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +120 +68 +28 +-8 +0 +-32 +-3 +-34 +-3 +-34 +-1 +-33 +0 +-31 +3 +-29 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-23 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +119 +68 +27 +-9 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +1 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +-51 +27 +-7 +31 +-4 +8 +-23 +7 +-24 +7 +-24 +7 +-24 +8 +-24 +8 +-23 +8 +-24 +9 +-22 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +120 +69 +28 +-8 +-1 +-32 +-4 +-35 +-4 +-35 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +3 +-29 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-25 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-23 +-49 +30 +-5 +33 +-3 +10 +-22 +9 +-23 +7 +-24 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +120 +68 +28 +-9 +-1 +-32 +-4 +-35 +-3 +-33 +-2 +-33 +1 +-31 +2 +-30 +3 +-29 +5 +-28 +5 +-28 +6 +-27 +7 +-26 +7 +-25 +7 +-25 +8 +-25 +-51 +27 +-8 +31 +-5 +8 +-23 +7 +-24 +7 +-25 +7 +-24 +8 +-24 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +9 +119 +68 +27 +-9 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +6 +-27 +7 +-26 +7 +-25 +9 +-24 +-51 +27 +-7 +30 +-5 +8 +-24 +8 +-24 +6 +-25 +8 +-24 +7 +-24 +8 +-24 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +9 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-2 +-33 +0 +-31 +1 +-30 +3 +-29 +4 +-28 +4 +-28 +6 +-27 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-24 +9 +-24 +10 +-23 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-21 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-21 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-21 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-21 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +-49 +29 +-5 +33 +-3 +10 +-22 +9 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +9 +119 +68 +28 +-9 +-1 +-32 +-3 +-34 +-3 +-35 +-2 +-33 +1 +-31 +1 +-30 +3 +-29 +5 +-28 +5 +-28 +6 +-27 +6 +-27 +7 +-26 +7 +-25 +8 +-25 +-51 +27 +-8 +31 +-4 +8 +-23 +7 +-24 +7 +-25 +8 +-24 +8 +-23 +8 +-24 +8 +-23 +8 +-23 +8 +-23 +9 +-22 +9 +-22 +9 +-22 +9 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +7 +-26 +7 +-26 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-24 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +12 +-22 +11 +-23 +11 +-23 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +-49 +31 +-4 +33 +-2 +10 +-22 +9 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +9 +-22 +10 +120 +69 +28 +-9 +0 +-32 +-3 +-35 +-4 +-35 +-1 +-33 +0 +-31 +1 +-30 +3 +-29 +4 +-28 +6 +-27 +6 +-26 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +11 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +-49 +29 +-6 +33 +-2 +10 +-22 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-22 +9 +-22 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +9 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-24 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +-49 +29 +-5 +33 +-3 +10 +-22 +9 +-23 +9 +-23 +8 +-23 +8 +-23 +8 +-23 +9 +-23 +9 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +11 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +120 +69 +28 +-8 +0 +-31 +-3 +-34 +-3 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +11 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +12 +-21 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +-49 +29 +-5 +33 +-3 +10 +-22 +9 +-22 +8 +-24 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +119 +68 +28 +-9 +0 +-32 +-5 +-35 +-2 +-34 +-1 +-33 +0 +-31 +2 +-30 +3 +-29 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +8 +-25 +7 +-26 +8 +-25 +-51 +27 +-8 +31 +-4 +8 +-24 +7 +-24 +7 +-24 +8 +-24 +7 +-24 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +10 +-22 +9 +119 +68 +28 +-9 +-1 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +-1 +-33 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-28 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-23 +8 +-23 +8 +-23 +9 +-23 +10 +-22 +9 +-23 +9 +-22 +10 +-22 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-8 +0 +-32 +-4 +-35 +-3 +-35 +-2 +-33 +0 +-32 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +-51 +27 +-8 +31 +-5 +8 +-23 +7 +-24 +6 +-25 +7 +-24 +8 +-24 +8 +-23 +9 +-23 +8 +-24 +9 +-22 +9 +-23 +9 +-22 +9 +-22 +9 +-23 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-2 +-33 +0 +-32 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +6 +-26 +6 +-26 +8 +-25 +8 +-25 +-51 +28 +-6 +31 +-4 +8 +-23 +7 +-25 +6 +-25 +7 +-24 +7 +-24 +8 +-23 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +10 +-22 +9 +119 +68 +27 +-9 +-1 +-32 +-4 +-35 +-3 +-34 +-1 +-32 +-1 +-32 +2 +-30 +3 +-29 +3 +-29 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-21 +12 +-22 +11 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +10 +-23 +12 +-22 +12 +-22 +11 +-23 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +-49 +29 +-6 +33 +-2 +10 +-21 +9 +-23 +9 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +8 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +10 +120 +69 +28 +-9 +0 +-31 +-4 +-35 +-3 +-34 +0 +-32 +0 +-32 +1 +-30 +3 +-29 +3 +-29 +5 +-27 +6 +-26 +6 +-27 +7 +-26 +7 +-26 +7 +-25 +-52 +27 +-7 +31 +-5 +8 +-23 +7 +-24 +7 +-25 +7 +-24 +8 +-24 +8 +-24 +8 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-23 +9 +-22 +10 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +1 +-30 +3 +-29 +3 +-29 +5 +-28 +5 +-27 +6 +-26 +8 +-25 +7 +-26 +7 +-25 +8 +-24 +9 +-24 +9 +-24 +10 +-23 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-4 +33 +-2 +10 +-22 +9 +-23 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +9 +-23 +9 +-22 +10 +-22 +10 +-22 +10 +120 +68 +27 +-9 +1 +-31 +-4 +-35 +-3 +-34 +-1 +-32 +0 +-32 +2 +-30 +3 +-30 +4 +-28 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-24 +8 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-24 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +13 +-21 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +-49 +30 +-5 +33 +-3 +10 +-22 +9 +-22 +8 +-24 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +9 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +1 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +6 +-26 +7 +-26 +7 +-26 +9 +-24 +8 +-25 +9 +-24 +10 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +11 +-23 +10 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-23 +7 +-24 +9 +-23 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +10 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +10 +-22 +10 +-21 +11 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-21 +10 +-21 +10 +-21 +10 +-21 +11 +-21 +10 +-21 +10 +-22 +10 +-22 +11 +-21 +11 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +10 +120 +69 +28 +-8 +1 +-31 +-4 +-35 +-3 +-34 +-1 +-32 +0 +-32 +3 +-29 +3 +-29 +4 +-28 +6 +-27 +6 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +11 +-23 +10 +-24 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +10 +-23 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-23 +12 +-22 +11 +-22 +-49 +31 +-4 +33 +-3 +10 +-22 +9 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-23 +8 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-8 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-29 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +-51 +28 +-7 +31 +-4 +8 +-23 +8 +-24 +6 +-25 +7 +-24 +8 +-24 +8 +-24 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +10 +-22 +9 +-22 +10 +119 +67 +27 +-9 +-1 +-33 +-4 +-35 +-3 +-34 +-2 +-33 +0 +-31 +1 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +6 +-26 +7 +-25 +8 +-25 +8 +-25 +10 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-23 +10 +-23 +11 +-23 +11 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-23 +11 +-22 +-49 +28 +-6 +33 +-2 +10 +-22 +9 +-22 +8 +-24 +8 +-23 +9 +-22 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +9 +-24 +-51 +28 +-7 +31 +-4 +8 +-23 +7 +-25 +6 +-25 +7 +-24 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +8 +-23 +9 +-22 +9 +-22 +9 +-23 +10 +120 +68 +27 +-9 +-1 +-32 +-5 +-35 +-3 +-34 +-2 +-33 +1 +-31 +1 +-31 +3 +-29 +3 +-29 +5 +-27 +6 +-27 +6 +-26 +7 +-26 +7 +-26 +7 +-25 +-51 +26 +-8 +31 +-4 +8 +-23 +8 +-23 +6 +-25 +7 +-24 +8 +-24 +8 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-22 +8 +-23 +9 +-22 +10 +-22 +9 +119 +68 +27 +-9 +-1 +-32 +-4 +-35 +-4 +-35 +-1 +-33 +0 +-32 +2 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +11 +-23 +11 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +12 +-21 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +10 +-23 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-21 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-22 +8 +-24 +9 +-23 +9 +-23 +8 +-23 +10 +-22 +9 +-23 +9 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-31 +1 +-30 +3 +-29 +4 +-28 +5 +-28 +6 +-27 +6 +-26 +7 +-26 +8 +-25 +8 +-25 +-51 +27 +-8 +31 +-5 +8 +-23 +8 +-24 +7 +-25 +7 +-24 +8 +-24 +8 +-24 +8 +-23 +8 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-22 +10 +120 +69 +28 +-9 +0 +-32 +-4 +-35 +-4 +-35 +-2 +-33 +0 +-32 +2 +-30 +3 +-29 +3 +-29 +6 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-23 +11 +-22 +11 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +12 +-21 +12 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-22 +8 +-24 +9 +-23 +8 +-23 +9 +-22 +10 +-22 +10 +-21 +10 +-22 +9 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +120 +69 +28 +-8 +0 +-32 +-4 +-35 +-3 +-35 +-1 +-33 +1 +-31 +1 +-31 +2 +-29 +4 +-29 +5 +-27 +6 +-27 +7 +-26 +7 +-25 +8 +-26 +8 +-25 +8 +-24 +8 +-25 +10 +-24 +10 +-23 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +12 +-22 +10 +-23 +-49 +29 +-6 +33 +-3 +10 +-21 +10 +-22 +8 +-23 +8 +-23 +9 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +-22 +10 +-22 +9 +120 +69 +28 +-8 +0 +-32 +-3 +-35 +-3 +-34 +-1 +-33 +0 +-31 +1 +-30 +4 +-29 +4 +-29 +5 +-27 +5 +-27 +6 +-26 +7 +-26 +7 +-26 +9 +-24 +8 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-24 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +10 +-23 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-3 +10 +-22 +8 +-23 +8 +-24 +8 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-22 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-22 +11 +-21 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-21 +10 +-22 +11 +-21 +10 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-21 +11 +-21 +10 +-22 +10 +-21 +10 +-22 +10 +-22 +10 +-22 +10 +-21 +11 +-21 +10 +-21 +10 +120 +68 +28 +-8 +0 +-32 +-3 +-35 +-2 +-34 +-1 +-32 +1 +-31 +3 +-30 +3 +-29 +4 +-28 +5 +-28 +6 +-26 +6 +-27 +7 +-26 +8 +-25 +8 +-25 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +9 +-24 +10 +-23 +10 +-23 +9 +-24 +10 +-23 +11 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +10 +-23 +11 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +-49 +30 +-5 +33 +-3 +9 +-22 +9 +-23 +8 +-23 +9 +-23 +9 +-22 +9 +-23 +9 +-23 +10 +-22 +9 +-23 +10 +-22 +10 +-22 +10 +-22 +10 +-22 +9 +119 +68 +27 +-9 +0 +-31 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +1 +-30 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +6 +-26 +7 +-26 +7 +-26 +8 +-25 +-51 +26 +-8 +31 +-4 +8 +-23 +7 +-24 +6 +-25 +7 +-24 +7 +-24 +8 +-23 +9 +-22 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +-22 +9 +120 +68 +28 +-9 +0 +-32 +-4 +-35 +-4 +-35 +-1 +-33 +1 +-31 +2 +-30 +3 +-30 +3 +-29 +5 +-28 +5 +-27 +7 +-26 +7 +-26 +8 +-25 +8 +-25 +8 +-24 +9 +-24 +9 +-24 +10 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-24 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-23 +11 +-23 +10 +-23 +11 +-23 +-49 +30 +-5 +33 +-2 +10 +-22 +9 +-23 +8 +-24 +9 +-23 +8 +-23 +9 +-22 +9 +-22 +9 +-23 +9 +-22 +9 +-22 +9 +-22 +10 +-22 +9 +-23 +11 +120 +68 +28 +-8 +0 +-32 +-4 +-35 +-3 +-34 +-2 +-33 +1 +-31 +1 +-31 +3 +-29 +4 +-28 +5 +-27 +6 +-27 +7 +-26 +7 +-26 +8 +-25 +7 +-25 +-52 +27 +-8 +31 +-5 +8 +-23 +8 +-24 +7 +-24 +7 +-24 +8 +-23 +7 +-24 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +9 +-23 +10 +-22 +9 +119 +68 +27 +-9 +0 +-32 +-4 +-35 +-3 +-35 +-1 +-33 +-1 +-32 +1 +-30 +3 +-29 +3 +-29 +5 +-27 +5 +-27 +7 +-26 +7 +-25 +8 +-25 +8 +-25 +-51 +28 +-7 +30 +-5 +8 +-23 +7 +-25 +6 +-25 +8 +-24 +7 +-25 +8 +-24 +8 +-24 +8 +-23 +9 +-22 +9 +-23 +10 +-22 +9 +-23 +9 +-23 +10 +120 +68 +27 +-9 +-1 +-32 +-4 +-35 +-3 +-34 +-1 +-33 +0 +-32 +1 +-30 +4 +-28 +4 +-28 +4 +-28 +6 +-27 +7 +-26 +6 +-26 +8 +-25 +8 +-25 +9 +-25 +9 +-24 +9 +-24 +9 +-24 +9 +-24 +10 +-23 +10 +-24 +10 +-23 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +10 +-23 +11 +-22 +10 +-23 +11 +-22 +11 +-23 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +12 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +11 +-22 +11 +-22 +11 +-22 +11 +-22 +11 +-23 +12 +-22 +11 +-22 +12 +-22 +12 +-22 +11 +-22 +11 +-22 +11 diff --git a/traces/ioProx-XSF-01-BE-03011.pm3 b/traces/ioProx-XSF-01-BE-03011.pm3 new file mode 100644 index 00000000..34fbbec1 --- /dev/null +++ b/traces/ioProx-XSF-01-BE-03011.pm3 @@ -0,0 +1,16000 @@ +-55 +-90 +-103 +3 +73 +91 +32 +-17 +-59 +-93 +-105 +3 +73 +92 +32 +-17 +-58 +-93 +-104 +4 +74 +93 +33 +-16 +-58 +-92 +-104 +4 +75 +93 +33 +-15 +-57 +-92 +-104 +6 +76 +95 +34 +-14 +-57 +-91 +-103 +7 +76 +95 +34 +-14 +-57 +-91 +-103 +7 +77 +95 +35 +-14 +-56 +-91 +-105 +-98 +33 +100 +109 +84 +25 +-22 +-63 +-97 +-110 +-93 +37 +102 +109 +84 +25 +-22 +-63 +-97 +-110 +-95 +36 +101 +109 +83 +24 +-23 +-64 +-98 +-110 +-96 +35 +100 +108 +82 +23 +-24 +-65 +-98 +-111 +-97 +34 +99 +107 +81 +22 +-25 +-66 +-99 +-112 +-97 +33 +99 +106 +81 +22 +-25 +-65 +-99 +-112 +-97 +33 +99 +105 +46 +-7 +-49 +-86 +-99 +4 +76 +91 +33 +-17 +-42 +-93 +-104 +4 +75 +92 +33 +-17 +-41 +-93 +-103 +5 +77 +93 +35 +-15 +-56 +-92 +-103 +6 +78 +94 +35 +-15 +-56 +-92 +-102 +7 +79 +94 +36 +-14 +-56 +-91 +-102 +7 +79 +95 +37 +-14 +-55 +-91 +-101 +7 +79 +95 +37 +-14 +-55 +-91 +-101 +7 +79 +95 +37 +-14 +-55 +-91 +-102 +7 +79 +95 +37 +-14 +-55 +-91 +-102 +6 +78 +94 +36 +-14 +-56 +-91 +-102 +6 +78 +94 +35 +-15 +-56 +-92 +-102 +6 +78 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +93 +35 +-15 +-56 +-92 +-103 +6 +78 +94 +35 +-15 +-56 +-92 +-102 +6 +78 +94 +35 +-15 +-56 +-92 +-103 +5 +78 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +94 +35 +-15 +-56 +-92 +-102 +6 +79 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +94 +35 +-15 +-56 +-92 +-103 +6 +78 +93 +35 +-15 +-56 +-92 +-103 +6 +78 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +94 +36 +-15 +-56 +-92 +-102 +7 +79 +95 +36 +-15 +-56 +-92 +-102 +6 +79 +94 +36 +-15 +-56 +-92 +-102 +6 +79 +94 +36 +-15 +-56 +-92 +-102 +7 +79 +95 +37 +-14 +-55 +-91 +-102 +7 +79 +95 +37 +-14 +-56 +-91 +-102 +6 +79 +95 +37 +-14 +-56 +-91 +-102 +7 +79 +95 +36 +-15 +-56 +-92 +-102 +6 +79 +95 +36 +-15 +-56 +-92 +-102 +7 +79 +95 +37 +-14 +-55 +-92 +-102 +6 +78 +95 +36 +-15 +-56 +-92 +-102 +6 +79 +95 +37 +-14 +-56 +-92 +-102 +6 +79 +94 +36 +-15 +-56 +-92 +-103 +6 +78 +95 +36 +-14 +-56 +-92 +-102 +6 +79 +94 +36 +-15 +-56 +-92 +-102 +6 +78 +95 +36 +-14 +-56 +-92 +-103 +6 +79 +94 +36 +-15 +-56 +-92 +-103 +6 +79 +95 +36 +-15 +-56 +-92 +-103 +6 +78 +94 +36 +-15 +-56 +-92 +-103 +6 +78 +94 +36 +-15 +-56 +-92 +-103 +6 +79 +95 +37 +-14 +-56 +-92 +-102 +7 +79 +95 +36 +-15 +-56 +-92 +-102 +7 +79 +95 +37 +-14 +-55 +-92 +-102 +7 +79 +96 +37 +-14 +-55 +-91 +-102 +7 +79 +95 +37 +-14 +-55 +-92 +-102 +7 +79 +96 +37 +-14 +-55 +-91 +-102 +7 +79 +95 +37 +-14 +-55 +-92 +-102 +7 +79 +95 +37 +-14 +-55 +-92 +-102 +7 +79 +96 +37 +-14 +-55 +-91 +-102 +8 +79 +95 +37 +-14 +-55 +-92 +-102 +7 +79 +96 +79 +20 +-27 +-67 +-100 +-128 +-95 +36 +103 +111 +86 +26 +-22 +-63 +-97 +-111 +-95 +36 +102 +109 +83 +24 +-23 +-65 +-98 +-112 +-97 +34 +100 +108 +82 +23 +-24 +-66 +-99 +-112 +-98 +33 +99 +107 +81 +22 +-25 +-66 +-99 +-128 +-98 +33 +99 +106 +81 +22 +-25 +-66 +-100 +-128 +-99 +33 +98 +106 +80 +22 +-26 +-67 +-100 +-128 +-100 +32 +98 +106 +80 +22 +-26 +-67 +-100 +-128 +-99 +32 +98 +106 +80 +22 +-26 +-67 +-100 +-128 +-99 +33 +98 +106 +80 +22 +-26 +-67 +-100 +-128 +-100 +32 +98 +106 +81 +22 +-25 +-66 +-100 +-128 +-99 +33 +99 +106 +80 +22 +-26 +-67 +-100 +-128 +-99 +32 +98 +106 +80 +22 +-26 +-67 +-100 +-128 +-100 +32 +99 +106 +46 +-7 +-50 +-87 +-100 +3 +75 +90 +32 +-18 +-59 +-95 +-106 +2 +75 +91 +33 +-17 +-43 +-94 +-105 +4 +76 +93 +34 +-16 +-58 +-93 +-105 +4 +77 +94 +35 +-16 +-57 +-93 +-104 +5 +78 +94 +36 +-15 +-56 +-93 +-103 +6 +78 +94 +35 +-15 +-57 +-93 +-103 +6 +78 +95 +36 +-15 +-56 +-92 +-103 +5 +79 +95 +36 +-15 +-56 +-92 +-103 +6 +79 +95 +37 +-15 +-56 +-92 +-103 +6 +79 +95 +36 +-15 +-56 +-92 +-103 +7 +79 +95 +36 +-15 +-56 +-92 +-103 +6 +79 +95 +36 +-15 +-56 +-92 +-103 +6 +79 +95 +36 +-15 +-56 +-92 +-103 +6 +79 +95 +37 +-15 +-56 +-92 +-103 +6 +79 +95 +37 +-15 +-56 +-92 +-103 +5 +78 +95 +36 +-15 +-56 +-92 +-103 +6 +79 +95 +36 +-15 +-56 +-92 +-103 +6 +79 +94 +36 +-15 +-57 +-93 +-103 +6 +79 +95 +36 +-15 +-56 +-92 +-104 +6 +79 +95 +37 +-15 +-56 +-92 +-103 +6 +79 +95 +36 +-15 +-56 +-92 +-103 +7 +79 +95 +37 +-14 +-56 +-92 +-103 +6 +79 +95 +36 +-15 +-56 +-92 +-103 +6 +78 +95 +37 +-15 +-56 +-92 +-103 +6 +79 +95 +37 +-15 +-56 +-92 +-103 +6 +79 +95 +37 +-15 +-56 +-92 +-103 +6 +79 +95 +37 +-15 +-56 +-92 +-103 +6 +78 +95 +37 +-15 +-56 +-92 +-103 +6 +79 +95 +37 +-14 +-56 +-92 +-103 +6 +79 +95 +37 +-14 +-56 +-92 +-103 +6 +79 +96 +37 +-14 +-56 +-92 +-103 +6 +79 +95 +79 +20 +-27 +-68 +-101 +-128 +-96 +36 +103 +111 +86 +26 +-22 +-64 +-98 +-111 +-95 +36 +102 +110 +85 +25 +-23 +-65 +-98 +-112 +-96 +35 +101 +109 +83 +24 +-24 +-65 +-99 +-112 +-97 +35 +101 +109 +83 +24 +-24 +-65 +-99 +-112 +-97 +34 +101 +108 +83 +24 +-24 +-66 +-99 +-128 +-98 +33 +99 +108 +82 +23 +-25 +-66 +-100 +-110 +7 +79 +97 +36 +-14 +-57 +-92 +-105 +1 +72 +91 +30 +-19 +-61 +-95 +-107 +2 +73 +92 +32 +-17 +-60 +-95 +-107 +4 +74 +94 +33 +-16 +-59 +-93 +-106 +4 +75 +94 +33 +-16 +-59 +-93 +-105 +5 +76 +95 +34 +-15 +-58 +-93 +-105 +6 +76 +95 +34 +-15 +-58 +-93 +-105 +6 +77 +95 +75 +19 +-29 +-69 +-103 +-128 +-98 +36 +100 +111 +83 +26 +-24 +-64 +-99 +-112 +-98 +35 +100 +110 +81 +24 +-25 +-65 +-100 +-112 +-99 +35 +99 +109 +80 +24 +-26 +-66 +-101 +-128 +-100 +34 +98 +109 +80 +24 +-26 +-66 +-101 +-128 +-99 +34 +98 +108 +80 +23 +-26 +-66 +-101 +-128 +-100 +33 +97 +109 +80 +23 +-26 +-66 +-101 +-128 +-100 +33 +97 +108 +80 +23 +-26 +-66 +-101 +-128 +-100 +34 +97 +108 +80 +23 +-26 +-66 +-101 +-128 +-100 +33 +97 +108 +80 +24 +-26 +-66 +-101 +-128 +-101 +33 +98 +108 +80 +23 +-26 +-67 +-101 +-128 +-100 +33 +97 +109 +80 +23 +-27 +-67 +-101 +-128 +-100 +33 +97 +108 +80 +23 +-26 +-66 +-101 +-128 +-101 +33 +97 +108 +80 +23 +-27 +-67 +-101 +-128 +-100 +33 +97 +107 +79 +22 +-27 +-67 +-102 +-128 +-101 +32 +97 +108 +79 +23 +-27 +-67 +-101 +-128 +-100 +33 +97 +108 +80 +23 +-26 +-67 +-101 +-128 +-101 +33 +98 +109 +80 +24 +-26 +-66 +-101 +-128 +-99 +34 +98 +109 +81 +24 +-26 +-66 +-101 +-128 +-100 +34 +98 +109 +80 +24 +-26 +-66 +-101 +-128 +-100 +34 +98 +109 +81 +24 +-26 +-66 +-101 +-128 +-100 +34 +98 +109 +80 +24 +-26 +-66 +-101 +-128 +-100 +34 +98 +109 +80 +23 +-26 +-66 +-101 +-128 +-101 +34 +98 +109 +81 +24 +-26 +-66 +-101 +-128 +-100 +33 +98 +109 +80 +23 +-26 +-67 +-101 +-128 +-100 +34 +98 +109 +80 +23 +-26 +-66 +-101 +-128 +-101 +33 +97 +109 +80 +23 +-26 +-66 +-101 +-128 +-100 +33 +97 +108 +80 +23 +-26 +-67 +-102 +-128 +-100 +33 +97 +108 +80 +23 +-27 +-67 +-102 +-128 +-101 +33 +97 +109 +80 +23 +-26 +-67 +-101 +-128 +-100 +34 +98 +109 +81 +24 +-26 +-66 +-101 +-128 +-99 +34 +98 +109 +81 +24 +-26 +-66 +-101 +-128 +-99 +34 +99 +110 +47 +-5 +-50 +-86 +-101 +4 +75 +94 +33 +-17 +-59 +-94 +-106 +4 +75 +95 +33 +-16 +-59 +-94 +-106 +5 +76 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-14 +-58 +-93 +-105 +6 +77 +97 +35 +-14 +-58 +-93 +-105 +6 +77 +96 +35 +-14 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +5 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +7 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +7 +77 +96 +35 +-15 +-58 +-93 +-105 +7 +77 +96 +35 +-15 +-58 +-93 +-105 +7 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-15 +-58 +-93 +-105 +7 +77 +96 +35 +-15 +-58 +-93 +-105 +6 +77 +96 +35 +-14 +-58 +-93 +-105 +7 +77 +97 +36 +-14 +-57 +-93 +-105 +7 +77 +97 +36 +-14 +-57 +-92 +-104 +7 +77 +97 +36 +-14 +-57 +-93 +-105 +7 +78 +97 +36 +-14 +-57 +-93 +-104 +7 +78 +97 +36 +-14 +-57 +-92 +-105 +7 +77 +97 +36 +-14 +-57 +-93 +-105 +7 +78 +97 +36 +-14 +-57 +-93 +-105 +7 +78 +97 +36 +-14 +-57 +-93 +-105 +7 +77 +97 +77 +21 +-28 +-68 +-103 +-128 +-98 +37 +101 +113 +85 +27 +-23 +-64 +-99 +-112 +-98 +36 +100 +111 +82 +25 +-25 +-66 +-101 +-128 +-99 +35 +99 +110 +82 +24 +-25 +-66 +-101 +-128 +-100 +34 +99 +110 +80 +23 +-26 +-67 +-102 +-128 +-100 +34 +98 +109 +80 +24 +-26 +-67 +-102 +-128 +-100 +34 +98 +109 +80 +23 +-27 +-67 +-102 +-128 +-101 +33 +97 +109 +80 +23 +-26 +-67 +-102 +-128 +-101 +33 +97 +108 +80 +23 +-27 +-67 +-102 +-128 +-101 +33 +98 +109 +80 +23 +-27 +-67 +-102 +-128 +-101 +33 +98 +109 +80 +23 +-27 +-67 +-102 +-128 +-100 +34 +98 +109 +81 +24 +-26 +-67 +-102 +-128 +-100 +34 +98 +109 +80 +23 +-26 +-67 +-102 +-128 +-100 +34 +98 +110 +81 +24 +-26 +-66 +-101 +-128 +-100 +35 +99 +110 +82 +24 +-26 +-66 +-101 +-128 +-100 +35 +99 +110 +83 +25 +-25 +-65 +-101 +-128 +-99 +35 +99 +110 +82 +24 +-25 +-66 +-101 +-128 +-99 +35 +100 +110 +82 +25 +-25 +-66 +-101 +-128 +-100 +34 +99 +110 +81 +24 +-26 +-67 +-102 +-128 +-101 +33 +98 +109 +81 +24 +-26 +-67 +-102 +-128 +-102 +33 +97 +108 +80 +23 +-27 +-67 +-102 +-128 +-101 +33 +97 +108 +80 +23 +-27 +-67 +-102 +-128 +-101 +33 +97 +108 +80 +23 +-27 +-67 +-102 +-128 +-102 +33 +97 +109 +80 +23 +-27 +-67 +-102 +-128 +-100 +33 +98 +109 +80 +23 +-26 +-67 +-102 +-128 +-99 +35 +99 +110 +81 +24 +-26 +-66 +-101 +-128 +-100 +35 +100 +111 +47 +-5 +-50 +-86 +-102 +4 +74 +93 +32 +-17 +-60 +-95 +-108 +3 +74 +93 +32 +-17 +-60 +-95 +-107 +4 +75 +95 +33 +-16 +-59 +-95 +-107 +4 +75 +95 +33 +-16 +-59 +-95 +-107 +5 +75 +95 +34 +-16 +-59 +-94 +-106 +5 +76 +95 +33 +-16 +-59 +-95 +-107 +4 +75 +94 +33 +-17 +-60 +-95 +-107 +2 +73 +93 +32 +-18 +-60 +-95 +-108 +3 +74 +94 +33 +-17 +-60 +-95 +-107 +4 +76 +94 +33 +-17 +-60 +-95 +-107 +5 +76 +95 +34 +-16 +-59 +-94 +-106 +6 +77 +96 +35 +-15 +-59 +-94 +-106 +7 +77 +97 +36 +-14 +-58 +-93 +-105 +8 +79 +99 +37 +-14 +-57 +-93 +-105 +8 +79 +98 +37 +-14 +-57 +-93 +-105 +8 +79 +98 +37 +-14 +-57 +-93 +-104 +9 +80 +99 +37 +-13 +-57 +-93 +-104 +8 +79 +99 +37 +-14 +-57 +-93 +-104 +8 +79 +99 +37 +-14 +-57 +-93 +-105 +7 +77 +98 +36 +-14 +-57 +-93 +-105 +7 +78 +97 +36 +-14 +-58 +-93 +-105 +7 +77 +97 +36 +-15 +-58 +-93 +-106 +7 +77 +96 +35 +-15 +-58 +-94 +-106 +5 +76 +96 +35 +-15 +-58 +-94 +-106 +7 +77 +97 +35 +-15 +-58 +-93 +-106 +7 +77 +97 +36 +-14 +-58 +-93 +-105 +7 +77 +97 +35 +-15 +-58 +-93 +-106 +7 +78 +98 +36 +-14 +-58 +-93 +-105 +8 +79 +98 +36 +-14 +-58 +-93 +-105 +8 +79 +99 +37 +-13 +-57 +-92 +-105 +8 +79 +98 +36 +-14 +-57 +-93 +-105 +7 +78 +98 +36 +-14 +-57 +-93 +-105 +8 +79 +98 +36 +-14 +-57 +-93 +-105 +7 +78 +97 +36 +-14 +-58 +-93 +-105 +7 +78 +97 +36 +-14 +-58 +-93 +-106 +6 +77 +97 +35 +-15 +-58 +-94 +-106 +7 +78 +97 +35 +-15 +-58 +-93 +-106 +7 +78 +97 +36 +-14 +-58 +-93 +-105 +8 +79 +98 +36 +-14 +-57 +-93 +-108 +-99 +35 +102 +112 +89 +28 +-21 +-63 +-98 +-112 +-94 +39 +106 +113 +88 +28 +-21 +-64 +-99 +-128 +-97 +37 +103 +111 +86 +26 +-23 +-65 +-100 +-128 +-98 +35 +101 +110 +84 +24 +-24 +-66 +-100 +-128 +-99 +34 +101 +109 +83 +23 +-25 +-67 +-101 +-128 +-100 +33 +100 +108 +82 +22 +-26 +-67 +-102 +-128 +-101 +32 +99 +107 +46 +-8 +-51 +-89 +-102 +1 +73 +90 +31 +-20 +-61 +-97 +-109 +1 +74 +90 +31 +-19 +-61 +-97 +-108 +3 +75 +92 +33 +-18 +-60 +-96 +-107 +3 +77 +93 +34 +-17 +-43 +-96 +-107 +5 +78 +94 +35 +-16 +-58 +-95 +-106 +6 +78 +95 +35 +-16 +-58 +-95 +-106 +5 +79 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +95 +79 +20 +-28 +-69 +-103 +-128 +-97 +36 +103 +111 +86 +26 +-23 +-65 +-100 +-128 +-98 +35 +102 +109 +83 +24 +-25 +-67 +-101 +-128 +-99 +34 +101 +109 +83 +23 +-25 +-67 +-101 +-128 +-100 +33 +100 +108 +82 +22 +-26 +-68 +-102 +-128 +-100 +33 +99 +107 +82 +22 +-26 +-68 +-102 +-128 +-100 +33 +99 +107 +81 +22 +-27 +-68 +-102 +-128 +-101 +33 +99 +107 +82 +22 +-26 +-68 +-102 +-128 +-101 +33 +99 +107 +82 +22 +-26 +-68 +-102 +-128 +-100 +33 +99 +108 +82 +22 +-26 +-68 +-102 +-128 +-101 +33 +100 +108 +82 +22 +-26 +-68 +-102 +-128 +-100 +33 +99 +107 +82 +22 +-26 +-68 +-102 +-128 +-101 +33 +99 +107 +82 +22 +-26 +-68 +-102 +-128 +-100 +33 +100 +108 +46 +-7 +-51 +-89 +-102 +2 +75 +91 +32 +-19 +-61 +-97 +-108 +2 +74 +92 +32 +-19 +-61 +-97 +-108 +3 +76 +93 +34 +-17 +-43 +-96 +-107 +4 +77 +94 +35 +-17 +-43 +-95 +-106 +5 +78 +95 +35 +-16 +-58 +-95 +-106 +5 +78 +95 +36 +-16 +-58 +-95 +-106 +5 +79 +95 +36 +-16 +-58 +-95 +-106 +5 +78 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-94 +-105 +6 +79 +96 +37 +-15 +-57 +-94 +-105 +6 +79 +96 +37 +-15 +-57 +-94 +-105 +7 +80 +97 +37 +-15 +-57 +-94 +-105 +7 +80 +97 +37 +-15 +-57 +-94 +-105 +7 +80 +97 +37 +-15 +-57 +-94 +-105 +7 +80 +97 +37 +-15 +-57 +-94 +-105 +8 +80 +97 +37 +-15 +-57 +-94 +-105 +8 +80 +97 +37 +-15 +-57 +-94 +-105 +7 +80 +97 +37 +-15 +-57 +-94 +-104 +7 +80 +97 +37 +-14 +-57 +-94 +-104 +8 +81 +97 +38 +-14 +-57 +-93 +-105 +8 +80 +97 +37 +-15 +-57 +-94 +-105 +7 +80 +97 +37 +-15 +-57 +-94 +-105 +6 +79 +96 +37 +-15 +-57 +-94 +-105 +6 +79 +95 +36 +-16 +-58 +-95 +-105 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +6 +79 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +6 +79 +96 +36 +-16 +-58 +-94 +-106 +6 +79 +96 +37 +-16 +-58 +-94 +-106 +6 +78 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +6 +78 +95 +35 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-94 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +6 +79 +95 +36 +-16 +-58 +-95 +-106 +7 +79 +96 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-94 +-106 +6 +79 +96 +37 +-15 +-58 +-94 +-105 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +6 +79 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +7 +79 +96 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +37 +-15 +-58 +-94 +-105 +7 +79 +96 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +37 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +6 +79 +95 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-106 +6 +79 +95 +36 +-16 +-58 +-95 +-106 +7 +79 +95 +36 +-16 +-58 +-95 +-106 +7 +79 +96 +36 +-16 +-58 +-95 +-106 +7 +80 +96 +37 +-15 +-58 +-94 +-106 +6 +79 +96 +37 +-16 +-58 +-94 +-105 +7 +79 +96 +37 +-15 +-58 +-94 +-105 +7 +80 +96 +36 +-16 +-58 +-95 +-105 +7 +79 +96 +37 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +7 +79 +96 +37 +-16 +-58 +-94 +-105 +6 +79 +97 +37 +-15 +-58 +-94 +-105 +7 +80 +96 +36 +-16 +-58 +-95 +-106 +6 +79 +96 +36 +-16 +-58 +-95 +-105 +7 +80 +97 +37 +-15 +-58 +-94 +-105 +7 +80 +97 +37 +-15 +-57 +-94 +-105 +7 +80 +97 +37 +-15 +-57 +-94 +-105 +7 +80 +97 +80 +21 +-27 +-69 +-103 +-128 +-95 +38 +105 +112 +88 +27 +-22 +-65 +-99 +-128 +-96 +37 +104 +112 +86 +26 +-23 +-65 +-100 +-128 +-98 +36 +102 +109 +84 +24 +-25 +-67 +-101 +-128 +-99 +34 +101 +109 +83 +23 +-26 +-68 +-102 +-128 +-100 +33 +100 +107 +82 +22 +-27 +-68 +-103 +-128 +-100 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +32 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +32 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +32 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +33 +99 +107 +81 +22 +-27 +-69 +-103 +-128 +-101 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-100 +33 +99 +107 +82 +22 +-27 +-69 +-103 +-128 +-101 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-100 +33 +100 +108 +82 +22 +-26 +-68 +-102 +-128 +-100 +33 +99 +107 +81 +22 +-27 +-69 +-103 +-128 +-100 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +33 +99 +107 +81 +22 +-27 +-69 +-103 +-128 +-100 +33 +100 +107 +81 +22 +-27 +-69 +-103 +-128 +-101 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +33 +99 +106 +81 +21 +-27 +-69 +-103 +-128 +-101 +32 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-101 +33 +99 +106 +80 +21 +-28 +-69 +-103 +-128 +6 +78 +97 +35 +-16 +-59 +-95 +-108 +1 +72 +91 +30 +-20 +-63 +-98 +-110 +3 +74 +94 +32 +-18 +-61 +-96 +-108 +5 +76 +95 +33 +-17 +-60 +-95 +-107 +6 +77 +96 +34 +-16 +-60 +-95 +-107 +8 +78 +97 +35 +-15 +-59 +-94 +-106 +8 +79 +97 +35 +-15 +-59 +-94 +-106 +8 +78 +97 +35 +-15 +-59 +-94 +-106 +7 +77 +97 +35 +-15 +-59 +-94 +-106 +8 +78 +97 +35 +-15 +-59 +-94 +-106 +7 +78 +97 +35 +-15 +-58 +-94 +-106 +7 +78 +97 +35 +-15 +-59 +-94 +-106 +7 +78 +97 +35 +-15 +-59 +-95 +-106 +7 +77 +96 +35 +-16 +-59 +-95 +-106 +7 +77 +97 +35 +-16 +-59 +-95 +-106 +8 +78 +97 +35 +-15 +-59 +-95 +-107 +7 +77 +97 +35 +-15 +-59 +-94 +-107 +8 +78 +97 +35 +-15 +-59 +-94 +-106 +8 +79 +97 +36 +-15 +-58 +-94 +-106 +8 +79 +98 +36 +-15 +-58 +-94 +-106 +8 +79 +99 +37 +-14 +-58 +-93 +-105 +10 +80 +99 +37 +-14 +-58 +-93 +-105 +9 +79 +99 +36 +-14 +-58 +-93 +-105 +9 +80 +99 +36 +-14 +-58 +-94 +-106 +8 +79 +98 +36 +-14 +-58 +-94 +-106 +8 +78 +97 +35 +-15 +-59 +-94 +-106 +8 +77 +97 +35 +-16 +-59 +-95 +-106 +7 +77 +97 +35 +-15 +-59 +-95 +-107 +6 +77 +96 +34 +-16 +-59 +-95 +-107 +7 +77 +96 +34 +-16 +-59 +-95 +-107 +7 +77 +95 +34 +-17 +-60 +-95 +-107 +7 +77 +96 +34 +-16 +-59 +-95 +-110 +-100 +34 +101 +109 +86 +26 +-23 +-66 +-100 +-128 +-96 +38 +104 +111 +85 +25 +-24 +-66 +-101 +-128 +-98 +35 +102 +109 +83 +24 +-25 +-67 +-102 +-128 +-99 +34 +101 +109 +83 +23 +-26 +-68 +-102 +-128 +-99 +34 +100 +107 +81 +22 +-27 +-69 +-103 +-128 +-100 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-100 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-100 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-100 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-100 +33 +99 +107 +81 +21 +-27 +-69 +-103 +-128 +-99 +34 +100 +107 +82 +22 +-27 +-68 +-103 +-128 +-100 +34 +100 +107 +81 +22 +-27 +-69 +-103 +-128 +-100 +34 +99 +107 +82 +22 +-27 +-69 +-103 +-128 +7 +79 +97 +35 +-16 +-59 +-95 +-108 +1 +72 +91 +29 +-20 +-63 +-98 +-110 +3 +74 +93 +31 +-18 +-62 +-97 +-109 +5 +75 +94 +33 +-17 +-61 +-96 +-108 +6 +77 +95 +33 +-17 +-60 +-95 +-107 +6 +77 +96 +34 +-16 +-60 +-95 +-107 +7 +77 +96 +34 +-16 +-60 +-95 +-107 +7 +77 +97 +77 +20 +-30 +-70 +-105 +-128 +-97 +38 +102 +113 +84 +26 +-24 +-65 +-101 +-128 +-97 +38 +101 +111 +82 +24 +-26 +-67 +-102 +-128 +-99 +36 +99 +110 +81 +23 +-27 +-67 +-103 +-128 +-100 +35 +99 +110 +80 +23 +-27 +-68 +-103 +-128 +-100 +34 +98 +109 +80 +22 +-28 +-69 +-104 +-128 +-100 +35 +98 +108 +79 +22 +-28 +-69 +-104 +-128 +-101 +34 +98 +109 +80 +23 +-28 +-68 +-103 +-128 +-100 +35 +98 +109 +80 +22 +-28 +-68 +-104 +-128 +-100 +35 +99 +109 +80 +22 +-28 +-68 +-104 +-128 +-100 +35 +99 +109 +80 +23 +-27 +-68 +-103 +-128 +-99 +35 +100 +110 +80 +23 +-27 +-68 +-103 +-128 +-99 +36 +100 +110 +81 +24 +-27 +-67 +-103 +-128 +-99 +36 +100 +110 +82 +24 +-27 +-67 +-103 +-128 +-99 +36 +100 +110 +81 +24 +-27 +-67 +-103 +-128 +-99 +36 +99 +110 +81 +23 +-27 +-68 +-103 +-128 +-100 +35 +99 +108 +80 +22 +-28 +-68 +-104 +-128 +-100 +35 +98 +108 +79 +22 +-28 +-69 +-104 +-128 +-101 +34 +97 +108 +79 +21 +-28 +-69 +-104 +-128 +-101 +34 +97 +107 +79 +21 +-28 +-69 +-104 +-128 +-101 +34 +98 +108 +79 +22 +-28 +-69 +-104 +-128 +-100 +35 +98 +108 +80 +23 +-27 +-68 +-104 +-128 +-99 +36 +99 +109 +81 +23 +-27 +-68 +-103 +-128 +-99 +35 +100 +110 +82 +24 +-26 +-67 +-103 +-128 +-99 +36 +99 +109 +80 +23 +-27 +-68 +-103 +-128 +-100 +35 +99 +109 +80 +22 +-28 +-68 +-104 +-128 +-100 +34 +97 +107 +79 +22 +-28 +-69 +-104 +-128 +-101 +33 +97 +107 +78 +21 +-29 +-69 +-104 +-128 +-102 +33 +96 +106 +77 +20 +-29 +-70 +-105 +-128 +-104 +31 +95 +105 +75 +18 +-31 +-71 +-106 +-128 +-103 +32 +95 +104 +75 +19 +-31 +-71 +-106 +-128 +-103 +32 +96 +106 +77 +19 +-30 +-71 +-106 +-128 +-101 +34 +97 +107 +43 +-9 +-53 +-90 +-105 +2 +72 +91 +30 +-20 +-63 +-98 +-110 +3 +74 +93 +31 +-19 +-62 +-97 +-108 +6 +77 +95 +33 +-17 +-60 +-96 +-107 +8 +77 +96 +34 +-16 +-59 +-95 +-107 +8 +78 +97 +35 +-15 +-59 +-94 +-106 +9 +79 +97 +36 +-15 +-58 +-94 +-106 +9 +78 +97 +35 +-15 +-58 +-94 +-106 +9 +79 +97 +77 +20 +-29 +-70 +-105 +-128 +-96 +39 +102 +113 +84 +26 +-24 +-66 +-101 +-128 +-97 +37 +100 +111 +82 +24 +-26 +-67 +-102 +-128 +-99 +36 +99 +109 +80 +22 +-28 +-68 +-104 +-128 +-100 +35 +98 +109 +80 +22 +-28 +-68 +-104 +-128 +-99 +35 +98 +107 +79 +21 +-28 +-69 +-104 +-128 +-100 +35 +98 +109 +80 +22 +-28 +-68 +-104 +-112 +6 +81 +96 +36 +-16 +-59 +-95 +-107 +1 +74 +90 +31 +-20 +-62 +-98 +-109 +4 +76 +92 +33 +-19 +-61 +-97 +-107 +6 +78 +94 +34 +-17 +-43 +-96 +-107 +6 +78 +94 +35 +-17 +-43 +-96 +-106 +7 +79 +95 +36 +-16 +-59 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +6 +78 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +8 +79 +95 +35 +-16 +-59 +-95 +-106 +8 +80 +95 +36 +-16 +-58 +-95 +-105 +7 +79 +96 +36 +-16 +-58 +-95 +-105 +9 +80 +96 +37 +-16 +-58 +-95 +-105 +9 +81 +96 +37 +-16 +-58 +-95 +-105 +8 +80 +96 +37 +-16 +-58 +-95 +-105 +8 +80 +96 +36 +-16 +-58 +-95 +-105 +8 +80 +96 +36 +-16 +-58 +-95 +-105 +8 +80 +95 +36 +-16 +-58 +-95 +-105 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +6 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +78 +94 +35 +-17 +-43 +-96 +-106 +6 +79 +94 +35 +-17 +-43 +-96 +-106 +7 +79 +94 +35 +-17 +-43 +-96 +-107 +5 +78 +94 +34 +-17 +-43 +-96 +-106 +7 +79 +94 +35 +-17 +-43 +-96 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-16 +-59 +-95 +-106 +6 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +6 +78 +94 +35 +-17 +-43 +-96 +-106 +8 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-16 +-59 +-95 +-106 +8 +79 +95 +35 +-17 +-43 +-95 +-106 +6 +79 +95 +35 +-17 +-43 +-95 +-106 +8 +79 +95 +36 +-16 +-59 +-95 +-106 +7 +79 +95 +36 +-16 +-59 +-95 +-105 +8 +79 +95 +36 +-16 +-59 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +8 +79 +95 +35 +-17 +-43 +-95 +-106 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +8 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-16 +-59 +-95 +-106 +8 +79 +95 +35 +-17 +-43 +-95 +-106 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-105 +8 +80 +95 +36 +-16 +-58 +-95 +-105 +8 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +94 +35 +-17 +-43 +-96 +-106 +6 +79 +95 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-106 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +8 +79 +95 +35 +-17 +-43 +-95 +-109 +-98 +36 +100 +112 +85 +27 +-24 +-65 +-101 +-128 +-93 +41 +103 +113 +84 +26 +-25 +-66 +-101 +-128 +-95 +39 +101 +111 +82 +24 +-26 +-67 +-102 +-128 +-97 +38 +100 +110 +80 +23 +-27 +-68 +-103 +-128 +-97 +37 +100 +109 +80 +23 +-27 +-68 +-103 +-128 +-97 +37 +100 +109 +80 +22 +-28 +-68 +-103 +-128 +-98 +37 +100 +110 +80 +23 +-27 +-68 +-103 +-128 +-98 +37 +100 +109 +80 +23 +-27 +-68 +-103 +-128 +-98 +36 +99 +109 +80 +23 +-27 +-68 +-103 +-128 +-99 +35 +98 +107 +79 +22 +-28 +-69 +-104 +-128 +-99 +35 +98 +108 +79 +22 +-28 +-69 +-104 +-128 +-99 +35 +97 +107 +78 +21 +-29 +-69 +-104 +-128 +-100 +35 +97 +107 +78 +21 +-29 +-69 +-104 +-128 +6 +79 +94 +34 +-17 +-43 +-96 +-108 +1 +72 +88 +29 +-22 +-63 +-99 +-109 +3 +74 +89 +31 +-20 +-62 +-98 +-108 +5 +76 +92 +33 +-19 +-61 +-97 +-107 +5 +77 +93 +33 +-18 +-60 +-96 +-107 +6 +78 +94 +34 +-17 +-43 +-96 +-106 +6 +78 +93 +34 +-17 +-43 +-96 +-106 +7 +78 +93 +34 +-17 +-43 +-96 +-106 +7 +78 +94 +34 +-17 +-43 +-96 +-106 +8 +79 +94 +34 +-17 +-43 +-96 +-106 +7 +79 +94 +34 +-17 +-43 +-96 +-106 +7 +79 +94 +35 +-17 +-43 +-95 +-106 +7 +79 +95 +35 +-17 +-43 +-95 +-105 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +8 +79 +94 +35 +-17 +-43 +-95 +-105 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +7 +79 +94 +35 +-17 +-43 +-95 +-105 +7 +79 +94 +35 +-17 +-43 +-95 +-105 +8 +79 +95 +35 +-17 +-43 +-95 +-105 +8 +79 +95 +35 +-17 +-43 +-95 +-106 +8 +79 +94 +35 +-17 +-43 +-95 +-105 +8 +79 +94 +35 +-17 +-43 +-95 +-105 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +8 +79 +95 +35 +-17 +-43 +-95 +-106 +8 +79 +94 +35 +-17 +-43 +-95 +-105 +8 +79 +95 +35 +-17 +-43 +-95 +-105 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +7 +79 +94 +35 +-17 +-43 +-96 +-106 +7 +79 +94 +35 +-17 +-43 +-95 +-106 +8 +79 +94 +35 +-17 +-43 +-95 +-106 +7 +79 +94 +35 +-17 +-43 +-95 +-105 +8 +79 +94 +35 +-17 +-43 +-95 +-109 +-97 +36 +100 +111 +83 +25 +-25 +-66 +-101 +-128 +-94 +40 +102 +111 +83 +25 +-25 +-66 +-101 +-128 +-95 +38 +100 +109 +80 +23 +-27 +-68 +-103 +-128 +-97 +37 +100 +109 +80 +23 +-27 +-68 +-103 +-128 +-97 +37 +99 +108 +79 +21 +-28 +-69 +-104 +-128 +-97 +37 +99 +108 +79 +22 +-28 +-68 +-104 +-128 +-98 +36 +99 +108 +44 +-8 +-52 +-89 +-103 +5 +74 +91 +30 +-20 +-62 +-97 +-109 +5 +74 +92 +31 +-19 +-62 +-97 +-108 +6 +76 +94 +33 +-17 +-60 +-96 +-107 +7 +77 +95 +33 +-17 +-60 +-95 +-106 +9 +78 +96 +34 +-16 +-59 +-95 +-106 +9 +78 +96 +35 +-16 +-59 +-94 +-105 +10 +78 +96 +34 +-16 +-59 +-95 +-109 +-96 +36 +101 +109 +85 +25 +-24 +-66 +-100 +-128 +-92 +39 +104 +110 +84 +24 +-25 +-67 +-101 +-128 +-95 +37 +101 +107 +81 +22 +-27 +-68 +-102 +-128 +-97 +35 +100 +107 +80 +21 +-27 +-69 +-103 +-128 +-97 +35 +99 +105 +79 +20 +-28 +-70 +-103 +-128 +-98 +34 +99 +105 +79 +20 +-28 +-70 +-104 +-128 +-98 +34 +99 +105 +79 +19 +-28 +-70 +-104 +-128 +-98 +35 +99 +105 +79 +20 +-28 +-70 +-103 +-128 +-98 +34 +99 +104 +78 +19 +-29 +-70 +-104 +-128 +-98 +34 +99 +104 +78 +19 +-29 +-70 +-104 +-128 +-98 +34 +99 +105 +79 +20 +-28 +-69 +-103 +-128 +-98 +35 +99 +105 +79 +20 +-28 +-70 +-104 +-128 +-97 +34 +99 +105 +79 +20 +-28 +-70 +-103 +-128 +-98 +35 +99 +105 +79 +20 +-28 +-70 +-103 +-128 +-97 +34 +99 +105 +78 +19 +-29 +-70 +-104 +-128 +-97 +35 +99 +105 +79 +19 +-29 +-70 +-104 +-128 +-98 +34 +99 +105 +79 +20 +-28 +-70 +-103 +-128 +-97 +35 +99 +105 +79 +19 +-29 +-70 +-104 +-128 +-97 +35 +99 +105 +79 +19 +-29 +-70 +-104 +-128 +-97 +35 +99 +105 +79 +20 +-28 +-70 +-103 +-128 +-97 +35 +99 +104 +78 +19 +-29 +-70 +-104 +-128 +-98 +34 +98 +105 +78 +19 +-29 +-70 +-104 +-128 +-98 +34 +98 +105 +78 +19 +-29 +-70 +-104 +-128 +-97 +35 +99 +105 +78 +19 +-29 +-70 +-104 +-128 +-97 +35 +100 +106 +79 +20 +-28 +-69 +-103 +-128 +-96 +36 +100 +106 +79 +20 +-28 +-69 +-103 +-128 +-97 +36 +100 +106 +80 +20 +-27 +-69 +-103 +-128 +-96 +36 +100 +106 +79 +20 +-28 +-69 +-103 +-128 +-97 +35 +100 +105 +78 +19 +-28 +-70 +-103 +-128 +-97 +35 +99 +106 +79 +20 +-28 +-69 +-103 +-128 +-97 +35 +99 +105 +79 +20 +-28 +-69 +-103 +-128 +-96 +36 +99 +106 +79 +20 +-28 +-69 +-103 +-112 +8 +79 +95 +33 +-17 +-60 +-95 +-108 +3 +72 +89 +28 +-21 +-63 +-98 +-109 +5 +74 +91 +30 +-19 +-62 +-97 +-108 +6 +74 +92 +31 +-18 +-61 +-96 +-107 +6 +75 +93 +32 +-18 +-61 +-96 +-107 +8 +77 +94 +33 +-17 +-60 +-95 +-106 +9 +77 +95 +33 +-17 +-60 +-95 +-106 +9 +78 +95 +34 +-16 +-59 +-95 +-106 +9 +77 +95 +34 +-16 +-59 +-94 +-105 +10 +79 +97 +35 +-15 +-58 +-94 +-104 +11 +79 +97 +35 +-15 +-58 +-93 +-104 +10 +78 +96 +34 +-16 +-59 +-94 +-105 +9 +78 +96 +35 +-15 +-59 +-94 +-105 +10 +78 +96 +34 +-15 +-59 +-94 +-105 +9 +77 +95 +34 +-16 +-59 +-95 +-105 +9 +77 +95 +33 +-16 +-59 +-95 +-106 +8 +76 +93 +33 +-17 +-60 +-95 +-106 +8 +77 +94 +33 +-17 +-60 +-95 +-106 +8 +77 +93 +32 +-17 +-60 +-95 +-106 +8 +77 +94 +33 +-17 +-60 +-95 +-106 +8 +77 +94 +33 +-17 +-60 +-95 +-106 +9 +77 +94 +33 +-17 +-60 +-95 +-106 +9 +77 +94 +33 +-17 +-60 +-95 +-106 +9 +77 +94 +33 +-17 +-60 +-95 +-106 +8 +77 +94 +32 +-17 +-60 +-95 +-106 +10 +77 +95 +33 +-17 +-59 +-95 +-106 +9 +77 +94 +33 +-17 +-60 +-95 +-106 +8 +76 +94 +33 +-17 +-60 +-95 +-106 +8 +76 +93 +32 +-17 +-60 +-95 +-106 +9 +77 +95 +33 +-17 +-59 +-94 +-106 +9 +77 +95 +34 +-16 +-59 +-95 +-105 +9 +77 +95 +33 +-17 +-59 +-95 +-109 +-96 +35 +101 +108 +83 +23 +-25 +-67 +-101 +-128 +-92 +40 +103 +109 +83 +23 +-25 +-67 +-101 +-128 +-93 +38 +101 +107 +81 +22 +-26 +-68 +-102 +-128 +-95 +37 +101 +107 +80 +21 +-27 +-69 +-102 +-128 +-96 +36 +100 +105 +79 +20 +-28 +-69 +-103 +-128 +-96 +36 +99 +105 +79 +20 +-28 +-69 +-103 +-128 +-96 +36 +99 +104 +78 +19 +-28 +-70 +-103 +-128 +-96 +35 +99 +105 +78 +19 +-29 +-70 +-103 +-128 +-96 +36 +99 +104 +78 +19 +-29 +-70 +-103 +-128 +-96 +35 +99 +104 +78 +19 +-28 +-69 +-103 +-128 +-96 +35 +99 +105 +78 +19 +-29 +-70 +-103 +-128 +-96 +36 +99 +104 +78 +19 +-29 +-70 +-103 +-128 +-96 +36 +99 +104 +78 +19 +-29 +-70 +-103 +-128 +-97 +35 +99 +104 +78 +19 +-29 +-70 +-103 +-128 +-96 +35 +99 +104 +77 +19 +-29 +-70 +-104 +-128 +-96 +35 +99 +104 +78 +19 +-29 +-70 +-103 +-128 +-97 +35 +99 +105 +78 +19 +-29 +-70 +-103 +-128 +-96 +35 +98 +104 +78 +19 +-29 +-70 +-103 +-128 +-95 +36 +99 +105 +78 +19 +-28 +-70 +-103 +-128 +-96 +36 +99 +105 +79 +20 +-28 +-69 +-103 +-128 +-95 +36 +100 +105 +79 +20 +-28 +-69 +-103 +-128 +-95 +36 +99 +106 +79 +20 +-28 +-69 +-103 +-128 +-94 +37 +101 +106 +79 +20 +-27 +-69 +-102 +-128 +-95 +37 +100 +106 +80 +21 +-27 +-68 +-102 +-128 +-95 +36 +100 +105 +79 +20 +-28 +-69 +-103 +-128 +-95 +36 +100 +105 +79 +20 +-28 +-69 +-103 +-111 +10 +79 +95 +33 +-16 +-59 +-95 +-107 +3 +71 +88 +28 +-21 +-63 +-98 +-109 +5 +72 +89 +29 +-20 +-63 +-97 +-108 +5 +74 +91 +30 +-19 +-61 +-96 +-107 +7 +75 +92 +31 +-18 +-61 +-95 +-106 +8 +76 +93 +32 +-17 +-60 +-95 +-106 +9 +77 +94 +33 +-17 +-60 +-95 +-105 +10 +77 +95 +34 +-16 +-59 +-94 +-104 +10 +77 +95 +34 +-16 +-59 +-94 +-104 +11 +78 +95 +34 +-16 +-59 +-94 +-104 +10 +77 +95 +34 +-16 +-59 +-94 +-105 +10 +77 +94 +33 +-16 +-59 +-94 +-105 +9 +77 +93 +33 +-17 +-60 +-95 +-105 +9 +76 +93 +32 +-17 +-60 +-95 +-106 +8 +76 +93 +32 +-17 +-60 +-95 +-106 +7 +75 +91 +31 +-18 +-61 +-96 +-107 +6 +74 +91 +30 +-19 +-61 +-96 +-107 +7 +74 +90 +30 +-19 +-62 +-96 +-107 +6 +74 +91 +30 +-19 +-61 +-96 +-107 +8 +75 +92 +31 +-18 +-61 +-95 +-106 +8 +76 +92 +31 +-18 +-60 +-95 +-106 +9 +77 +93 +32 +-17 +-60 +-95 +-105 +10 +77 +94 +33 +-17 +-59 +-94 +-105 +10 +77 +94 +33 +-16 +-59 +-94 +-104 +10 +79 +95 +34 +-16 +-58 +-94 +-104 +11 +79 +95 +34 +-16 +-58 +-93 +-104 +11 +79 +95 +34 +-15 +-58 +-93 +-104 +11 +79 +95 +34 +-16 +-58 +-94 +-104 +11 +78 +95 +34 +-16 +-59 +-93 +-104 +10 +77 +94 +33 +-16 +-59 +-94 +-104 +10 +77 +94 +33 +-17 +-59 +-94 +-105 +9 +77 +93 +32 +-17 +-60 +-95 +-106 +9 +77 +93 +32 +-17 +-60 +-95 +-105 +9 +77 +93 +32 +-17 +-60 +-95 +-105 +9 +77 +93 +32 +-17 +-60 +-95 +-105 +10 +77 +93 +33 +-17 +-60 +-95 +-105 +10 +77 +94 +33 +-17 +-59 +-94 +-105 +10 +77 +94 +33 +-16 +-59 +-94 +-104 +11 +78 +95 +34 +-16 +-59 +-94 +-104 +11 +78 +94 +73 +17 +-31 +-71 +-105 +-128 +-92 +41 +101 +110 +81 +24 +-25 +-66 +-100 +-128 +-92 +40 +101 +109 +79 +22 +-27 +-67 +-102 +-128 +-94 +38 +99 +107 +77 +21 +-28 +-68 +-103 +-128 +-95 +37 +98 +106 +77 +20 +-29 +-69 +-103 +-128 +-95 +37 +98 +106 +76 +19 +-29 +-69 +-104 +-128 +-95 +37 +98 +106 +76 +20 +-29 +-69 +-103 +-110 +10 +81 +94 +35 +-16 +-58 +-94 +-105 +4 +74 +88 +30 +-20 +-62 +-97 +-106 +6 +75 +90 +32 +-19 +-60 +-96 +-105 +8 +77 +91 +33 +-18 +-59 +-95 +-105 +7 +78 +91 +33 +-18 +-59 +-95 +-104 +9 +78 +92 +33 +-17 +-43 +-95 +-104 +9 +79 +92 +33 +-17 +-43 +-95 +-104 +8 +78 +92 +33 +-18 +-43 +-95 +-108 +-96 +36 +97 +107 +80 +23 +-26 +-66 +-101 +-128 +-92 +40 +100 +108 +77 +22 +-28 +-68 +-102 +-128 +-94 +38 +98 +106 +77 +20 +-29 +-69 +-103 +-128 +-95 +37 +98 +106 +76 +20 +-29 +-69 +-103 +-128 +-95 +37 +97 +106 +75 +19 +-29 +-69 +-104 +-128 +-95 +37 +97 +105 +75 +19 +-30 +-69 +-104 +-128 +-96 +37 +97 +105 +75 +19 +-30 +-69 +-103 +-128 +-95 +37 +97 +105 +75 +19 +-30 +-69 +-104 +-128 +-95 +36 +96 +105 +75 +19 +-30 +-69 +-104 +-128 +-95 +37 +97 +104 +75 +19 +-30 +-69 +-104 +-128 +-96 +37 +97 +105 +75 +19 +-30 +-69 +-104 +-128 +-95 +37 +97 +105 +75 +19 +-29 +-69 +-104 +-128 +-95 +37 +97 +105 +75 +19 +-30 +-69 +-104 +-110 +9 +79 +92 +33 +-17 +-43 +-95 +-106 +4 +73 +86 +28 +-22 +-62 +-98 +-107 +5 +75 +88 +31 +-20 +-61 +-96 +-106 +7 +77 +90 +32 +-18 +-60 +-95 +-105 +7 +77 +90 +32 +-18 +-60 +-95 +-104 +8 +78 +91 +33 +-18 +-43 +-95 +-104 +9 +78 +92 +33 +-18 +-43 +-95 +-104 +8 +78 +92 +33 +-18 +-43 +-95 +-104 +8 +78 +91 +33 +-18 +-43 +-95 +-104 +9 +78 +91 +33 +-18 +-43 +-95 +-104 +9 +78 +92 +33 +-17 +-43 +-95 +-104 +9 +78 +92 +33 +-17 +-43 +-94 +-104 +9 +78 +92 +33 +-17 +-43 +-95 +-104 +9 +78 +92 +33 +-17 +-43 +-94 +-104 +9 +78 +91 +33 +-18 +-43 +-95 +-104 +8 +78 +91 +33 +-18 +-43 +-95 +-104 +8 +78 +91 +33 +-18 +-43 +-95 +-104 +9 +78 +91 +33 +-18 +-43 +-95 +-104 +9 +78 +92 +33 +-17 +-43 +-94 +-103 +10 +79 +92 +33 +-17 +-42 +-94 +-103 +9 +79 +92 +33 +-17 +-42 +-94 +-103 +9 +79 +92 +33 +-17 +-42 +-94 +-103 +10 +79 +92 +34 +-17 +-42 +-94 +-103 +10 +79 +93 +34 +-17 +-42 +-94 +-103 +10 +78 +92 +34 +-17 +-42 +-94 +-103 +10 +79 +93 +34 +-17 +-42 +-94 +-103 +10 +79 +92 +34 +-17 +-42 +-94 +-103 +10 +79 +93 +35 +-16 +-58 +-94 +-103 +10 +79 +93 +34 +-16 +-58 +-94 +-102 +10 +79 +93 +35 +-16 +-58 +-94 +-102 +10 +79 +93 +34 +-17 +-42 +-94 +-103 +10 +78 +92 +33 +-17 +-42 +-94 +-103 +9 +78 +91 +33 +-17 +-43 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-95 +-104 +9 +78 +92 +33 +-17 +-43 +-94 +-104 +9 +78 +91 +33 +-18 +-43 +-95 +-104 +8 +78 +91 +33 +-18 +-43 +-94 +-104 +9 +78 +91 +33 +-18 +-43 +-95 +-104 +8 +78 +91 +33 +-18 +-59 +-95 +-104 +9 +78 +90 +32 +-18 +-59 +-95 +-104 +9 +78 +91 +33 +-18 +-43 +-95 +-104 +9 +78 +91 +33 +-17 +-43 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-95 +-103 +9 +78 +91 +33 +-18 +-43 +-95 +-104 +8 +78 +91 +32 +-18 +-43 +-95 +-104 +9 +77 +90 +32 +-18 +-59 +-95 +-104 +9 +77 +91 +32 +-18 +-43 +-95 +-103 +9 +78 +91 +33 +-17 +-43 +-94 +-104 +9 +78 +91 +33 +-17 +-43 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-94 +-103 +10 +78 +91 +33 +-17 +-42 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-94 +-103 +9 +78 +91 +33 +-17 +-43 +-94 +-103 +10 +78 +91 +33 +-17 +-42 +-94 +-103 +9 +77 +91 +33 +-17 +-43 +-94 +-103 +9 +78 +91 +33 +-17 +-43 +-94 +-103 +10 +78 +91 +33 +-17 +-43 +-94 +-103 +9 +78 +91 +33 +-17 +-43 +-94 +-103 +9 +78 +91 +33 +-17 +-43 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-94 +-103 +9 +78 +91 +33 +-17 +-42 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-94 +-103 +9 +78 +91 +33 +-18 +-43 +-94 +-103 +9 +78 +90 +32 +-18 +-43 +-94 +-103 +9 +78 +91 +33 +-17 +-42 +-94 +-103 +9 +78 +91 +33 +-17 +-42 +-94 +-103 +9 +78 +91 +33 +-17 +-42 +-94 +-103 +9 +78 +91 +33 +-17 +-43 +-94 +-103 +9 +78 +91 +33 +-17 +-42 +-94 +-103 +9 +77 +91 +33 +-18 +-43 +-94 +-107 +-94 +37 +97 +106 +77 +22 +-27 +-67 +-101 +-128 +-90 +41 +100 +108 +77 +22 +-27 +-67 +-101 +-128 +-91 +40 +99 +106 +76 +20 +-28 +-67 +-102 +-128 +-92 +39 +98 +106 +76 +20 +-28 +-68 +-102 +-128 +-93 +38 +97 +105 +75 +19 +-29 +-68 +-102 +-128 +-92 +38 +98 +105 +75 +19 +-29 +-69 +-103 +-128 +-93 +39 +98 +105 +76 +20 +-29 +-68 +-102 +-128 +-92 +39 +98 +106 +76 +20 +-28 +-68 +-102 +-128 +-92 +39 +98 +105 +75 +19 +-29 +-68 +-102 +-128 +-92 +38 +97 +104 +75 +19 +-29 +-68 +-102 +-128 +-92 +38 +97 +104 +74 +19 +-30 +-69 +-103 +-128 +-93 +38 +97 +104 +73 +18 +-30 +-69 +-103 +-128 +-94 +37 +96 +103 +73 +17 +-31 +-70 +-103 +-128 +-94 +37 +96 +103 +73 +18 +-30 +-69 +-103 +-128 +-94 +37 +96 +102 +73 +18 +-30 +-69 +-103 +-128 +-94 +37 +96 +103 +73 +18 +-30 +-69 +-103 +-128 +-94 +37 +96 +103 +73 +18 +-30 +-69 +-103 +-128 +-94 +37 +96 +103 +73 +18 +-30 +-69 +-103 +-128 +-93 +37 +96 +103 +73 +17 +-31 +-69 +-103 +-128 +-94 +37 +97 +103 +74 +18 +-30 +-69 +-103 +-128 +-93 +37 +96 +103 +74 +18 +-30 +-69 +-103 +-128 +-93 +38 +97 +103 +73 +18 +-30 +-69 +-103 +-128 +-93 +37 +97 +103 +73 +18 +-30 +-69 +-103 +-128 +-93 +37 +96 +104 +74 +18 +-30 +-69 +-103 +-128 +-93 +37 +97 +104 +73 +18 +-30 +-69 +-103 +-128 +-93 +37 +96 +103 +41 +-9 +-52 +-88 +-101 +7 +73 +88 +29 +-20 +-61 +-95 +-106 +7 +73 +88 +28 +-20 +-61 +-95 +-105 +8 +74 +89 +30 +-19 +-60 +-95 +-105 +9 +75 +90 +30 +-18 +-60 +-94 +-104 +9 +75 +90 +31 +-18 +-60 +-94 +-104 +9 +75 +91 +31 +-18 +-59 +-94 +-104 +9 +75 +91 +31 +-18 +-60 +-94 +-104 +9 +75 +91 +31 +-17 +-59 +-94 +-104 +10 +76 +91 +31 +-17 +-59 +-93 +-103 +10 +76 +92 +32 +-17 +-59 +-93 +-103 +11 +77 +92 +32 +-17 +-59 +-93 +-103 +11 +77 +93 +32 +-16 +-58 +-93 +-103 +11 +77 +92 +32 +-17 +-58 +-93 +-102 +11 +77 +92 +32 +-17 +-59 +-93 +-102 +11 +77 +92 +32 +-17 +-59 +-93 +-103 +11 +77 +92 +32 +-17 +-58 +-93 +-103 +11 +77 +92 +32 +-17 +-59 +-93 +-103 +10 +77 +92 +32 +-17 +-58 +-93 +-103 +10 +76 +92 +32 +-17 +-59 +-93 +-103 +10 +76 +91 +31 +-17 +-59 +-93 +-103 +10 +76 +91 +31 +-17 +-59 +-93 +-103 +10 +76 +91 +31 +-17 +-59 +-93 +-103 +10 +76 +91 +31 +-17 +-59 +-93 +-103 +10 +76 +91 +31 +-17 +-59 +-93 +-103 +10 +76 +91 +31 +-17 +-59 +-93 +-103 +11 +76 +91 +31 +-17 +-59 +-93 +-103 +11 +76 +92 +32 +-17 +-58 +-93 +-102 +11 +77 +93 +33 +-16 +-58 +-92 +-102 +11 +77 +93 +33 +-16 +-58 +-92 +-102 +12 +78 +93 +33 +-16 +-58 +-92 +-101 +13 +77 +93 +33 +-15 +-57 +-92 +-102 +12 +77 +92 +71 +16 +-31 +-70 +-103 +-128 +-89 +41 +99 +107 +77 +21 +-27 +-66 +-100 +-112 +-90 +40 +98 +105 +75 +19 +-28 +-67 +-101 +-128 +-91 +39 +97 +104 +73 +18 +-30 +-68 +-102 +-128 +-92 +38 +97 +103 +72 +17 +-30 +-69 +-103 +-128 +-92 +37 +96 +103 +72 +17 +-31 +-69 +-103 +-128 +-93 +37 +96 +102 +72 +17 +-30 +-69 +-103 +-128 +-93 +37 +96 +102 +72 +17 +-30 +-69 +-103 +-128 +-92 +37 +96 +102 +72 +17 +-31 +-69 +-103 +-128 +-92 +38 +96 +103 +72 +17 +-30 +-69 +-102 +-128 +-93 +37 +95 +103 +72 +18 +-30 +-69 +-102 +-128 +-92 +37 +96 +102 +72 +17 +-31 +-69 +-103 +-128 +-92 +38 +96 +101 +72 +17 +-31 +-69 +-103 +-128 +-92 +38 +96 +102 +41 +-9 +-52 +-87 +-100 +8 +73 +87 +28 +-20 +-61 +-95 +-105 +7 +73 +88 +28 +-19 +-61 +-95 +-105 +8 +74 +89 +29 +-19 +-60 +-94 +-104 +8 +74 +89 +30 +-18 +-60 +-94 +-103 +10 +76 +90 +31 +-17 +-59 +-93 +-103 +10 +75 +91 +31 +-17 +-59 +-93 +-102 +11 +76 +91 +31 +-17 +-59 +-93 +-106 +-93 +36 +98 +103 +77 +20 +-27 +-67 +-100 +-112 +-88 +40 +101 +104 +77 +19 +-27 +-67 +-100 +-112 +-89 +39 +100 +103 +76 +19 +-28 +-68 +-101 +-128 +-91 +38 +98 +101 +75 +17 +-29 +-69 +-101 +-128 +-91 +38 +97 +101 +74 +17 +-29 +-69 +-101 +-128 +-91 +37 +98 +102 +74 +17 +-29 +-69 +-101 +-128 +-91 +37 +97 +101 +74 +16 +-30 +-70 +-102 +-128 +-91 +37 +98 +101 +74 +17 +-29 +-69 +-101 +-128 +-91 +37 +97 +101 +74 +17 +-29 +-69 +-101 +-128 +-91 +37 +98 +101 +74 +17 +-29 +-69 +-101 +-128 +-91 +37 +97 +101 +73 +16 +-30 +-69 +-102 +-128 +-91 +37 +97 +101 +73 +16 +-30 +-70 +-102 +-128 +-91 +37 +97 +101 +74 +17 +-29 +-69 +-102 +-128 +-91 +37 +97 +101 +74 +17 +-29 +-69 +-101 +-128 +-91 +37 +97 +101 +73 +16 +-30 +-69 +-102 +-128 +-91 +37 +97 +101 +74 +16 +-29 +-69 +-101 +-128 +-91 +37 +98 +101 +74 +17 +-29 +-69 +-101 +-128 +-90 +38 +98 +102 +75 +17 +-29 +-68 +-101 +-128 +-90 +38 +98 +102 +75 +18 +-29 +-68 +-101 +-128 +-89 +38 +99 +103 +75 +18 +-28 +-68 +-101 +-128 +-89 +38 +99 +102 +75 +18 +-28 +-68 +-101 +-128 +-90 +39 +99 +102 +75 +18 +-28 +-68 +-101 +-128 +-90 +38 +97 +101 +74 +17 +-29 +-69 +-101 +-128 +-90 +38 +97 +101 +74 +17 +-29 +-69 +-101 +-128 +-91 +36 +97 +100 +72 +16 +-30 +-70 +-102 +-128 +-91 +36 +97 +100 +73 +16 +-30 +-70 +-102 +-128 +-91 +37 +97 +100 +73 +16 +-30 +-69 +-101 +-128 +-91 +37 +97 +100 +74 +16 +-29 +-69 +-101 +-128 +-90 +38 +97 +101 +74 +17 +-29 +-69 +-101 +-128 +-90 +38 +99 +102 +75 +18 +-28 +-68 +-100 +-128 +-89 +38 +99 +102 +75 +17 +-28 +-68 +-101 +-128 +-89 +38 +98 +102 +74 +17 +-29 +-69 +-101 +-106 +13 +79 +93 +33 +-15 +-57 +-91 +-103 +6 +71 +85 +27 +-21 +-62 +-95 +-105 +7 +72 +87 +28 +-19 +-61 +-94 +-104 +7 +73 +87 +28 +-19 +-60 +-94 +-104 +6 +72 +87 +28 +-20 +-61 +-94 +-104 +7 +72 +86 +28 +-20 +-61 +-95 +-104 +7 +72 +86 +28 +-20 +-61 +-95 +-104 +8 +73 +87 +28 +-19 +-60 +-94 +-107 +-95 +33 +95 +100 +74 +17 +-29 +-68 +-101 +-128 +-88 +39 +100 +102 +75 +18 +-28 +-68 +-100 +-112 +-88 +40 +100 +103 +75 +18 +-28 +-68 +-100 +-112 +-88 +40 +99 +103 +75 +18 +-28 +-68 +-100 +-112 +-88 +39 +99 +102 +74 +17 +-28 +-68 +-100 +-128 +-88 +39 +99 +102 +75 +18 +-28 +-68 +-100 +-112 +-89 +38 +99 +102 +43 +-8 +-50 +-86 +-98 +9 +76 +86 +30 +-19 +-59 +-94 +-103 +8 +75 +86 +30 +-19 +-59 +-94 +-102 +8 +75 +86 +30 +-19 +-59 +-94 +-102 +8 +75 +86 +30 +-19 +-59 +-94 +-102 +9 +76 +87 +30 +-19 +-59 +-94 +-102 +9 +76 +87 +31 +-18 +-59 +-93 +-101 +10 +77 +88 +31 +-18 +-58 +-93 +-101 +10 +77 +88 +31 +-18 +-58 +-93 +-101 +10 +78 +89 +32 +-17 +-41 +-92 +-100 +11 +78 +89 +32 +-17 +-41 +-92 +-101 +11 +78 +89 +32 +-17 +-41 +-92 +-101 +11 +78 +89 +32 +-17 +-41 +-92 +-100 +11 +78 +89 +33 +-17 +-41 +-92 +-100 +11 +78 +89 +32 +-17 +-41 +-92 +-100 +11 +78 +89 +32 +-17 +-41 +-92 +-101 +10 +77 +88 +32 +-18 +-42 +-92 +-101 +11 +78 +89 +32 +-17 +-41 +-92 +-101 +10 +77 +88 +32 +-18 +-42 +-93 +-101 +10 +77 +88 +31 +-18 +-42 +-93 +-101 +10 +77 +89 +32 +-17 +-42 +-92 +-100 +11 +78 +88 +32 +-17 +-41 +-92 +-100 +11 +78 +90 +33 +-17 +-41 +-92 +-100 +11 +78 +90 +33 +-17 +-41 +-92 +-100 +11 +78 +90 +33 +-17 +-41 +-92 +-100 +11 +78 +89 +33 +-17 +-41 +-92 +-100 +11 +78 +89 +32 +-17 +-41 +-92 +-100 +11 +78 +89 +32 +-17 +-41 +-92 +-100 +10 +77 +88 +31 +-18 +-42 +-92 +-101 +10 +76 +88 +31 +-18 +-42 +-93 +-101 +9 +76 +87 +31 +-18 +-58 +-93 +-101 +9 +76 +87 +31 +-18 +-58 +-93 +-101 +9 +76 +87 +31 +-18 +-58 +-93 +-101 +10 +76 +87 +31 +-18 +-58 +-93 +-101 +10 +77 +87 +31 +-18 +-58 +-93 +-101 +10 +77 +88 +31 +-18 +-58 +-93 +-101 +10 +77 +88 +31 +-18 +-42 +-93 +-101 +10 +77 +88 +31 +-18 +-58 +-93 +-101 +10 +77 +88 +31 +-18 +-42 +-92 +-101 +11 +77 +88 +31 +-18 +-42 +-92 +-101 +10 +76 +88 +31 +-18 +-58 +-93 +-101 +10 +76 +88 +31 +-18 +-42 +-92 +-101 +10 +76 +88 +31 +-18 +-58 +-93 +-101 +10 +77 +88 +31 +-18 +-42 +-92 +-101 +10 +77 +88 +31 +-18 +-58 +-93 +-101 +10 +77 +88 +31 +-18 +-58 +-92 +-100 +10 +77 +88 +31 +-18 +-42 +-92 +-100 +10 +76 +88 +31 +-18 +-42 +-92 +-100 +10 +77 +88 +31 +-18 +-41 +-92 +-100 +10 +77 +88 +32 +-17 +-41 +-92 +-100 +10 +77 +88 +32 +-17 +-41 +-92 +-100 +11 +77 +88 +31 +-18 +-42 +-92 +-100 +10 +77 +88 +32 +-17 +-41 +-92 +-101 +10 +77 +88 +31 +-18 +-41 +-92 +-100 +10 +77 +88 +31 +-18 +-58 +-92 +-100 +10 +77 +87 +31 +-18 +-58 +-92 +-101 +10 +77 +88 +68 +12 +-32 +-71 +-103 +-128 +-88 +38 +98 +101 +74 +18 +-28 +-67 +-99 +-111 +-87 +39 +98 +101 +73 +17 +-29 +-68 +-100 +-112 +-88 +38 +97 +100 +72 +16 +-29 +-69 +-101 +-112 +-89 +38 +97 +100 +72 +16 +-29 +-69 +-101 +-112 +-89 +38 +97 +99 +72 +16 +-29 +-69 +-101 +-112 +-89 +38 +97 +100 +72 +16 +-29 +-68 +-100 +-112 +-89 +38 +97 +100 +73 +16 +-29 +-68 +-100 +-112 +-88 +38 +97 +100 +72 +16 +-29 +-68 +-100 +-112 +-88 +38 +98 +101 +73 +16 +-29 +-68 +-100 +-112 +-89 +38 +98 +101 +73 +17 +-29 +-68 +-100 +-112 +-88 +39 +97 +100 +73 +16 +-29 +-68 +-100 +-112 +-88 +39 +98 +100 +72 +16 +-29 +-68 +-100 +-112 +-88 +39 +98 +101 +43 +-8 +-49 +-85 +-97 +10 +76 +86 +30 +-19 +-58 +-93 +-101 +9 +75 +86 +30 +-18 +-58 +-93 +-101 +10 +77 +87 +31 +-18 +-58 +-92 +-101 +9 +76 +87 +31 +-18 +-58 +-93 +-100 +10 +77 +87 +31 +-18 +-58 +-92 +-100 +10 +76 +87 +31 +-18 +-42 +-92 +-100 +10 +76 +87 +31 +-18 +-42 +-92 +-100 +9 +76 +87 +31 +-18 +-58 +-92 +-100 +10 +76 +87 +31 +-18 +-58 +-92 +-100 +10 +77 +87 +31 +-18 +-42 +-92 +-100 +10 +76 +87 +31 +-18 +-58 +-92 +-100 +10 +76 +87 +31 +-18 +-58 +-92 +-100 +10 +76 +87 +31 +-18 +-58 +-92 +-100 +10 +77 +88 +31 +-18 +-41 +-92 +-100 +10 +77 +87 +31 +-18 +-58 +-92 +-100 +10 +76 +87 +31 +-18 +-58 +-92 +-100 +10 +77 +87 +31 +-18 +-58 +-92 +-100 +10 +76 +87 +31 +-18 +-58 +-92 +-100 +10 +77 +87 +31 +-18 +-58 +-92 +-100 +10 +76 +87 +31 +-18 +-58 +-92 +-100 +10 +77 +87 +31 +-18 +-41 +-92 +-100 +11 +77 +88 +31 +-18 +-41 +-92 +-100 +11 +77 +88 +31 +-17 +-41 +-92 +-100 +10 +77 +87 +31 +-18 +-41 +-92 +-100 +11 +77 +87 +31 +-18 +-41 +-92 +-100 +10 +77 +88 +31 +-18 +-41 +-92 +-99 +11 +77 +87 +31 +-18 +-41 +-92 +-100 +10 +77 +88 +31 +-18 +-41 +-92 +-100 +11 +77 +88 +31 +-17 +-41 +-92 +-100 +11 +77 +87 +31 +-18 +-41 +-92 +-100 +11 +77 +88 +31 +-18 +-41 +-92 +-100 +10 +77 +87 +67 +12 +-33 +-71 +-102 +-128 +-88 +38 +97 +100 +73 +17 +-28 +-67 +-99 +-111 +-87 +39 +98 +101 +72 +16 +-29 +-68 +-100 +-111 +-88 +38 +97 +99 +71 +15 +-30 +-69 +-100 +-112 +-88 +38 +97 +100 +72 +16 +-29 +-68 +-100 +-111 +-88 +38 +97 +99 +72 +16 +-29 +-68 +-100 +-111 +-88 +38 +97 +99 +71 +16 +-29 +-68 +-100 +-104 +15 +80 +92 +33 +-15 +-56 +-89 +-100 +8 +72 +85 +27 +-20 +-60 +-93 +-102 +9 +73 +86 +28 +-18 +-59 +-92 +-101 +10 +74 +87 +29 +-18 +-58 +-92 +-101 +11 +75 +88 +30 +-17 +-58 +-91 +-100 +11 +74 +88 +30 +-17 +-58 +-91 +-100 +11 +75 +88 +30 +-17 +-58 +-91 +-100 +12 +75 +89 +65 +12 +-33 +-71 +-103 +-128 +-88 +39 +97 +103 +72 +18 +-28 +-66 +-99 +-110 +-87 +41 +97 +101 +71 +17 +-29 +-67 +-100 +-110 +-87 +40 +97 +102 +71 +17 +-29 +-67 +-100 +-110 +-88 +40 +97 +102 +71 +17 +-29 +-67 +-100 +-110 +-87 +40 +96 +102 +72 +18 +-29 +-67 +-100 +-110 +-87 +41 +97 +101 +71 +17 +-29 +-67 +-100 +-110 +-88 +40 +97 +102 +71 +18 +-29 +-67 +-100 +-110 +-88 +40 +96 +101 +70 +16 +-30 +-68 +-100 +-111 +-88 +39 +95 +100 +70 +16 +-30 +-68 +-100 +-111 +-89 +38 +95 +99 +69 +15 +-31 +-68 +-101 +-111 +-89 +39 +95 +99 +69 +15 +-31 +-68 +-101 +-111 +-88 +39 +95 +100 +69 +15 +-31 +-68 +-101 +-111 +-89 +38 +95 +99 +69 +15 +-31 +-68 +-101 +-111 +-89 +39 +95 +100 +69 +15 +-31 +-68 +-101 +-111 +-90 +38 +95 +100 +69 +16 +-31 +-68 +-101 +-111 +-88 +39 +95 +100 +69 +15 +-31 +-68 +-101 +-111 +-89 +39 +95 +99 +68 +15 +-31 +-68 +-101 +-111 +-88 +39 +95 +100 +69 +16 +-30 +-68 +-100 +-111 +-88 +39 +95 +100 +69 +16 +-30 +-68 +-100 +-111 +-88 +40 +95 +100 +70 +16 +-30 +-67 +-100 +-111 +-88 +39 +95 +100 +69 +16 +-30 +-68 +-100 +-111 +-88 +39 +95 +100 +69 +16 +-30 +-68 +-100 +-111 +-88 +39 +95 +99 +69 +16 +-30 +-68 +-100 +-111 +-88 +40 +95 +99 +68 +15 +-31 +-68 +-101 +-111 +-88 +39 +95 +100 +69 +16 +-30 +-68 +-100 +-111 +-88 +40 +96 +100 +69 +16 +-30 +-68 +-100 +-111 +-88 +39 +95 +100 +69 +15 +-30 +-68 +-100 +-111 +-89 +39 +95 +100 +68 +15 +-31 +-68 +-101 +-111 +-89 +38 +94 +99 +69 +15 +-31 +-68 +-100 +-111 +-88 +39 +95 +100 +68 +15 +-31 +-68 +-100 +-111 +-88 +39 +95 +100 +69 +16 +-30 +-67 +-100 +-110 +-87 +40 +96 +101 +41 +-8 +-50 +-84 +-112 +12 +75 +88 +30 +-17 +-58 +-91 +-100 +11 +74 +86 +28 +-18 +-58 +-91 +-100 +11 +75 +88 +30 +-17 +-58 +-91 +-99 +12 +75 +88 +30 +-17 +-58 +-90 +-99 +12 +75 +88 +30 +-17 +-57 +-90 +-99 +12 +76 +88 +30 +-17 +-57 +-90 +-99 +12 +75 +88 +30 +-17 +-57 +-90 +-99 +12 +75 +87 +29 +-17 +-58 +-91 +-100 +12 +75 +88 +30 +-17 +-58 +-91 +-100 +11 +75 +88 +30 +-17 +-57 +-90 +-99 +11 +75 +88 +30 +-17 +-57 +-91 +-99 +11 +75 +87 +29 +-17 +-58 +-91 +-100 +11 +75 +88 +30 +-17 +-58 +-91 +-99 +12 +75 +87 +29 +-17 +-58 +-91 +-99 +12 +75 +88 +30 +-17 +-57 +-90 +-99 +13 +76 +89 +31 +-16 +-57 +-90 +-99 +13 +76 +89 +31 +-16 +-56 +-90 +-98 +13 +77 +89 +31 +-16 +-56 +-90 +-98 +14 +77 +90 +32 +-15 +-56 +-89 +-114 +14 +77 +90 +31 +-15 +-56 +-89 +-98 +13 +77 +89 +31 +-16 +-56 +-90 +-98 +13 +76 +89 +31 +-16 +-57 +-90 +-99 +12 +75 +88 +30 +-17 +-57 +-90 +-99 +12 +75 +88 +30 +-17 +-58 +-90 +-99 +11 +74 +87 +29 +-17 +-58 +-91 +-99 +11 +74 +87 +29 +-17 +-58 +-91 +-100 +11 +74 +86 +29 +-18 +-58 +-91 +-100 +11 +74 +87 +29 +-17 +-58 +-91 +-100 +11 +74 +87 +29 +-17 +-58 +-91 +-100 +11 +74 +87 +29 +-18 +-58 +-91 +-99 +11 +74 +87 +29 +-17 +-58 +-91 +-100 +12 +75 +87 +63 +11 +-34 +-71 +-102 +-112 +-88 +39 +95 +101 +70 +16 +-30 +-67 +-99 +-110 +-87 +40 +96 +100 +70 +16 +-30 +-67 +-99 +-109 +-87 +40 +95 +99 +68 +15 +-30 +-67 +-100 +-110 +-88 +39 +95 +100 +68 +16 +-30 +-67 +-100 +-110 +-88 +39 +94 +99 +68 +15 +-30 +-67 +-100 +-110 +-88 +40 +95 +99 +68 +15 +-31 +-68 +-100 +-110 +-88 +39 +95 +99 +69 +16 +-30 +-67 +-100 +-110 +-88 +39 +95 +100 +69 +16 +-30 +-67 +-100 +-110 +-87 +40 +95 +100 +69 +16 +-30 +-67 +-99 +-109 +-88 +40 +95 +100 +69 +16 +-30 +-67 +-99 +-109 +-87 +40 +95 +100 +69 +16 +-30 +-67 +-99 +-110 +-87 +40 +96 +100 +69 +16 +-30 +-67 +-100 +-110 +-87 +40 +95 +99 +69 +16 +-30 +-67 +-99 +-109 +-87 +40 +95 +100 +68 +15 +-30 +-67 +-100 +-110 +-88 +39 +95 +100 +69 +16 +-30 +-67 +-99 +-110 +-87 +40 +95 +99 +68 +15 +-30 +-67 +-100 +-110 +-88 +40 +95 +99 +68 +15 +-30 +-67 +-100 +-110 +-87 +40 +95 +99 +68 +15 +-30 +-67 +-100 +-110 +-87 +40 +95 +99 +68 +15 +-31 +-68 +-100 +-110 +-88 +40 +95 +100 +69 +16 +-30 +-67 +-99 +-109 +-87 +39 +95 +99 +68 +15 +-30 +-67 +-100 +-110 +-87 +40 +95 +99 +68 +15 +-30 +-67 +-100 +-109 +-88 +39 +95 +99 +68 +15 +-30 +-67 +-100 +-110 +-87 +39 +95 +99 +68 +15 +-30 +-67 +-100 +-110 +-87 +40 +95 +99 +68 +16 +-30 +-67 +-100 +-110 +-87 +40 +95 +100 +40 +-8 +-49 +-83 +-111 +13 +76 +87 +30 +-17 +-57 +-90 +-99 +12 +74 +87 +29 +-17 +-57 +-90 +-99 +12 +75 +88 +30 +-17 +-57 +-90 +-98 +12 +75 +88 +31 +-16 +-56 +-89 +-114 +13 +76 +88 +31 +-16 +-56 +-89 +-98 +13 +76 +88 +31 +-16 +-56 +-89 +-114 +13 +76 +88 +31 +-16 +-56 +-89 +-98 +12 +75 +88 +30 +-16 +-56 +-89 +-98 +12 +75 +87 +30 +-17 +-57 +-90 +-98 +12 +75 +87 +29 +-17 +-57 +-90 +-99 +12 +74 +87 +29 +-17 +-57 +-90 +-99 +11 +74 +87 +29 +-17 +-57 +-90 +-99 +11 +74 +87 +30 +-17 +-57 +-90 +-99 +12 +75 +87 +30 +-17 +-57 +-90 +-98 +13 +75 +87 +30 +-17 +-57 +-90 +-98 +12 +75 +88 +31 +-16 +-56 +-89 +-113 +13 +76 +89 +31 +-16 +-56 +-89 +-114 +13 +76 +88 +30 +-16 +-56 +-89 +-113 +13 +76 +88 +31 +-16 +-56 +-89 +-98 +12 +75 +87 +30 +-17 +-57 +-89 +-98 +12 +75 +86 +29 +-17 +-57 +-90 +-99 +11 +74 +86 +29 +-17 +-57 +-90 +-99 +11 +73 +85 +28 +-18 +-58 +-91 +-100 +9 +72 +84 +28 +-18 +-58 +-91 +-100 +9 +72 +84 +27 +-19 +-59 +-91 +-100 +9 +72 +83 +27 +-19 +-59 +-91 +-100 +9 +72 +83 +26 +-19 +-59 +-92 +-101 +9 +72 +84 +27 +-19 +-58 +-91 +-100 +11 +74 +86 +29 +-17 +-58 +-90 +-99 +12 +74 +87 +29 +-17 +-57 +-90 +-98 +13 +75 +88 +30 +-16 +-56 +-89 +-98 +13 +76 +88 +31 +-16 +-56 +-89 +-113 +13 +76 +89 +31 +-16 +-56 +-89 +-113 +14 +77 +88 +31 +-16 +-56 +-89 +-113 +14 +76 +88 +31 +-16 +-56 +-89 +-114 +13 +76 +88 +30 +-16 +-56 +-89 +-113 +13 +76 +88 +30 +-16 +-56 +-89 +-114 +13 +76 +87 +30 +-16 +-56 +-89 +-98 +12 +75 +87 +29 +-17 +-57 +-89 +-102 +-91 +35 +93 +96 +69 +14 +-30 +-68 +-99 +-109 +-86 +39 +96 +98 +69 +15 +-29 +-67 +-99 +-109 +-86 +39 +96 +98 +70 +15 +-29 +-67 +-98 +-109 +-86 +39 +97 +98 +69 +15 +-29 +-67 +-98 +-109 +-85 +39 +96 +98 +70 +16 +-29 +-67 +-98 +-109 +-85 +40 +97 +99 +70 +16 +-29 +-67 +-98 +-109 +-85 +40 +97 +99 +42 +-8 +-48 +-83 +-109 +12 +77 +86 +31 +-17 +-40 +-90 +-98 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +11 +75 +84 +29 +-18 +-57 +-90 +-98 +11 +75 +84 +30 +-18 +-57 +-90 +-98 +11 +76 +85 +30 +-17 +-40 +-90 +-98 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +11 +76 +85 +30 +-18 +-40 +-90 +-98 +11 +76 +85 +64 +10 +-33 +-70 +-101 +-111 +-86 +39 +97 +99 +71 +16 +-28 +-66 +-97 +-108 +-84 +40 +98 +99 +71 +16 +-28 +-66 +-97 +-108 +-84 +40 +97 +100 +71 +16 +-28 +-66 +-97 +-108 +-85 +40 +98 +99 +71 +16 +-28 +-66 +-97 +-108 +-85 +40 +97 +99 +71 +16 +-28 +-66 +-97 +-108 +-85 +39 +97 +98 +70 +15 +-29 +-67 +-98 +-109 +-86 +38 +96 +98 +69 +15 +-29 +-67 +-98 +-109 +-86 +38 +95 +97 +68 +14 +-30 +-68 +-99 +-110 +-87 +38 +95 +97 +68 +14 +-30 +-68 +-99 +-109 +-87 +38 +95 +97 +68 +14 +-30 +-68 +-99 +-109 +-86 +38 +95 +97 +68 +14 +-30 +-68 +-99 +-110 +-86 +38 +96 +97 +69 +14 +-30 +-68 +-99 +-109 +-86 +38 +96 +97 +41 +-9 +-49 +-84 +-110 +12 +76 +85 +30 +-18 +-40 +-90 +-98 +10 +75 +84 +29 +-18 +-57 +-90 +-98 +10 +75 +84 +29 +-18 +-56 +-90 +-98 +10 +75 +84 +29 +-18 +-57 +-91 +-98 +11 +75 +84 +29 +-18 +-56 +-90 +-98 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +12 +76 +85 +30 +-17 +-40 +-90 +-97 +11 +75 +85 +30 +-17 +-40 +-90 +-97 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +12 +76 +85 +31 +-17 +-40 +-90 +-97 +12 +76 +85 +31 +-17 +-40 +-90 +-97 +12 +77 +85 +31 +-17 +-40 +-90 +-97 +11 +76 +85 +31 +-17 +-40 +-90 +-97 +12 +76 +85 +30 +-17 +-40 +-90 +-97 +11 +76 +85 +30 +-18 +-40 +-90 +-97 +12 +76 +85 +30 +-18 +-40 +-90 +-97 +12 +76 +85 +31 +-17 +-40 +-89 +-97 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +12 +76 +85 +30 +-17 +-40 +-90 +-97 +12 +76 +85 +30 +-17 +-40 +-90 +-97 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +11 +75 +84 +30 +-18 +-40 +-90 +-97 +12 +76 +84 +30 +-18 +-40 +-90 +-97 +12 +76 +85 +30 +-17 +-40 +-90 +-97 +12 +76 +85 +30 +-17 +-40 +-89 +-97 +11 +76 +85 +30 +-17 +-40 +-90 +-97 +12 +77 +85 +31 +-17 +-40 +-89 +-97 +12 +77 +86 +31 +-17 +-39 +-89 +-97 +13 +77 +86 +31 +-16 +-39 +-89 +-97 +12 +77 +86 +31 +-17 +-39 +-89 +-112 +13 +77 +86 +31 +-17 +-39 +-89 +-97 +13 +77 +85 +31 +-17 +-39 +-89 +-97 +13 +77 +86 +31 +-16 +-39 +-89 +-97 +12 +77 +86 +31 +-16 +-39 +-89 +-112 +13 +78 +86 +31 +-16 +-39 +-89 +-112 +13 +77 +86 +31 +-17 +-39 +-89 +-112 +13 +77 +86 +31 +-17 +-39 +-89 +-97 +12 +76 +86 +31 +-17 +-39 +-89 +-112 +12 +77 +86 +31 +-17 +-39 +-89 +-97 +12 +76 +85 +31 +-17 +-40 +-89 +-97 +11 +76 +85 +30 +-17 +-40 +-89 +-97 +10 +75 +84 +30 +-17 +-40 +-90 +-97 +11 +75 +84 +30 +-17 +-40 +-89 +-97 +11 +75 +84 +30 +-17 +-40 +-89 +-97 +12 +75 +85 +30 +-17 +-40 +-89 +-97 +11 +75 +85 +30 +-17 +-40 +-89 +-97 +11 +75 +84 +30 +-17 +-40 +-89 +-97 +11 +75 +85 +30 +-17 +-40 +-89 +-97 +11 +76 +85 +30 +-17 +-40 +-89 +-97 +10 +75 +84 +30 +-17 +-40 +-89 +-97 +11 +75 +85 +30 +-17 +-40 +-89 +-97 +11 +76 +84 +30 +-18 +-40 +-89 +-97 +11 +76 +85 +30 +-17 +-40 +-89 +-97 +11 +75 +85 +30 +-17 +-40 +-89 +-97 +11 +75 +84 +30 +-17 +-40 +-89 +-97 +12 +76 +85 +30 +-17 +-40 +-89 +-97 +12 +76 +85 +31 +-17 +-39 +-89 +-97 +11 +76 +85 +30 +-17 +-40 +-89 +-97 +12 +76 +85 +30 +-17 +-40 +-89 +-97 +11 +76 +85 +30 +-17 +-39 +-89 +-97 +11 +75 +84 +30 +-17 +-40 +-89 +-97 +11 +76 +84 +30 +-17 +-40 +-89 +-97 +12 +76 +85 +31 +-17 +-39 +-89 +-97 +12 +76 +85 +31 +-17 +-39 +-89 +-97 +12 +76 +85 +30 +-17 +-40 +-89 +-97 +11 +76 +85 +30 +-17 +-39 +-89 +-97 +11 +76 +84 +30 +-17 +-40 +-89 +-97 +12 +76 +85 +31 +-17 +-39 +-89 +-97 +11 +76 +85 +30 +-17 +-39 +-89 +-97 +11 +75 +84 +63 +10 +-33 +-70 +-100 +-111 +-87 +37 +95 +97 +68 +14 +-29 +-67 +-98 +-108 +-85 +39 +97 +97 +69 +15 +-29 +-66 +-97 +-108 +-86 +39 +96 +97 +69 +15 +-29 +-67 +-97 +-108 +-85 +39 +96 +97 +69 +15 +-29 +-66 +-97 +-108 +-86 +39 +96 +98 +69 +15 +-29 +-67 +-97 +-108 +-85 +39 +96 +97 +68 +14 +-29 +-67 +-98 +-108 +-85 +39 +96 +98 +69 +15 +-29 +-66 +-97 +-108 +-85 +39 +96 +97 +69 +15 +-29 +-67 +-97 +-108 +-85 +39 +96 +97 +69 +15 +-29 +-67 +-97 +-108 +-85 +39 +97 +98 +69 +15 +-29 +-67 +-97 +-108 +-85 +40 +97 +98 +69 +15 +-29 +-66 +-97 +-108 +-84 +40 +97 +99 +69 +15 +-28 +-66 +-97 +-108 +-85 +40 +97 +99 +70 +16 +-28 +-66 +-97 +-107 +-84 +40 +98 +99 +70 +16 +-28 +-66 +-97 +-107 +-84 +40 +98 +99 +70 +16 +-28 +-66 +-97 +-107 +-84 +40 +97 +98 +70 +16 +-28 +-66 +-97 +-107 +-84 +39 +97 +98 +69 +15 +-28 +-66 +-97 +-107 +-85 +39 +96 +97 +69 +15 +-29 +-66 +-97 +-108 +-85 +39 +95 +96 +67 +14 +-30 +-67 +-98 +-108 +-86 +38 +95 +97 +68 +14 +-29 +-67 +-98 +-108 +-86 +38 +96 +97 +68 +14 +-29 +-67 +-98 +-108 +-86 +38 +95 +97 +67 +14 +-30 +-67 +-98 +-108 +-86 +38 +96 +97 +69 +15 +-29 +-67 +-97 +-108 +-86 +38 +96 +97 +68 +14 +-29 +-67 +-97 +-108 +-86 +38 +96 +96 +68 +14 +-29 +-67 +-97 +-100 +17 +80 +91 +34 +-13 +-53 +-86 +-112 +10 +72 +84 +28 +-18 +-57 +-89 +-98 +10 +72 +84 +28 +-18 +-57 +-89 +-114 +11 +74 +85 +29 +-17 +-56 +-89 +-114 +11 +74 +86 +29 +-17 +-56 +-88 +-113 +12 +74 +86 +29 +-17 +-56 +-88 +-113 +12 +74 +86 +29 +-17 +-56 +-88 +-113 +12 +74 +86 +29 +-16 +-56 +-88 +-113 +11 +74 +86 +29 +-16 +-56 +-88 +-113 +12 +74 +86 +29 +-17 +-56 +-88 +-113 +12 +74 +86 +29 +-16 +-56 +-88 +-113 +12 +74 +86 +29 +-16 +-56 +-88 +-113 +12 +75 +86 +30 +-16 +-56 +-88 +-113 +12 +74 +86 +29 +-16 +-56 +-88 +-113 +12 +75 +86 +29 +-16 +-56 +-88 +-113 +12 +74 +85 +28 +-17 +-56 +-89 +-114 +11 +74 +85 +29 +-17 +-56 +-89 +-113 +12 +74 +86 +29 +-17 +-56 +-88 +-113 +12 +75 +86 +30 +-16 +-56 +-88 +-113 +12 +75 +86 +30 +-16 +-56 +-88 +-113 +12 +75 +87 +30 +-16 +-55 +-87 +-112 +13 +75 +87 +30 +-16 +-56 +-88 +-112 +13 +75 +87 +30 +-16 +-55 +-88 +-113 +13 +75 +87 +30 +-16 +-55 +-88 +-113 +12 +75 +87 +30 +-16 +-55 +-88 +-112 +13 +75 +86 +30 +-16 +-56 +-88 +-112 +13 +75 +86 +30 +-16 +-56 +-88 +-112 +13 +75 +87 +30 +-16 +-55 +-88 +-113 +12 +75 +86 +30 +-16 +-55 +-88 +-112 +13 +75 +86 +30 +-16 +-56 +-88 +-113 +12 +74 +86 +29 +-16 +-56 +-88 +-113 +12 +74 +86 +30 +-16 +-56 +-88 +-100 +-91 +34 +93 +95 +68 +14 +-29 +-67 +-97 +-108 +-85 +39 +96 +98 +69 +15 +-28 +-66 +-97 +-107 +-85 +39 +97 +98 +69 +15 +-28 +-66 +-97 +-107 +-85 +39 +97 +98 +70 +16 +-28 +-65 +-96 +-107 +-84 +40 +97 +98 +69 +16 +-28 +-66 +-96 +-107 +-84 +40 +98 +99 +70 +16 +-27 +-65 +-96 +-107 +-84 +40 +98 +100 +71 +17 +-27 +-65 +-96 +-106 +-84 +40 +97 +98 +70 +16 +-28 +-65 +-96 +-107 +-85 +40 +96 +98 +69 +15 +-28 +-66 +-97 +-107 +-85 +38 +96 +97 +68 +15 +-29 +-66 +-97 +-107 +-86 +38 +95 +97 +68 +15 +-29 +-66 +-97 +-107 +-86 +38 +95 +96 +67 +14 +-29 +-67 +-97 +-108 +-86 +38 +95 +96 +67 +14 +-29 +-67 +-97 +-100 +17 +80 +91 +33 +-13 +-53 +-85 +-112 +10 +72 +83 +27 +-18 +-57 +-89 +-98 +10 +73 +84 +28 +-17 +-56 +-89 +-114 +11 +73 +84 +28 +-17 +-57 +-89 +-113 +11 +74 +85 +29 +-17 +-56 +-88 +-113 +11 +74 +85 +29 +-17 +-56 +-88 +-113 +12 +74 +85 +29 +-17 +-56 +-88 +-113 +12 +74 +85 +61 +10 +-34 +-69 +-100 +-109 +-88 +37 +93 +97 +66 +15 +-30 +-66 +-98 +-107 +-86 +39 +95 +98 +66 +15 +-30 +-66 +-98 +-107 +-86 +40 +95 +98 +67 +15 +-29 +-65 +-97 +-107 +-86 +40 +95 +99 +68 +16 +-29 +-65 +-97 +-106 +-86 +40 +94 +99 +67 +15 +-29 +-66 +-97 +-107 +-86 +40 +95 +99 +67 +15 +-29 +-66 +-97 +-107 +-86 +40 +95 +100 +68 +16 +-28 +-65 +-97 +-106 +-85 +40 +95 +99 +68 +16 +-29 +-65 +-97 +-106 +-86 +40 +94 +99 +67 +15 +-29 +-66 +-97 +-107 +-86 +40 +95 +99 +68 +16 +-29 +-65 +-97 +-106 +-86 +40 +95 +99 +67 +15 +-29 +-65 +-97 +-107 +-86 +40 +95 +99 +67 +15 +-29 +-65 +-97 +-106 +-86 +40 +95 +99 +68 +16 +-29 +-65 +-97 +-106 +-86 +39 +94 +99 +67 +15 +-29 +-65 +-97 +-107 +-86 +39 +94 +98 +67 +15 +-29 +-66 +-97 +-106 +-86 +40 +95 +98 +67 +15 +-29 +-66 +-97 +-107 +-86 +40 +95 +99 +67 +16 +-29 +-65 +-97 +-106 +-86 +40 +94 +98 +67 +15 +-29 +-66 +-97 +-107 +-86 +39 +94 +99 +67 +16 +-29 +-66 +-97 +-106 +-87 +40 +95 +98 +67 +15 +-29 +-66 +-97 +-107 +-86 +39 +95 +99 +67 +15 +-29 +-66 +-97 +-106 +-86 +39 +95 +99 +67 +15 +-29 +-66 +-97 +-106 +-86 +40 +95 +99 +68 +16 +-28 +-65 +-97 +-106 +-85 +40 +96 +99 +68 +16 +-28 +-65 +-97 +-106 +-85 +41 +96 +100 +69 +17 +-28 +-65 +-96 +-106 +-85 +41 +96 +101 +69 +17 +-28 +-65 +-96 +-106 +-84 +41 +97 +101 +69 +17 +-28 +-65 +-96 +-106 +-84 +41 +96 +100 +69 +17 +-28 +-64 +-96 +-106 +-85 +41 +96 +100 +69 +17 +-28 +-65 +-96 +-106 +-85 +40 +95 +99 +67 +15 +-29 +-65 +-97 +-106 +-86 +39 +95 +98 +67 +15 +-29 +-66 +-97 +-106 +-86 +39 +94 +99 +40 +-7 +-48 +-81 +-108 +13 +75 +87 +30 +-16 +-55 +-87 +-112 +11 +74 +85 +29 +-17 +-56 +-88 +-113 +11 +74 +86 +29 +-16 +-56 +-88 +-113 +12 +74 +86 +29 +-16 +-55 +-87 +-112 +13 +76 +87 +31 +-15 +-54 +-87 +-112 +13 +75 +87 +31 +-15 +-54 +-87 +-112 +13 +76 +87 +31 +-15 +-54 +-87 +-112 +13 +75 +87 +62 +11 +-33 +-68 +-100 +-108 +-88 +38 +94 +98 +67 +15 +-29 +-65 +-97 +-106 +-87 +39 +94 +98 +67 +15 +-29 +-66 +-97 +-107 +-88 +38 +94 +97 +66 +15 +-30 +-66 +-98 +-107 +-88 +37 +93 +97 +66 +14 +-30 +-66 +-98 +-107 +-89 +36 +92 +95 +64 +13 +-31 +-67 +-99 +-108 +-89 +36 +92 +95 +64 +13 +-31 +-67 +-99 +-100 +14 +80 +88 +33 +-14 +-53 +-87 +-112 +8 +73 +82 +28 +-19 +-56 +-90 +-97 +9 +74 +83 +29 +-18 +-40 +-89 +-97 +10 +75 +84 +30 +-17 +-39 +-88 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-111 +12 +77 +86 +31 +-16 +-38 +-87 +-111 +13 +77 +86 +32 +-15 +-54 +-87 +-111 +12 +77 +86 +32 +-15 +-53 +-87 +-111 +11 +77 +86 +32 +-16 +-54 +-87 +-111 +12 +77 +86 +31 +-16 +-38 +-87 +-111 +12 +77 +86 +31 +-16 +-38 +-87 +-111 +11 +76 +85 +31 +-16 +-38 +-88 +-112 +11 +75 +84 +31 +-16 +-38 +-88 +-112 +10 +75 +84 +30 +-17 +-39 +-88 +-112 +11 +75 +84 +30 +-17 +-39 +-88 +-112 +11 +75 +84 +30 +-17 +-39 +-88 +-112 +10 +76 +85 +31 +-16 +-38 +-88 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-111 +11 +77 +86 +31 +-16 +-38 +-87 +-111 +12 +77 +85 +31 +-16 +-38 +-87 +-111 +11 +77 +86 +31 +-16 +-38 +-87 +-111 +12 +77 +86 +32 +-16 +-54 +-87 +-111 +12 +77 +86 +31 +-16 +-38 +-87 +-111 +12 +76 +86 +31 +-16 +-38 +-87 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-111 +12 +77 +85 +31 +-16 +-38 +-88 +-111 +11 +75 +84 +30 +-17 +-39 +-88 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-111 +12 +77 +86 +32 +-16 +-54 +-87 +-111 +12 +77 +86 +32 +-16 +-54 +-87 +-111 +12 +77 +86 +32 +-15 +-53 +-87 +-111 +12 +77 +86 +31 +-16 +-38 +-87 +-111 +12 +77 +86 +31 +-16 +-38 +-87 +-111 +12 +77 +85 +31 +-16 +-38 +-87 +-111 +12 +77 +86 +31 +-16 +-38 +-87 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-112 +11 +75 +84 +31 +-16 +-38 +-88 +-112 +10 +75 +84 +30 +-17 +-39 +-88 +-112 +10 +75 +84 +30 +-17 +-39 +-88 +-112 +9 +75 +84 +30 +-17 +-39 +-88 +-112 +10 +75 +84 +30 +-17 +-39 +-88 +-112 +11 +75 +84 +30 +-16 +-39 +-88 +-112 +10 +76 +84 +30 +-17 +-39 +-88 +-112 +10 +76 +85 +31 +-16 +-38 +-88 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-112 +11 +75 +84 +30 +-17 +-39 +-88 +-112 +11 +75 +84 +30 +-16 +-39 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +11 +75 +84 +30 +-17 +-39 +-88 +-112 +11 +75 +85 +31 +-16 +-38 +-88 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +11 +75 +85 +31 +-16 +-38 +-88 +-112 +11 +75 +84 +31 +-16 +-38 +-88 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-98 +-92 +35 +92 +97 +68 +16 +-29 +-65 +-97 +-106 +-86 +40 +95 +99 +68 +17 +-28 +-65 +-96 +-106 +-86 +40 +95 +99 +68 +16 +-28 +-65 +-96 +-106 +-87 +39 +95 +99 +68 +17 +-28 +-65 +-96 +-106 +-86 +40 +95 +99 +68 +16 +-28 +-65 +-96 +-106 +-87 +39 +95 +99 +68 +17 +-28 +-65 +-96 +-106 +-87 +39 +95 +99 +68 +16 +-29 +-65 +-97 +-106 +-87 +39 +95 +99 +68 +16 +-28 +-65 +-96 +-106 +-87 +39 +95 +99 +68 +16 +-28 +-65 +-96 +-106 +-87 +39 +94 +99 +67 +16 +-29 +-65 +-97 +-106 +-87 +39 +95 +99 +68 +16 +-29 +-65 +-97 +-106 +-87 +39 +94 +98 +67 +15 +-29 +-65 +-97 +-106 +-87 +39 +95 +99 +68 +16 +-28 +-65 +-97 +-98 +17 +83 +91 +36 +-12 +-50 +-84 +-110 +11 +75 +84 +30 +-17 +-39 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +10 +76 +86 +31 +-16 +-38 +-87 +-111 +11 +76 +86 +31 +-16 +-38 +-87 +-111 +11 +77 +86 +32 +-15 +-54 +-87 +-111 +11 +77 +86 +32 +-15 +-53 +-87 +-111 +11 +77 +86 +32 +-16 +-54 +-87 +-111 +11 +77 +86 +32 +-15 +-53 +-87 +-111 +12 +77 +86 +32 +-15 +-53 +-87 +-111 +12 +77 +86 +32 +-15 +-53 +-87 +-111 +12 +77 +86 +32 +-15 +-53 +-87 +-111 +11 +76 +86 +31 +-16 +-38 +-87 +-111 +11 +76 +86 +31 +-16 +-38 +-87 +-111 +10 +75 +85 +31 +-16 +-38 +-87 +-111 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +11 +76 +84 +30 +-16 +-38 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-87 +-112 +10 +76 +85 +31 +-16 +-38 +-88 +-112 +10 +76 +85 +31 +-16 +-38 +-88 +-112 +10 +76 +85 +31 +-16 +-38 +-88 +-112 +10 +76 +84 +31 +-16 +-38 +-88 +-112 +11 +75 +84 +31 +-16 +-38 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +10 +75 +85 +31 +-16 +-38 +-88 +-112 +11 +76 +85 +31 +-16 +-38 +-88 +-112 +11 +76 +86 +31 +-16 +-38 +-87 +-111 +11 +77 +86 +31 +-16 +-38 +-87 +-98 +-92 +35 +91 +97 +67 +16 +-29 +-65 +-97 +-106 +-88 +38 +95 +99 +68 +16 +-28 +-65 +-96 +-106 +-87 +39 +95 +100 +69 +17 +-28 +-64 +-96 +-105 +-87 +39 +95 +100 +68 +17 +-28 +-64 +-96 +-105 +-87 +39 +95 +99 +68 +16 +-28 +-65 +-96 +-106 +-87 +39 +95 +99 +68 +17 +-28 +-65 +-96 +-105 +-87 +39 +94 +99 +41 +-6 +-47 +-81 +-108 +13 +75 +87 +31 +-15 +-54 +-86 +-112 +11 +74 +86 +30 +-15 +-55 +-87 +-112 +11 +74 +86 +30 +-15 +-55 +-87 +-113 +10 +74 +86 +30 +-15 +-55 +-87 +-112 +11 +74 +86 +30 +-16 +-55 +-87 +-112 +11 +74 +86 +30 +-15 +-55 +-87 +-112 +12 +75 +87 +30 +-15 +-55 +-87 +-99 +-92 +33 +93 +96 +69 +15 +-28 +-65 +-96 +-106 +-86 +38 +96 +98 +70 +16 +-27 +-65 +-95 +-106 +-86 +38 +96 +98 +69 +16 +-28 +-65 +-96 +-106 +-87 +38 +96 +98 +70 +16 +-27 +-65 +-96 +-106 +-86 +38 +96 +98 +70 +16 +-27 +-65 +-96 +-106 +-86 +38 +97 +98 +70 +16 +-27 +-65 +-95 +-106 +-86 +38 +96 +98 +70 +16 +-27 +-65 +-95 +-106 +-87 +38 +96 +99 +70 +16 +-27 +-65 +-95 +-106 +-86 +38 +96 +99 +70 +16 +-27 +-65 +-95 +-106 +-86 +38 +97 +99 +70 +16 +-27 +-65 +-95 +-106 +-86 +38 +97 +100 +71 +17 +-26 +-64 +-95 +-105 +-86 +38 +97 +99 +71 +17 +-27 +-64 +-95 +-105 +-85 +39 +97 +100 +72 +18 +-26 +-64 +-95 +-105 +-86 +38 +97 +100 +71 +17 +-26 +-64 +-95 +-105 +-86 +38 +97 +99 +70 +16 +-27 +-65 +-95 +-106 +-87 +38 +96 +98 +70 +16 +-27 +-65 +-96 +-106 +-87 +37 +96 +98 +70 +16 +-27 +-65 +-95 +-106 +-87 +37 +95 +97 +69 +15 +-28 +-65 +-96 +-106 +-87 +37 +95 +97 +69 +15 +-28 +-65 +-96 +-106 +-88 +37 +96 +98 +69 +16 +-28 +-65 +-96 +-106 +-88 +37 +95 +97 +69 +16 +-28 +-65 +-96 +-106 +-87 +37 +95 +98 +69 +16 +-28 +-65 +-96 +-106 +-87 +37 +95 +97 +69 +15 +-28 +-65 +-96 +-106 +-87 +37 +95 +98 +69 +15 +-28 +-65 +-96 +-106 +-87 +37 +96 +98 +70 +16 +-27 +-65 +-96 +-106 +-87 +37 +96 +98 +70 +16 +-27 +-65 +-96 +-106 +-88 +37 +96 +99 +70 +16 +-27 +-65 +-95 +-106 +-87 +38 +96 +98 +70 +16 +-27 +-65 +-95 +-106 +-87 +37 +96 +98 +70 +16 +-27 +-65 +-96 +-106 +-87 +37 +96 +99 +70 +16 +-27 +-65 +-95 +-106 +-87 +37 +96 +98 +69 +15 +-28 +-65 +-96 +-106 +-87 +37 +96 +98 +69 +16 +-27 +-65 +-96 +-99 +16 +81 +93 +35 +-11 +-51 +-84 +-111 +10 +73 +86 +30 +-16 +-55 +-87 +-113 +10 +74 +86 +30 +-16 +-55 +-87 +-113 +10 +73 +86 +30 +-16 +-55 +-87 +-113 +9 +73 +86 +30 +-16 +-55 +-87 +-113 +10 +73 +85 +29 +-16 +-56 +-87 +-113 +11 +74 +87 +30 +-15 +-55 +-87 +-112 +11 +74 +87 +31 +-15 +-54 +-87 +-112 +11 +74 +87 +31 +-15 +-54 +-86 +-112 +12 +75 +88 +31 +-14 +-54 +-86 +-112 +12 +75 +88 +32 +-14 +-54 +-86 +-112 +12 +75 +88 +31 +-15 +-54 +-86 +-112 +11 +74 +88 +31 +-14 +-54 +-86 +-112 +12 +75 +88 +31 +-14 +-54 +-86 +-112 +11 +75 +88 +31 +-14 +-54 +-86 +-112 +11 +75 +87 +31 +-15 +-54 +-86 +-112 +11 +74 +88 +31 +-14 +-54 +-86 +-112 +11 +75 +87 +31 +-15 +-54 +-87 +-112 +11 +75 +88 +31 +-14 +-54 +-86 +-112 +11 +75 +87 +31 +-15 +-54 +-86 +-112 +10 +74 +87 +30 +-15 +-55 +-87 +-112 +11 +74 +87 +30 +-15 +-55 +-87 +-112 +11 +74 +87 +31 +-15 +-54 +-87 +-112 +11 +75 +88 +31 +-14 +-54 +-86 +-112 +11 +74 +87 +31 +-15 +-54 +-86 +-112 +12 +76 +89 +32 +-14 +-53 +-86 +-111 +12 +76 +88 +32 +-14 +-54 +-86 +-111 +12 +76 +89 +33 +-13 +-53 +-86 +-111 +12 +76 +90 +33 +-13 +-53 +-85 +-111 +12 +76 +88 +32 +-14 +-54 +-86 +-111 +12 +76 +89 +32 +-14 +-54 +-86 +-111 +12 +76 +88 +31 +-14 +-54 +-86 +-98 +-93 +33 +93 +97 +70 +16 +-27 +-65 +-96 +-106 +-88 +37 +96 +99 +70 +16 +-27 +-65 +-96 +-106 +-88 +36 +95 +98 +70 +16 +-27 +-65 +-96 +-106 +-88 +36 +95 +98 +70 +16 +-27 +-65 +-96 +-106 +-88 +36 +95 +98 +69 +16 +-28 +-65 +-96 +-106 +-88 +36 +95 +98 +70 +16 +-27 +-65 +-96 +-106 +-89 +36 +95 +98 +70 +16 +-27 +-65 +-96 +-106 +-88 +36 +96 +98 +70 +16 +-27 +-65 +-95 +-106 +-88 +37 +96 +98 +70 +16 +-27 +-65 +-96 +-106 +-88 +36 +95 +98 +70 +16 +-27 +-65 +-96 +-106 +-88 +37 +96 +99 +70 +16 +-27 +-65 +-96 +-106 +-88 +36 +95 +98 +70 +16 +-27 +-65 +-96 +-106 +-88 +36 +96 +98 +70 +16 +-27 +-65 +-96 +-106 +-88 +37 +96 +99 +70 +16 +-27 +-65 +-96 +-106 +-88 +37 +97 +99 +71 +17 +-27 +-65 +-95 +-106 +-88 +37 +96 +99 +70 +16 +-27 +-65 +-96 +-106 +-88 +37 +97 +100 +72 +18 +-26 +-64 +-95 +-106 +-87 +37 +97 +99 +71 +17 +-27 +-65 +-95 +-106 +-87 +37 +96 +99 +71 +17 +-27 +-64 +-95 +-106 +-88 +37 +97 +99 +71 +17 +-27 +-65 +-95 +-106 +-88 +37 +96 +99 +70 +16 +-27 +-65 +-95 +-106 +-88 +36 +96 +99 +71 +17 +-27 +-65 +-95 +-106 +-88 +37 +96 +99 +71 +17 +-27 +-65 +-95 +-106 +-88 +37 +96 +99 +71 +17 +-27 +-65 +-95 +-106 +-88 +37 +96 +99 +70 +17 +-27 +-65 +-95 +-106 +-88 +37 +96 +98 +71 +17 +-27 +-65 +-95 +-99 +16 +81 +93 +36 +-11 +-51 +-84 +-111 +10 +73 +86 +29 +-16 +-56 +-88 +-113 +10 +73 +86 +30 +-16 +-55 +-88 +-113 +10 +74 +87 +30 +-15 +-55 +-87 +-113 +10 +74 +87 +31 +-15 +-55 +-87 +-113 +10 +74 +87 +31 +-15 +-55 +-87 +-112 +11 +74 +87 +31 +-15 +-55 +-87 +-112 +10 +75 +88 +31 +-15 +-54 +-87 +-112 +11 +75 +88 +31 +-14 +-54 +-86 +-112 +11 +75 +88 +31 +-15 +-54 +-86 +-112 +11 +76 +89 +32 +-14 +-54 +-86 +-112 +12 +76 +89 +32 +-14 +-54 +-86 +-112 +12 +77 +90 +33 +-13 +-53 +-85 +-111 +12 +77 +89 +33 +-13 +-53 +-86 +-111 +12 +76 +89 +33 +-14 +-53 +-86 +-111 +12 +76 +90 +33 +-13 +-53 +-86 +-112 +11 +75 +89 +32 +-14 +-54 +-86 +-112 +11 +75 +88 +31 +-14 +-54 +-86 +-112 +10 +74 +88 +31 +-15 +-54 +-87 +-112 +10 +75 +87 +31 +-15 +-55 +-87 +-113 +10 +74 +87 +31 +-15 +-55 +-87 +-112 +10 +74 +88 +31 +-15 +-54 +-87 +-113 +10 +74 +87 +31 +-15 +-55 +-87 +-112 +11 +75 +88 +31 +-14 +-54 +-86 +-112 +11 +75 +88 +32 +-14 +-54 +-86 +-112 +11 +76 +89 +33 +-13 +-53 +-86 +-112 +12 +76 +90 +33 +-13 +-53 +-86 +-112 +11 +76 +89 +32 +-14 +-54 +-86 +-112 +11 +75 +89 +32 +-14 +-54 +-86 +-112 +11 +75 +88 +31 +-15 +-54 +-87 +-112 +10 +74 +88 +31 +-15 +-54 +-87 +-113 +10 +73 +87 +30 +-15 +-55 +-87 +-113 +8 +73 +86 +29 +-16 +-55 +-88 +-114 +8 +72 +85 +29 +-17 +-56 +-88 +-98 +7 +71 +84 +28 +-17 +-57 +-89 +-98 +7 +71 +84 +28 +-17 +-56 +-88 +-98 +8 +72 +85 +29 +-17 +-56 +-88 +-114 +9 +73 +87 +30 +-16 +-55 +-87 +-113 +10 +74 +88 +31 +-15 +-54 +-87 +-112 +10 +75 +89 +64 +13 +-31 +-67 +-99 +-108 +-90 +37 +95 +101 +72 +19 +-26 +-63 +-95 +-105 +-87 +39 +96 +102 +72 +19 +-26 +-63 +-95 +-105 +-87 +39 +96 +102 +72 +19 +-26 +-63 +-95 +-105 +-88 +38 +96 +102 +71 +19 +-26 +-63 +-95 +-105 +-88 +38 +95 +101 +70 +18 +-27 +-64 +-96 +-105 +-89 +38 +95 +101 +70 +18 +-27 +-64 +-96 +-99 +14 +82 +91 +36 +-12 +-51 +-85 +-111 +8 +74 +85 +30 +-17 +-39 +-88 +-97 +7 +74 +85 +30 +-17 +-39 +-88 +-97 +8 +75 +86 +31 +-16 +-38 +-88 +-97 +8 +75 +86 +32 +-16 +-54 +-88 +-112 +9 +75 +86 +32 +-15 +-54 +-87 +-112 +10 +77 +88 +33 +-15 +-53 +-87 +-112 +10 +77 +88 +33 +-15 +-53 +-87 +-98 +-93 +35 +93 +100 +72 +19 +-26 +-63 +-95 +-105 +-87 +39 +96 +103 +72 +20 +-26 +-63 +-95 +-105 +-88 +38 +96 +102 +71 +19 +-26 +-63 +-95 +-105 +-89 +38 +95 +101 +71 +19 +-27 +-63 +-95 +-105 +-89 +38 +95 +101 +70 +18 +-27 +-64 +-96 +-105 +-89 +37 +95 +101 +70 +18 +-27 +-64 +-96 +-106 +-90 +37 +95 +101 +70 +18 +-27 +-64 +-96 +-106 +-89 +38 +96 +102 +71 +19 +-26 +-64 +-96 +-105 +-89 +38 +96 +102 +72 +20 +-26 +-63 +-95 +-105 +-88 +39 +96 +103 +72 +19 +-26 +-63 +-95 +-105 +-88 +39 +96 +102 +72 +20 +-26 +-63 +-95 +-105 +-88 +38 +96 +102 +72 +19 +-26 +-63 +-95 +-105 +-89 +38 +95 +101 +71 +19 +-27 +-64 +-96 +-99 +14 +82 +93 +37 +-11 +-50 +-85 +-111 +8 +74 +85 +31 +-17 +-39 +-88 +-97 +7 +74 +85 +31 +-16 +-39 +-88 +-97 +7 +74 +85 +31 +-16 +-39 +-88 +-97 +7 +74 +85 +31 +-16 +-39 +-88 +-97 +8 +75 +86 +31 +-16 +-38 +-88 +-97 +8 +76 +86 +32 +-15 +-54 +-88 +-97 +8 +75 +86 +32 +-16 +-54 +-88 +-97 +8 +76 +87 +32 +-15 +-54 +-87 +-112 +8 +75 +87 +32 +-15 +-54 +-88 +-97 +9 +76 +87 +32 +-15 +-54 +-87 +-112 +9 +76 +87 +32 +-15 +-54 +-88 +-97 +8 +75 +87 +32 +-15 +-54 +-88 +-97 +9 +76 +86 +32 +-15 +-54 +-88 +-112 +9 +76 +87 +32 +-15 +-54 +-87 +-112 +9 +76 +87 +33 +-15 +-54 +-87 +-112 +8 +75 +88 +33 +-15 +-53 +-87 +-112 +9 +76 +87 +32 +-15 +-54 +-88 +-112 +9 +76 +87 +32 +-15 +-54 +-87 +-112 +9 +76 +87 +32 +-15 +-54 +-88 +-112 +9 +77 +88 +33 +-15 +-53 +-87 +-112 +9 +76 +87 +32 +-15 +-54 +-87 +-112 +9 +76 +88 +33 +-15 +-54 +-87 +-112 +9 +76 +88 +33 +-15 +-53 +-87 +-112 +9 +77 +87 +33 +-15 +-54 +-87 +-112 +9 +76 +88 +33 +-15 +-54 +-87 +-112 +9 +76 +87 +33 +-15 +-54 +-87 +-112 +10 +77 +88 +33 +-15 +-53 +-87 +-112 +8 +75 +88 +33 +-15 +-53 +-87 +-112 +9 +76 +87 +33 +-15 +-54 +-87 +-112 +9 +76 +88 +33 +-15 +-53 +-87 +-112 +9 +76 +88 +33 +-15 +-53 +-87 +-112 +8 +76 +88 +33 +-15 +-54 +-87 +-97 +9 +76 +87 +32 +-15 +-54 +-88 +-97 +8 +76 +87 +32 +-15 +-54 +-88 +-112 +9 +76 +87 +32 +-15 +-54 +-88 +-97 +8 +76 +87 +33 +-15 +-54 +-87 +-112 +9 +77 +88 +33 +-14 +-53 +-87 +-112 +9 +76 +88 +33 +-15 +-53 +-87 +-112 +10 +77 +89 +34 +-14 +-53 +-87 +-112 +9 +77 +89 +34 +-14 +-53 +-87 +-112 +10 +77 +89 +34 +-14 +-53 +-87 +-112 +10 +77 +89 +34 +-14 +-53 +-87 +-112 +10 +77 +88 +33 +-14 +-53 +-87 +-112 +10 +77 +89 +34 +-14 +-53 +-87 +-112 +10 +78 +89 +34 +-14 +-53 +-87 +-112 +10 +78 +89 +34 +-14 +-53 +-87 +-112 +10 +77 +89 +34 +-14 +-53 +-87 +-112 +9 +77 +89 +33 +-14 +-53 +-87 +-112 +9 +76 +88 +33 +-15 +-54 +-87 +-112 +9 +76 +88 +33 +-15 +-54 +-88 +-112 +9 +76 +87 +32 +-15 +-54 +-88 +-97 +8 +75 +88 +33 +-15 +-54 +-88 +-97 +9 +75 +87 +32 +-15 +-54 +-88 +-97 +9 +76 +87 +32 +-15 +-54 +-88 +-97 +9 +76 +88 +33 +-15 +-54 +-88 +-97 +8 +76 +88 +33 +-15 +-54 +-88 +-97 +9 +77 +88 +33 +-15 +-53 +-87 +-112 +8 +76 +88 +33 +-15 +-54 +-88 +-97 +8 +76 +87 +32 +-15 +-54 +-88 +-97 +8 +76 +88 +33 +-15 +-53 +-87 +-97 +8 +76 +88 +33 +-15 +-54 +-88 +-97 +8 +76 +87 +32 +-15 +-54 +-88 +-97 +8 +76 +87 +32 +-15 +-54 +-88 +-97 +8 +76 +88 +33 +-15 +-54 +-88 +-97 +9 +76 +88 +33 +-15 +-53 +-88 +-97 +8 +76 +88 +33 +-15 +-53 +-87 +-97 +9 +76 +88 +33 +-15 +-54 +-88 +-97 +8 +76 +88 +33 +-15 +-54 +-88 +-97 +9 +76 +88 +33 +-15 +-53 +-87 +-97 +9 +77 +88 +33 +-15 +-54 +-88 +-97 +9 +77 +88 +33 +-15 +-54 +-88 +-99 +-95 +33 +93 +101 +72 +19 +-27 +-64 +-96 +-106 +-90 +38 +96 +103 +73 +20 +-26 +-63 +-95 +-105 +-90 +37 +96 +103 +73 +20 +-26 +-63 +-96 +-105 +-91 +37 +95 +102 +72 +19 +-26 +-64 +-96 +-106 +-91 +36 +95 +102 +72 +19 +-27 +-64 +-96 +-106 +-90 +37 +95 +101 +72 +19 +-27 +-64 +-96 +-106 +-91 +37 +95 +102 +72 +19 +-26 +-64 +-96 +-106 +-91 +36 +95 +101 +71 +19 +-27 +-64 +-96 +-106 +-91 +36 +95 +102 +72 +19 +-27 +-64 +-96 +-106 +-91 +36 +95 +102 +72 +19 +-26 +-64 +-96 +-106 +-91 +36 +95 +102 +72 +19 +-26 +-64 +-96 +-106 +-91 +37 +95 +102 +72 +19 +-27 +-64 +-96 +-106 +-91 +36 +95 +102 +72 +19 +-27 +-64 +-96 +-106 +-91 +37 +95 +102 +72 +19 +-26 +-64 +-96 +-106 +-91 +37 +95 +102 +72 +19 +-26 +-64 +-96 +-106 +-90 +37 +95 +103 +72 +19 +-26 +-64 +-96 +-106 +-91 +37 +96 +103 +72 +20 +-26 +-64 +-96 +-106 +-91 +37 +95 +102 +72 +20 +-26 +-64 +-96 +-106 +-91 +37 +95 +102 +73 +20 +-26 +-63 +-96 +-106 +-91 +37 +96 +104 +73 +20 +-26 +-63 +-96 +-106 +-90 +37 +95 +103 +73 +20 +-26 +-63 +-96 +-106 +-90 +37 +96 +104 +74 +21 +-25 +-63 +-95 +-106 +-90 +37 +97 +104 +74 +21 +-26 +-63 +-95 +-105 +-90 +37 +96 +103 +73 +20 +-26 +-63 +-96 +-106 +-90 +37 +95 +103 +73 +20 +-26 +-63 +-96 +-106 +-91 +36 +95 +102 +43 +-5 +-47 +-81 +-109 +10 +75 +89 +32 +-14 +-54 +-87 +-98 +8 +73 +88 +31 +-15 +-55 +-88 +-98 +8 +74 +88 +31 +-15 +-55 +-88 +-98 +8 +74 +89 +31 +-15 +-55 +-88 +-98 +8 +74 +89 +31 +-15 +-55 +-88 +-98 +8 +74 +89 +32 +-15 +-55 +-88 +-98 +8 +74 +89 +32 +-15 +-55 +-88 +-98 +8 +74 +89 +32 +-15 +-55 +-87 +-114 +9 +74 +89 +32 +-14 +-55 +-87 +-114 +9 +75 +89 +32 +-14 +-54 +-87 +-114 +9 +75 +89 +32 +-15 +-55 +-88 +-114 +9 +75 +90 +32 +-14 +-54 +-87 +-114 +9 +75 +90 +33 +-14 +-54 +-87 +-113 +9 +75 +90 +33 +-14 +-54 +-87 +-113 +9 +75 +90 +33 +-14 +-54 +-87 +-113 +9 +75 +90 +33 +-14 +-54 +-87 +-113 +9 +75 +90 +32 +-14 +-54 +-87 +-114 +9 +75 +90 +32 +-14 +-54 +-87 +-114 +9 +75 +90 +33 +-14 +-54 +-87 +-114 +8 +75 +90 +33 +-14 +-54 +-87 +-114 +9 +75 +90 +32 +-14 +-54 +-87 +-114 +9 +75 +90 +32 +-14 +-54 +-87 +-114 +8 +75 +90 +32 +-14 +-54 +-87 +-98 +8 +74 +89 +32 +-15 +-55 +-88 +-98 +9 +75 +90 +32 +-14 +-55 +-87 +-114 +8 +74 +90 +32 +-14 +-55 +-87 +-98 +9 +75 +90 +32 +-14 +-54 +-87 +-114 +9 +75 +91 +33 +-14 +-54 +-87 +-113 +10 +76 +91 +33 +-13 +-54 +-87 +-113 +10 +77 +91 +33 +-13 +-54 +-87 +-113 +10 +76 +91 +34 +-13 +-54 +-87 +-113 +10 +76 +91 +68 +16 +-29 +-66 +-98 +-108 +-91 +37 +96 +104 +74 +21 +-25 +-63 +-96 +-106 +-90 +37 +96 +104 +74 +21 +-25 +-63 +-96 +-106 +-91 +36 +96 +103 +73 +20 +-26 +-64 +-96 +-106 +-92 +36 +96 +103 +73 +20 +-26 +-64 +-96 +-106 +-92 +36 +96 +103 +73 +20 +-26 +-64 +-96 +-106 +-91 +36 +95 +103 +73 +20 +-26 +-64 +-97 +-107 +-92 +36 +95 +103 +73 +20 +-27 +-64 +-97 +-107 +-92 +35 +95 +103 +72 +19 +-27 +-64 +-97 +-107 +-92 +36 +95 +103 +73 +20 +-26 +-64 +-97 +-107 +-92 +36 +96 +103 +74 +21 +-26 +-63 +-96 +-106 +-91 +37 +96 +104 +74 +21 +-25 +-63 +-96 +-106 +-90 +37 +96 +105 +75 +22 +-25 +-63 +-95 +-106 +-91 +37 +97 +105 +45 +-4 diff --git a/traces/ioprox-XSF-01-3B-44725.pm3 b/traces/ioprox-XSF-01-3B-44725.pm3 new file mode 100644 index 00000000..bf1cc958 --- /dev/null +++ b/traces/ioprox-XSF-01-3B-44725.pm3 @@ -0,0 +1,40000 @@ +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +43 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-59 +7 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +41 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-32 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +47 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +50 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +57 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +27 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +46 +51 +18 +-8 +-31 +-49 +-57 +10 +44 +50 +16 +-9 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +40 +10 +-16 +-36 +-55 +-69 +-80 +24 +55 +48 +41 +11 +-15 +-35 +-54 +-68 +-80 +24 +56 +50 +43 +12 +-14 +-34 +-53 +-68 +-79 +25 +56 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-79 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +7 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +23 +56 +47 +42 +10 +-14 +-36 +-53 +-68 +-79 +23 +57 +48 +44 +12 +-13 +-35 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-58 +10 +43 +49 +16 +-9 +-32 +-50 +-58 +10 +43 +48 +15 +-10 +-32 +-50 +-58 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +14 +-10 +-33 +-50 +-59 +7 +40 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-11 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +57 +48 +43 +12 +-14 +-36 +-53 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +19 +-8 +-30 +-49 +-55 +11 +46 +49 +18 +-9 +-31 +-50 +-56 +10 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +48 +17 +-10 +-32 +-50 +-57 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +22 +56 +46 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +56 +48 +43 +11 +-14 +-36 +-53 +-68 +-79 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +18 +-8 +-30 +-49 +-56 +11 +46 +50 +18 +-8 +-30 +-49 +-56 +10 +45 +48 +17 +-10 +-32 +-50 +-57 +8 +44 +48 +16 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +8 +-16 +-38 +-54 +-70 +-80 +22 +55 +46 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-58 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-66 +-78 +24 +56 +48 +43 +12 +-14 +-36 +-53 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +14 +-12 +-34 +-51 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-56 +11 +46 +50 +18 +-8 +-30 +-49 +-57 +9 +44 +48 +18 +-10 +-31 +-50 +-57 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +43 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +22 +56 +47 +42 +10 +-14 +-36 +-53 +-69 +-79 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +14 +-12 +-34 +-51 +-67 +-77 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-58 +10 +44 +50 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +40 +46 +14 +-12 +-34 +-52 +-60 +7 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +9 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +24 +58 +49 +44 +13 +-12 +-34 +-52 +-67 +-78 +24 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-55 +12 +46 +50 +18 +-9 +-30 +-50 +-57 +10 +45 +48 +18 +-9 +-31 +-50 +-57 +9 +44 +48 +17 +-10 +-32 +-50 +-58 +8 +42 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-11 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-51 +-59 +8 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-52 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-33 +-52 +-59 +6 +42 +46 +16 +-11 +-33 +-51 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-32 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +6 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-59 +6 +43 +46 +15 +-12 +-32 +-51 +-59 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-59 +6 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +22 +56 +46 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +14 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-51 +-67 +-78 +25 +58 +50 +19 +-8 +-30 +-49 +-55 +12 +46 +50 +18 +-9 +-30 +-49 +-56 +10 +45 +48 +17 +-10 +-31 +-50 +-57 +8 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-32 +-51 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-66 +-78 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-79 +26 +57 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +25 +57 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +17 +-8 +-31 +-49 +-57 +10 +44 +50 +16 +-9 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +14 +-10 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +38 +9 +-16 +-37 +-55 +-69 +-80 +23 +55 +48 +40 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +48 +41 +11 +-15 +-35 +-53 +-68 +-79 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-68 +-79 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-58 +9 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +40 +8 +-16 +-37 +-54 +-70 +-80 +21 +54 +46 +42 +10 +-15 +-36 +-53 +-69 +-79 +24 +56 +48 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +58 +48 +44 +12 +-14 +-35 +-53 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +46 +14 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-58 +9 +42 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +47 +15 +-11 +-33 +-51 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-10 +-33 +-50 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +47 +15 +-11 +-33 +-50 +-59 +8 +40 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +7 +41 +47 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +14 +-11 +-33 +-51 +-59 +8 +40 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-60 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +41 +47 +15 +-11 +-33 +-51 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-78 +24 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-58 +10 +44 +48 +16 +-10 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +57 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +18 +-9 +-30 +-49 +-56 +12 +46 +50 +19 +-8 +-30 +-49 +-56 +9 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +48 +16 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-11 +-32 +-51 +-58 +9 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +22 +56 +47 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +11 +-14 +-35 +-53 +-68 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +51 +46 +14 +-12 +-34 +-51 +-67 +-77 +26 +58 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-55 +12 +46 +50 +18 +-9 +-30 +-50 +-56 +10 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +6 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-33 +-52 +-59 +7 +42 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +23 +56 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +24 +57 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +19 +-8 +-30 +-49 +-55 +12 +47 +50 +19 +-8 +-30 +-49 +-56 +10 +44 +48 +16 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +23 +56 +47 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +18 +-9 +-30 +-50 +-56 +11 +46 +50 +18 +-8 +-30 +-49 +-56 +10 +44 +48 +17 +-10 +-31 +-50 +-57 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +50 +43 +12 +-14 +-34 +-52 +-67 +-79 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-68 +-79 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +18 +-8 +-31 +-49 +-57 +11 +44 +48 +16 +-10 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-55 +-69 +-80 +23 +54 +48 +40 +11 +-15 +-36 +-54 +-68 +-80 +25 +56 +50 +43 +13 +-14 +-34 +-53 +-67 +-78 +25 +56 +49 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +18 +-8 +-31 +-49 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-55 +-69 +-80 +23 +54 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +24 +55 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +25 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +17 +-8 +-31 +-49 +-57 +11 +44 +50 +17 +-9 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-58 +9 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-11 +-33 +-51 +-58 +9 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-60 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +7 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-12 +-34 +-52 +-60 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +39 +9 +-16 +-37 +-55 +-69 +-80 +24 +55 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +25 +56 +49 +42 +12 +-14 +-35 +-53 +-67 +-79 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-53 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +18 +-8 +-31 +-49 +-56 +12 +46 +50 +18 +-8 +-31 +-49 +-56 +11 +44 +50 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +46 +14 +-11 +-33 +-51 +-60 +7 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +40 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +14 +-11 +-33 +-50 +-59 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +7 +40 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-60 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-60 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-55 +-69 +-80 +22 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +55 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-33 +-52 +-66 +-78 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +56 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +50 +43 +13 +-14 +-34 +-53 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-58 +10 +45 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-33 +-51 +-59 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +15 +-11 +-32 +-52 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-66 +-78 +24 +55 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +56 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-53 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +18 +-8 +-31 +-49 +-56 +12 +46 +51 +18 +-8 +-31 +-49 +-57 +10 +44 +50 +16 +-9 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +10 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-10 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +8 +42 +48 +39 +10 +-16 +-37 +-55 +-69 +-80 +23 +54 +48 +40 +11 +-15 +-36 +-54 +-68 +-79 +24 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +56 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +18 +-8 +-31 +-49 +-56 +12 +46 +51 +18 +-8 +-31 +-49 +-56 +11 +44 +49 +16 +-9 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +10 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-54 +-69 +-80 +23 +54 +48 +41 +11 +-15 +-35 +-54 +-68 +-79 +24 +55 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-79 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +13 +-14 +-34 +-53 +-67 +-79 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +6 +41 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-59 +8 +42 +46 +15 +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-52 +-59 +7 +43 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-52 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +14 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-52 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +7 +42 +46 +40 +8 +-16 +-38 +-54 +-70 +-80 +22 +56 +46 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +12 +-14 +-35 +-52 +-68 +-79 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-59 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +47 +14 +-11 +-33 +-51 +-67 +-78 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +19 +-8 +-30 +-49 +-56 +10 +46 +49 +18 +-9 +-30 +-50 +-56 +10 +45 +48 +18 +-10 +-31 +-50 +-57 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +24 +56 +49 +43 +13 +-14 +-34 +-53 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +52 +18 +-8 +-30 +-48 +-56 +12 +46 +51 +18 +-8 +-30 +-49 +-57 +11 +44 +50 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +39 +9 +-16 +-37 +-55 +-69 +-80 +23 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-79 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +43 +13 +-14 +-34 +-53 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-33 +-52 +-58 +8 +44 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +9 +44 +48 +16 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-66 +-78 +25 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +25 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +52 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +50 +44 +14 +-13 +-34 +-52 +-58 +9 +45 +48 +18 +-9 +-31 +-50 +-57 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +44 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +56 +48 +41 +11 +-15 +-35 +-54 +-68 +-80 +25 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +18 +-7 +-30 +-48 +-56 +12 +46 +50 +17 +-8 +-31 +-49 +-57 +10 +44 +50 +16 +-9 +-32 +-50 +-58 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +47 +15 +-11 +-33 +-51 +-58 +9 +42 +46 +14 +-11 +-33 +-51 +-60 +7 +42 +47 +15 +-11 +-33 +-51 +-59 +7 +42 +48 +39 +10 +-16 +-37 +-55 +-69 +-80 +22 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-68 +-79 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-58 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +25 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +27 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +17 +-8 +-31 +-49 +-57 +11 +44 +50 +16 +-9 +-32 +-50 +-57 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +48 +39 +10 +-16 +-37 +-55 +-69 +-80 +23 +54 +48 +42 +11 +-15 +-35 +-54 +-68 +-79 +25 +56 +50 +42 +12 +-14 +-34 +-53 +-68 +-79 +25 +57 +50 +43 +12 +-14 +-34 +-53 +-68 +-79 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-10 +-32 +-50 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-11 +-33 +-51 +-58 +7 +41 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-11 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +45 +15 +-12 +-33 +-52 +-58 +8 +42 +46 +15 +-12 +-33 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +15 +-11 +-32 +-51 +-59 +6 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-33 +-52 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +6 +42 +46 +15 +-11 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-52 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +56 +48 +42 +12 +-14 +-35 +-54 +-68 +-79 +25 +56 +50 +43 +13 +-14 +-34 +-53 +-67 +-78 +26 +58 +50 +44 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +45 +14 +-12 +-33 +-52 +-66 +-78 +26 +58 +50 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-13 +-34 +-52 +-66 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-58 +8 +44 +47 +16 +-11 +-32 +-51 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +14 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-32 +-51 +-59 +7 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-51 +-59 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +15 +-11 +-33 +-52 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +8 +-16 +-38 +-55 +-70 +-80 +22 +56 +48 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +44 +12 +-13 +-35 +-52 +-59 +8 +44 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +14 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +56 +48 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +60 +51 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +12 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +18 +-8 +-30 +-49 +-55 +12 +46 +49 +18 +-9 +-31 +-50 +-56 +10 +45 +48 +16 +-10 +-32 +-50 +-57 +9 +44 +46 +16 +-11 +-32 +-51 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +50 +43 +13 +-14 +-34 +-53 +-67 +-79 +26 +56 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +17 +-8 +-31 +-49 +-57 +10 +44 +50 +16 +-9 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-11 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-54 +-69 +-80 +23 +54 +47 +40 +11 +-15 +-36 +-54 +-68 +-80 +25 +56 +50 +42 +12 +-14 +-35 +-53 +-68 +-79 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-79 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +46 +51 +18 +-8 +-31 +-49 +-56 +11 +44 +50 +17 +-9 +-32 +-50 +-58 +10 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +39 +9 +-16 +-37 +-55 +-69 +-80 +22 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +49 +43 +12 +-14 +-34 +-53 +-67 +-79 +25 +56 +50 +42 +12 +-14 +-35 +-53 +-68 +-79 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-79 +26 +58 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-58 +8 +44 +48 +17 +-10 +-32 +-50 +-57 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +56 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-79 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-33 +-52 +-58 +8 +44 +48 +17 +-10 +-32 +-50 +-58 +7 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-58 +9 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +9 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-32 +-51 +-58 +7 +42 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-58 +9 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +44 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +22 +55 +46 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-59 +10 +43 +48 +16 +-9 +-32 +-50 +-58 +8 +42 +48 +16 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-66 +-77 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-60 +8 +41 +46 +14 +-12 +-34 +-51 +-67 +-78 +24 +57 +48 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +58 +49 +43 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +48 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +49 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-58 +10 +43 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-60 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-66 +-78 +24 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +60 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-59 +10 +43 +49 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +40 +46 +14 +-11 +-34 +-51 +-60 +7 +40 +46 +14 +-11 +-33 +-51 +-60 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +7 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +9 +42 +47 +15 +-10 +-33 +-51 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +7 +41 +46 +14 +-11 +-33 +-51 +-60 +6 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +7 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +7 +42 +46 +14 +-11 +-33 +-51 +-60 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-60 +7 +41 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-67 +-78 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +48 +43 +12 +-13 +-35 +-53 +-68 +-78 +26 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-55 +12 +46 +50 +19 +-8 +-30 +-49 +-56 +10 +44 +48 +17 +-10 +-31 +-50 +-57 +8 +43 +47 +16 +-10 +-32 +-50 +-58 +7 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-51 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +15 +-11 +-32 +-51 +-58 +6 +42 +46 +15 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +41 +45 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-32 +-51 +-59 +6 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +15 +-12 +-33 +-51 +-59 +6 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +40 +8 +-16 +-38 +-54 +-70 +-80 +23 +56 +47 +42 +10 +-14 +-36 +-53 +-69 +-79 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-67 +-78 +24 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +59 +49 +44 +12 +-13 +-34 +-52 +-59 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +10 +42 +48 +16 +-10 +-32 +-50 +-59 +8 +42 +48 +16 +-10 +-32 +-50 +-59 +8 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +7 +41 +47 +14 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-60 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-59 +9 +43 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +14 +-11 +-33 +-51 +-60 +7 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +58 +48 +43 +12 +-14 +-35 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +24 +59 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +58 +50 +18 +-8 +-30 +-50 +-55 +12 +47 +50 +19 +-8 +-30 +-49 +-56 +10 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-52 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +6 +41 +46 +15 +-11 +-33 +-51 +-59 +6 +42 +46 +15 +-11 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-32 +-52 +-59 +7 +42 +46 +15 +-12 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-33 +-51 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-52 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-66 +-78 +25 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +13 +-14 +-34 +-53 +-67 +-78 +26 +58 +50 +44 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +27 +58 +52 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +17 +-9 +-31 +-50 +-58 +10 +44 +48 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +10 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +39 +10 +-16 +-36 +-55 +-69 +-80 +23 +54 +48 +42 +11 +-15 +-35 +-54 +-68 +-79 +24 +55 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-58 +8 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-52 +-59 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-52 +-59 +7 +42 +46 +40 +8 +-16 +-37 +-54 +-70 +-80 +22 +56 +47 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +12 +-14 +-35 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +49 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-59 +10 +43 +48 +16 +-10 +-33 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +48 +16 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-77 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +18 +-9 +-30 +-49 +-55 +11 +46 +49 +18 +-9 +-30 +-50 +-57 +10 +45 +48 +18 +-10 +-31 +-50 +-57 +9 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +8 +-16 +-38 +-54 +-70 +-80 +22 +56 +47 +42 +10 +-14 +-36 +-53 +-69 +-79 +24 +57 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +19 +-8 +-30 +-49 +-56 +11 +46 +50 +18 +-9 +-30 +-50 +-56 +10 +45 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +8 +-16 +-37 +-54 +-70 +-80 +23 +56 +46 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-67 +-78 +24 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-67 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +18 +-9 +-30 +-49 +-56 +12 +46 +50 +18 +-8 +-30 +-49 +-56 +10 +44 +48 +17 +-10 +-32 +-50 +-57 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +41 +46 +40 +8 +-16 +-38 +-55 +-70 +-80 +22 +55 +47 +41 +10 +-15 +-36 +-54 +-69 +-80 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +45 +13 +-12 +-34 +-52 +-58 +10 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +56 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +44 +13 +-13 +-34 +-52 +-68 +-78 +26 +60 +50 +46 +14 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-56 +12 +46 +50 +18 +-9 +-31 +-50 +-57 +10 +45 +48 +17 +-10 +-31 +-50 +-57 +9 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +45 +14 +-12 +-33 +-52 +-59 +7 +42 +45 +14 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-12 +-32 +-52 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +43 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-51 +-59 +7 +42 +46 +15 +-11 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-12 +-32 +-51 +-59 +7 +41 +45 +14 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +39 +8 +-16 +-38 +-55 +-70 +-80 +22 +55 +46 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-79 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +12 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +14 +-12 +-34 +-51 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +49 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-51 +-67 +-78 +25 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +59 +50 +18 +-9 +-30 +-49 +-56 +11 +46 +50 +19 +-8 +-30 +-49 +-56 +10 +45 +48 +18 +-9 +-31 +-50 +-57 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +45 +14 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +6 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-33 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +43 +12 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +18 +-8 +-30 +-48 +-56 +12 +45 +50 +17 +-8 +-31 +-49 +-57 +10 +43 +49 +16 +-9 +-32 +-50 +-58 +10 +44 +48 +16 +-9 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +38 +9 +-17 +-37 +-55 +-69 +-80 +23 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-79 +25 +57 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-58 +9 +44 +48 +17 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +22 +55 +46 +42 +10 +-14 +-36 +-53 +-69 +-79 +24 +58 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +49 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +49 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +10 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-60 +7 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +7 +40 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +7 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +57 +48 +43 +11 +-14 +-35 +-53 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +49 +43 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +12 +-12 +-34 +-52 +-59 +8 +44 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +48 +16 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-66 +-78 +24 +57 +48 +43 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +43 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +24 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-51 +-67 +-78 +26 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-55 +11 +46 +50 +18 +-8 +-30 +-49 +-56 +9 +44 +48 +16 +-10 +-32 +-51 +-57 +9 +44 +48 +16 +-10 +-32 +-50 +-57 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +23 +56 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +24 +56 +48 +43 +11 +-14 +-35 +-53 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +24 +58 +50 +43 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +60 +50 +46 +14 +-12 +-34 +-51 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-55 +12 +46 +50 +19 +-8 +-30 +-49 +-56 +9 +44 +48 +16 +-10 +-32 +-50 +-57 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +22 +56 +47 +42 +10 +-14 +-36 +-53 +-68 +-79 +23 +56 +47 +43 +11 +-14 +-36 +-53 +-68 +-79 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +19 +-8 +-30 +-49 +-56 +11 +46 +48 +18 +-9 +-31 +-50 +-57 +9 +44 +48 +17 +-10 +-32 +-50 +-58 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-38 +-54 +-70 +-80 +22 +56 +47 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-56 +12 +46 +50 +18 +-9 +-30 +-49 +-56 +10 +45 +48 +18 +-10 +-31 +-50 +-57 +9 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +47 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +26 +58 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +17 +-8 +-31 +-49 +-56 +12 +45 +50 +18 +-8 +-31 +-49 +-56 +11 +44 +50 +16 +-9 +-32 +-50 +-58 +10 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +39 +10 +-16 +-36 +-54 +-69 +-80 +24 +54 +48 +41 +11 +-15 +-35 +-54 +-68 +-80 +24 +56 +50 +42 +12 +-14 +-35 +-54 +-68 +-79 +26 +57 +50 +43 +13 +-14 +-34 +-53 +-67 +-79 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +18 +-8 +-30 +-49 +-56 +12 +45 +50 +17 +-8 +-31 +-49 +-57 +10 +43 +49 +16 +-9 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +39 +10 +-16 +-36 +-55 +-69 +-80 +24 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +46 +50 +18 +-8 +-31 +-49 +-56 +11 +44 +49 +16 +-9 +-32 +-50 +-57 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +7 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +38 +9 +-16 +-37 +-55 +-69 +-80 +22 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +24 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-79 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-30 +-49 +-56 +12 +46 +51 +18 +-8 +-31 +-49 +-57 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +10 +42 +48 +16 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +14 +-11 +-33 +-51 +-58 +9 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +41 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +9 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-60 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +41 +47 +15 +-11 +-33 +-51 +-58 +9 +42 +47 +15 +-10 +-33 +-51 +-58 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +7 +41 +47 +15 +-10 +-33 +-51 +-60 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-60 +8 +42 +47 +14 +-11 +-33 +-51 +-60 +7 +42 +47 +14 +-11 +-33 +-51 +-60 +7 +41 +47 +14 +-11 +-33 +-51 +-60 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +7 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-60 +7 +42 +48 +39 +10 +-16 +-36 +-54 +-68 +-80 +23 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +48 +42 +12 +-14 +-35 +-53 +-67 +-79 +26 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-79 +26 +58 +50 +43 +12 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +27 +58 +52 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-12 +-33 +-52 +-66 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-58 +9 +44 +48 +16 +-10 +-32 +-50 +-58 +9 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-52 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +56 +48 +42 +12 +-14 +-35 +-53 +-67 +-79 +24 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +25 +57 +50 +43 +12 +-14 +-34 +-53 +-67 +-79 +26 +57 +50 +43 +13 +-14 +-34 +-53 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +57 +50 +18 +-8 +-31 +-49 +-56 +12 +46 +51 +18 +-8 +-30 +-49 +-57 +10 +44 +49 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-54 +-69 +-80 +23 +55 +48 +41 +11 +-14 +-35 +-54 +-68 +-80 +24 +56 +48 +42 +12 +-14 +-35 +-53 +-67 +-79 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-79 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +18 +-8 +-31 +-49 +-56 +12 +46 +51 +18 +-8 +-31 +-49 +-57 +10 +44 +50 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +39 +10 +-16 +-36 +-55 +-69 +-80 +23 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +42 +12 +-14 +-34 +-53 +-67 +-78 +26 +58 +51 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-58 +9 +44 +48 +16 +-10 +-32 +-50 +-57 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +14 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +6 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-52 +-59 +7 +42 +46 +15 +-11 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-11 +-33 +-52 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +45 +14 +-12 +-33 +-52 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +15 +-11 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +8 +-16 +-38 +-55 +-70 +-80 +22 +55 +47 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +43 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +13 +-12 +-34 +-52 +-68 +-78 +26 +60 +50 +46 +14 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +14 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-58 +10 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-67 +-77 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +48 +43 +12 +-14 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +18 +-9 +-30 +-50 +-56 +11 +46 +50 +18 +-9 +-30 +-50 +-57 +10 +45 +48 +18 +-10 +-31 +-50 +-57 +9 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-79 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +18 +-8 +-31 +-49 +-56 +12 +46 +52 +18 +-8 +-30 +-48 +-56 +11 +44 +50 +17 +-8 +-31 +-49 +-57 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +47 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-54 +-69 +-80 +23 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-79 +25 +56 +50 +42 +12 +-14 +-35 +-53 +-67 +-79 +26 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +51 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-58 +9 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-52 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-79 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-58 +9 +44 +48 +17 +-10 +-31 +-50 +-57 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +42 +46 +15 +-11 +-32 +-52 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-33 +-51 +-66 +-78 +24 +56 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-30 +-48 +-56 +12 +46 +50 +18 +-8 +-31 +-49 +-57 +10 +44 +50 +16 +-9 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +39 +10 +-16 +-36 +-54 +-69 +-80 +23 +54 +48 +41 +11 +-15 +-35 +-54 +-68 +-79 +24 +56 +48 +42 +12 +-14 +-35 +-53 +-67 +-79 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-58 +9 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-51 +-66 +-78 +25 +56 +50 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +58 +50 +43 +12 +-14 +-34 +-53 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-33 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +18 +-8 +-30 +-48 +-55 +12 +46 +51 +18 +-8 +-31 +-49 +-57 +10 +44 +50 +16 +-9 +-32 +-50 +-57 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +7 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +7 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-55 +-69 +-80 +23 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +25 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-78 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-58 +9 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +45 +15 +-12 +-33 +-52 +-59 +7 +42 +45 +14 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-11 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +45 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-33 +-52 +-59 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +24 +56 +49 +43 +12 +-14 +-34 +-53 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +12 +-14 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +52 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-32 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-32 +-52 +-59 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +22 +55 +47 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-58 +10 +42 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +7 +40 +46 +14 +-11 +-33 +-51 +-60 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +15 +-10 +-33 +-51 +-66 +-78 +24 +57 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +24 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +59 +50 +19 +-8 +-30 +-49 +-55 +12 +46 +50 +18 +-8 +-30 +-49 +-56 +10 +44 +48 +18 +-10 +-31 +-50 +-57 +10 +44 +48 +17 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +56 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +56 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +42 +12 +-14 +-34 +-53 +-68 +-79 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-33 +-52 +-66 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +17 +-8 +-31 +-49 +-56 +12 +45 +50 +18 +-8 +-31 +-49 +-57 +10 +44 +50 +17 +-9 +-31 +-50 +-57 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +15 +-11 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +40 +47 +14 +-11 +-33 +-51 +-60 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +7 +40 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-11 +-33 +-51 +-58 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +7 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +39 +10 +-16 +-37 +-55 +-69 +-80 +23 +55 +48 +40 +11 +-16 +-36 +-54 +-68 +-80 +24 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +26 +57 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +46 +51 +18 +-8 +-30 +-48 +-57 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +10 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +14 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +48 +40 +10 +-16 +-36 +-54 +-69 +-80 +23 +54 +48 +42 +11 +-15 +-35 +-54 +-68 +-79 +25 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-53 +-67 +-79 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-58 +9 +44 +48 +18 +-10 +-31 +-50 +-57 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +55 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-58 +8 +44 +47 +16 +-10 +-32 +-50 +-58 +7 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +42 +46 +15 +-11 +-32 +-51 +-66 +-78 +24 +56 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +12 +-14 +-34 +-53 +-68 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +27 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-58 +9 +44 +48 +17 +-10 +-31 +-50 +-58 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-33 +-51 +-66 +-78 +25 +56 +49 +42 +12 +-14 +-34 +-53 +-67 +-79 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +43 +13 +-13 +-34 +-52 +-67 +-79 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-58 +9 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-33 +-52 +-59 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +22 +56 +47 +42 +10 +-14 +-36 +-53 +-69 +-79 +23 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-79 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-34 +-52 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +10 +44 +48 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-66 +-77 +24 +57 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-67 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-53 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +7 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-66 +-77 +24 +57 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +12 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-59 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +40 +47 +14 +-11 +-33 +-51 +-59 +7 +40 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +7 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-11 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-60 +8 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-59 +7 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +15 +-11 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +47 +15 +-10 +-33 +-51 +-59 +7 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-60 +8 +42 +47 +15 +-11 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-67 +-78 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +24 +59 +49 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +49 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-55 +12 +46 +50 +19 +-8 +-30 +-49 +-56 +10 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +42 +46 +15 +-11 +-33 +-52 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +45 +14 +-12 +-33 +-52 +-59 +6 +41 +45 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +6 +41 +46 +16 +-11 +-32 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-59 +6 +42 +46 +15 +-11 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +39 +8 +-16 +-38 +-54 +-70 +-80 +22 +56 +47 +42 +10 +-14 +-36 +-54 +-68 +-79 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +48 +43 +11 +-14 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-58 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +16 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-53 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-32 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-66 +-78 +24 +56 +48 +43 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +50 +19 +-8 +-30 +-49 +-56 +11 +46 +50 +18 +-8 +-30 +-49 +-57 +9 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +44 +48 +16 +-10 +-32 +-51 +-57 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-59 +8 +42 +46 +16 +-12 +-33 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +6 +42 +46 +15 +-12 +-33 +-52 +-59 +6 +42 +46 +15 +-11 +-33 +-51 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-51 +-59 +8 +43 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +47 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-11 +-33 +-51 +-59 +7 +43 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +6 +42 +46 +15 +-11 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-11 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-66 +-78 +24 +56 +50 +42 +12 +-14 +-35 +-53 +-68 +-79 +25 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +56 +50 +43 +13 +-13 +-34 +-53 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +18 +-8 +-31 +-49 +-57 +11 +44 +50 +17 +-8 +-31 +-49 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-58 +8 +42 +48 +14 +-10 +-33 +-51 +-59 +9 +42 +48 +39 +9 +-17 +-37 +-55 +-69 +-80 +24 +55 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +24 +56 +49 +42 +12 +-14 +-35 +-53 +-67 +-79 +26 +57 +50 +43 +12 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-53 +-58 +8 +44 +48 +16 +-10 +-32 +-50 +-57 +9 +44 +48 +17 +-10 +-32 +-50 +-58 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +39 +8 +-16 +-38 +-54 +-70 +-80 +23 +56 +48 +42 +11 +-14 +-36 +-53 +-68 +-79 +24 +56 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +12 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +24 +57 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-51 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +23 +57 +48 +43 +11 +-14 +-35 +-52 +-68 +-78 +23 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +14 +-12 +-34 +-51 +-67 +-78 +25 +59 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +19 +-8 +-30 +-49 +-56 +11 +46 +49 +18 +-9 +-31 +-50 +-56 +10 +44 +48 +17 +-10 +-32 +-50 +-57 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +8 +-16 +-37 +-54 +-70 +-80 +23 +56 +48 +43 +11 +-14 +-36 +-53 +-68 +-79 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +59 +49 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-35 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +19 +-8 +-30 +-49 +-55 +11 +46 +49 +18 +-9 +-31 +-50 +-56 +10 +46 +49 +18 +-9 +-31 +-50 +-57 +10 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +22 +56 +48 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +57 +48 +44 +12 +-14 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-58 +10 +44 +48 +16 +-10 +-32 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +7 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +23 +56 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +60 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +18 +-9 +-30 +-50 +-55 +12 +46 +50 +19 +-9 +-30 +-49 +-56 +10 +45 +48 +18 +-10 +-31 +-50 +-57 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +22 +56 +46 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-58 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +40 +46 +14 +-11 +-34 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +7 +41 +47 +15 +-10 +-33 +-51 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-66 +-78 +24 +57 +48 +43 +11 +-14 +-36 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +14 +-12 +-34 +-51 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +50 +19 +-8 +-30 +-49 +-55 +11 +46 +49 +18 +-9 +-31 +-50 +-56 +10 +44 +48 +17 +-10 +-31 +-50 +-57 +8 +44 +48 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-11 +-33 +-51 +-59 +6 +41 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +15 +-11 +-32 +-52 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +15 +-11 +-33 +-52 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +15 +-12 +-33 +-51 +-59 +7 +41 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +45 +14 +-12 +-33 +-52 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +46 +15 +-12 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +44 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +6 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +22 +55 +47 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +60 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +18 +-9 +-30 +-50 +-56 +11 +46 +50 +18 +-8 +-30 +-49 +-56 +10 +45 +48 +18 +-10 +-31 +-50 +-57 +9 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-33 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-11 +-32 +-52 +-59 +7 +43 +46 +16 +-11 +-32 +-52 +-58 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +15 +-12 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-51 +-66 +-78 +25 +56 +48 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +56 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +18 +-8 +-31 +-49 +-58 +10 +43 +50 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +14 +-11 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +40 +10 +-16 +-36 +-54 +-69 +-80 +22 +54 +48 +42 +12 +-14 +-35 +-54 +-68 +-79 +25 +56 +50 +42 +12 +-14 +-35 +-53 +-68 +-78 +25 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +42 +12 +-14 +-34 +-53 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +27 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-59 +8 +44 +48 +17 +-10 +-32 +-50 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +47 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +15 +-12 +-33 +-52 +-59 +7 +42 +46 +15 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +47 +40 +9 +-16 +-37 +-54 +-70 +-80 +23 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-79 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +57 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +48 +44 +12 +-13 +-35 +-53 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +60 +50 +45 +13 +-12 +-34 +-52 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-11 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +47 +14 +-11 +-33 +-51 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +40 +48 +14 +-10 +-33 +-51 +-59 +8 +40 +46 +14 +-11 +-34 +-52 +-60 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +14 +-11 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-10 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-50 +-66 +-78 +24 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +24 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +24 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-58 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +10 +42 +48 +16 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-66 +-77 +24 +56 +48 +43 +12 +-14 +-35 +-53 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +49 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +19 +-8 +-30 +-49 +-55 +12 +46 +50 +18 +-9 +-30 +-50 +-56 +10 +45 +48 +18 +-10 +-31 +-50 +-57 +9 +43 +47 +16 +-10 +-32 +-51 +-58 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-37 +-54 +-69 +-80 +22 +56 +46 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +56 +47 +42 +10 +-14 +-36 +-53 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +59 +50 +45 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +44 +12 +-12 +-34 +-52 +-68 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +57 +50 +44 +12 +-13 +-35 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-68 +-78 +25 +58 +48 +44 +12 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +18 +-8 +-30 +-49 +-56 +11 +46 +49 +18 +-9 +-30 +-50 +-56 +9 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +48 +17 +-10 +-32 +-50 +-57 +9 +44 +48 +16 +-10 +-32 +-51 +-58 +9 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +43 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +22 +55 +47 +42 +10 +-14 +-36 +-53 +-68 +-79 +24 +57 +48 +43 +11 +-14 +-36 +-53 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +49 +44 +12 +-13 +-34 +-52 +-68 +-78 +25 +58 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +49 +44 +12 +-12 +-35 +-52 +-67 +-78 +25 +58 +48 +45 +13 +-12 +-34 +-52 +-67 +-78 +24 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +25 +58 +50 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +60 +51 +19 +-8 +-30 +-49 +-55 +12 +47 +50 +19 +-8 +-30 +-49 +-56 +10 +44 +48 +17 +-10 +-32 +-50 +-57 +8 +44 +48 +16 +-10 +-32 +-50 +-58 +8 +44 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +40 +9 +-16 +-37 +-54 +-70 +-80 +22 +56 +47 +42 +10 +-14 +-36 +-53 +-69 +-79 +24 +57 +48 +43 +12 +-13 +-35 +-52 +-68 +-78 +24 +58 +48 +44 +12 +-13 +-35 +-52 +-68 +-78 +26 +59 +50 +44 +13 +-12 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +12 +-13 +-34 +-52 +-67 +-78 +26 +60 +50 +46 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +59 +50 +45 +13 +-12 +-34 +-52 +-68 +-78 +25 +58 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-12 +-34 +-52 +-67 +-78 +26 +59 +50 +44 +12 +-13 +-34 +-52 +-68 +-78 +26 +59 +50 +45 +13 +-12 +-34 +-52 +-67 +-78 +25 +58 +49 +18 +-9 +-30 +-50 +-56 +11 +46 +50 +18 +-8 +-30 +-49 +-56 +10 +45 +48 +17 +-10 +-31 +-50 +-57 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-66 +-78 +25 +56 +50 +43 +12 +-14 +-34 +-53 +-67 +-79 +25 +57 +50 +43 +13 +-14 +-34 +-53 +-67 +-78 +25 +56 +50 +43 +13 +-14 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +18 +-8 +-31 +-49 +-56 +12 +45 +51 +18 +-8 +-31 +-49 +-57 +11 +44 +50 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +39 +10 +-16 +-36 +-54 +-69 +-80 +22 +54 +48 +41 +11 +-15 +-35 +-54 +-68 +-79 +24 +56 +50 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +13 +-14 +-34 +-52 +-67 +-79 +25 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +17 +-8 +-31 +-49 +-57 +10 +43 +49 +16 +-9 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +39 +10 +-16 +-36 +-55 +-69 +-80 +23 +55 +48 +41 +11 +-15 +-35 +-54 +-68 +-79 +24 +55 +50 +42 +12 +-14 +-34 +-53 +-67 +-79 +26 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +57 +50 +43 +13 +-14 +-34 +-53 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +18 +-8 +-31 +-49 +-56 +12 +45 +50 +16 +-9 +-31 +-50 +-58 +10 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +48 +16 +-10 +-32 +-50 +-58 +9 +42 +47 +15 +-10 +-33 +-50 +-59 +7 +42 +48 +16 +-10 +-32 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +9 +41 +47 +14 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-60 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +38 +9 +-17 +-37 +-55 +-69 +-80 +23 +54 +48 +41 +11 +-15 +-36 +-54 +-68 +-80 +24 +56 +49 +42 +12 +-14 +-34 +-53 +-67 +-79 +25 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +52 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +51 +43 +13 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +18 +-8 +-31 +-49 +-57 +11 +44 +50 +16 +-9 +-32 +-50 +-58 +10 +44 +49 +16 +-9 +-32 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +9 +43 +48 +16 +-10 +-32 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +48 +16 +-10 +-32 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-58 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-58 +9 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +15 +-11 +-33 +-51 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +9 +42 +47 +14 +-11 +-33 +-51 +-58 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +47 +15 +-10 +-33 +-51 +-59 +8 +41 +47 +15 +-10 +-33 +-50 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +40 +46 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +46 +14 +-11 +-33 +-51 +-59 +8 +41 +48 +15 +-11 +-33 +-51 +-58 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +42 +46 +14 +-11 +-33 +-51 +-60 +6 +41 +47 +14 +-11 +-33 +-51 +-59 +7 +40 +46 +14 +-11 +-34 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-58 +9 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +47 +14 +-11 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +48 +15 +-10 +-33 +-50 +-59 +8 +41 +48 +15 +-10 +-33 +-51 +-59 +8 +42 +47 +39 +10 +-16 +-37 +-55 +-69 +-80 +24 +55 +48 +41 +11 +-15 +-35 +-54 +-68 +-79 +24 +56 +49 +42 +12 +-14 +-35 +-53 +-68 +-79 +26 +57 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +25 +57 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-66 +-78 +26 +58 +50 +43 +13 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +25 +56 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-12 +-34 +-52 +-66 +-78 +26 +57 +50 +44 +13 +-13 +-34 +-52 +-67 +-78 +26 +58 +50 +44 +14 +-13 +-34 +-52 +-67 +-78 +27 +58 +51 +44 +14 +-13 +-34 +-52 +-67 +-78 +26 +58 +51 +44 +14 +-12 +-34 +-52 +-58 +10 +45 +48 +17 +-10 +-31 +-50 +-57 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +42 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-12 +-32 +-51 +-59 +7 +42 +46 +16 +-11 +-32 +-51 +-59 +7 +42 +45 +14 +-12 +-33 +-52 +-59 +6 +42 +46 +15 +-11 +-33 +-51 +-59 +7 +42 +46 +15 +-12 +-33 +-52 +-59 +7 +43 +46 +15 +-11 +-32 +-51 +-59 +6 +43 +46 +16 +-11 +-32 +-51 +-58 +7 +42 +46 +15 +-11 +-33 +-52 +-58 +8 +43 +47 +16 +-11 +-32 +-51 +-58 +8 +43 +47 +16 +-10 +-32 +-51 +-58 +8 +43 +46 +16 +-11 +-32 +-51 +-58 +8 +42 From c579a5871e754224aa8d6d5b05ca7a0d583e8af9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 31 Dec 2014 12:01:00 +0100 Subject: [PATCH 67/78] CHG: modified cmdlf.c - CmdLFfind with a parameter to accept traces loaded with "data load". ie: "lf search 1" == take data from previously loaded. --- client/.history | 94 ------------------------------------------------- client/cmdlf.c | 59 +++++++++++++++++++------------ 2 files changed, 36 insertions(+), 117 deletions(-) delete mode 100644 client/.history diff --git a/client/.history b/client/.history deleted file mode 100644 index d781126a..00000000 --- a/client/.history +++ /dev/null @@ -1,94 +0,0 @@ -hw tune -lf read -data plot -data sample 4000 -lf t55xx rd 0 -lf t55xx trac -lf t55xx rd 1 -lf t55xx rd 2 -lf em4x 410xsim 124s -lf em4x 410xsim 0F0368568B -da pl -scr run sky -script list -scr run mifare_autopwn -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -n -scr run tnp3 -scr run tnp3 -n -hf mf nested 0 a 4b0b20107ccb d -hf mf nested 1 0 a 4b0b20107ccb d -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -scr run tnp3 -n -scr run tnp3 -hf mf nested 1 0 a 4b0b20107ccb d -scr run tnp3 diff --git a/client/cmdlf.c b/client/cmdlf.c index 70db0575..14d8d215 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -571,31 +571,44 @@ int CmdVchDemod(const char *Cmd) //by marshmellow int CmdLFfind(const char *Cmd) { - int ans=0; - if (!offline){ - ans=CmdLFRead(""); - //ans=CmdSamples("20000"); - } - if (GraphTraceLen<1000) return 0; - PrintAndLog("Checking for known tags:"); - - ans=Cmdaskmandemod(""); - PrintAndLog("ASK_MAN: %s", (ans)?"YES":"NO" ); - - ans=CmdFSKdemodHID(""); - PrintAndLog("HID: %s", (ans)?"YES":"NO" ); - - ans=CmdFSKdemodIO(""); - PrintAndLog("IO prox: %s", (ans)?"YES":"NO" ); + char cmdp = param_getchar(Cmd, 0); - ans=CmdIndalaDemod(""); - PrintAndLog("Indala (64): %s", (ans)?"YES":"NO" ); + if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: lf search [use data from Graphbuffer]"); + PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); + PrintAndLog(""); + PrintAndLog(" sample: lf search"); + PrintAndLog(" : lf search 1"); + return 0; + } - ans=CmdIndalaDemod("224"); - PrintAndLog("Indala (224): %s", (ans)?"YES":"NO" ); - - //PrintAndLog("No Known Tags Found!\n"); - return 0; + int ans = 0; + if (!offline && cmdp != '1' ){ + ans = CmdLFRead(""); + } else if (GraphTraceLen<1000) { + PrintAndLog("Data in Graphbuffer was too small."); + return 0; + } + + PrintAndLog("Checking for known tags:"); + + ans=Cmdaskmandemod(""); + PrintAndLog("ASK_MAN: %s", (ans)?"YES":"NO" ); + + ans=CmdFSKdemodHID(""); + PrintAndLog("HID: %s", (ans)?"YES":"NO" ); + + ans=CmdFSKdemodIO(""); + PrintAndLog("IO prox: %s", (ans)?"YES":"NO" ); + + ans=CmdIndalaDemod(""); + PrintAndLog("Indala (64): %s", (ans)?"YES":"NO" ); + + ans=CmdIndalaDemod("224"); + PrintAndLog("Indala (224): %s", (ans)?"YES":"NO" ); + + //PrintAndLog("No Known Tags Found!\n"); + return 0; } static command_t CommandTable[] = From 0a966150a0bf41466c3c3e0e39672892bf6bdd01 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 1 Jan 2015 14:07:42 +0100 Subject: [PATCH 68/78] Updated the README.txt CHG: added marshmellows last changes with rtrim, and minor fixes. DEL: code cleanup in usb_cdc.c --- README.txt | 124 +++++++++++++++++++---------------------------- client/cmddata.c | 14 +++++- client/cmddata.h | 1 + client/cmdlf.c | 12 +++-- common/cmd.c | 2 - common/usb_cdc.c | 70 +++++++++++++------------- 6 files changed, 103 insertions(+), 120 deletions(-) diff --git a/README.txt b/README.txt index cb2c7f3c..62c29920 100644 --- a/README.txt +++ b/README.txt @@ -1,87 +1,63 @@ +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 sourcecode and not all of them ever found their way to the master branch. +Among the stuff is + * jonor's hf 14a raw timing patch + * Piwi's updates. (usually gets into the master) + * Holimans iclass, (usually gets into the master) + * Marshmellows LF fixes (will go into the master) + * Midnitesnakes Ultralight, Ultralight-c enhancements + * My desfire, Ultralight extras, LF T55xx enhancements, bugs fixes (filelength, hf mf commands ), TNP3xxx lua scripts, Awid26, skidata scripts (will come) + * other osbscury 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. + +PM3 GUI: - * 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 - +I do tend to rename and move stuff around, the official PM3-GUI from Gaucho will not work so good. *sorry* + + DEVELOPMENT: -The tools required to build or run the project will vary depending on -your operating system. Please refer to the Wiki for details. +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 sourcecode 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. - * https://github.com/Proxmark/proxmark3/wiki +Common errors linux/macOS finds +Error: + * loclass/fileutils.c:15:2: warning: implicit declaration of function ‘_stat’ [-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 + -OBTAINING HARDWARE: - -The Proxmark 3 is available for purcahse (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. +And old Qt4 version 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. -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 diff --git a/client/cmddata.c b/client/cmddata.c index 7aa8fcf4..de564a69 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -226,7 +226,7 @@ int Cmdaskmandemod(const char *Cmd) PrintAndLog("EM410x pattern found: "); printEM410x(lo); } - if (BitLen>16) return 1; + //if (BitLen>16) return 1; return 0; } @@ -976,6 +976,15 @@ int CmdLtrim(const char *Cmd) RepaintGraphWindow(); return 0; } +int CmdRtrim(const char *Cmd) +{ + int ds = atoi(Cmd); + + GraphTraceLen = ds; + + RepaintGraphWindow(); + return 0; +} /* * Manchester demodulate a bitstream. The bitstream needs to be already in @@ -1377,13 +1386,14 @@ static command_t CommandTable[] = {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"}, {"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate graph window as a HID FSK using raw"}, {"fskiodemod", CmdFSKdemodIO, 1, "Demodulate graph window as an IO Prox FSK using raw"}, - {"fskrawdemod", CmdFSKrawdemod, 1, "[clock rate] [invert] Demodulate graph window from FSK to binary (clock = 64 or 50)(invert = 1 or 0)"}, + {"fskrawdemod", CmdFSKrawdemod, 1, "[clock rate] [invert] [rchigh] [rclow] Demodulate graph window from FSK to binary (clock = 50)(invert = 1 or 0)(rchigh = 10)(rclow=8)"}, {"grid", CmdGrid, 1, " -- overlay grid on graph window, use zero value to turn off either"}, {"hexsamples", CmdHexsamples, 0, " [] -- Dump big buffer as hex bytes"}, {"hide", CmdHide, 1, "Hide graph window"}, {"hpf", CmdHpf, 1, "Remove DC offset from trace"}, {"load", CmdLoad, 1, " -- Load trace (to graph window"}, {"ltrim", CmdLtrim, 1, " -- Trim samples from left of trace"}, + {"rtrim", CmdRtrim, 1, " -- Trim samples from right of trace"}, {"mandemod", CmdManchesterDemod, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"}, {"manrawdecode", Cmdmandecoderaw, 1, "Manchester decode binary stream already in graph buffer"}, {"manmod", CmdManchesterMod, 1, "[clock rate] -- Manchester modulate a binary stream"}, diff --git a/client/cmddata.h b/client/cmddata.h index 9b8f22ca..59ac43b9 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -36,6 +36,7 @@ int CmdHide(const char *Cmd); int CmdHpf(const char *Cmd); int CmdLoad(const char *Cmd); int CmdLtrim(const char *Cmd); +int CmdRtrim(const char *Cmd); int Cmdmandecoderaw(const char *Cmd); int CmdManchesterDemod(const char *Cmd); int CmdManchesterMod(const char *Cmd); diff --git a/client/cmdlf.c b/client/cmdlf.c index 14d8d215..8257a5b3 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -571,8 +571,9 @@ int CmdVchDemod(const char *Cmd) //by marshmellow int CmdLFfind(const char *Cmd) { + int ans = 0; char cmdp = param_getchar(Cmd, 0); - + if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: lf search [use data from Graphbuffer]"); PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); @@ -581,9 +582,8 @@ int CmdLFfind(const char *Cmd) PrintAndLog(" : lf search 1"); return 0; } - - int ans = 0; - if (!offline && cmdp != '1' ){ + + if (!offline || (cmdp != '1') ){ ans = CmdLFRead(""); } else if (GraphTraceLen<1000) { PrintAndLog("Data in Graphbuffer was too small."); @@ -607,7 +607,9 @@ int CmdLFfind(const char *Cmd) ans=CmdIndalaDemod("224"); PrintAndLog("Indala (224): %s", (ans)?"YES":"NO" ); - //PrintAndLog("No Known Tags Found!\n"); + if (!ans) + PrintAndLog("No Known Tags Found!\n"); + return 0; } diff --git a/common/cmd.c b/common/cmd.c index dae3a8da..66b93990 100644 --- a/common/cmd.c +++ b/common/cmd.c @@ -34,8 +34,6 @@ #include "string.h" #include "../include/proxmark3.h" -//static UsbCommand txcmd; - bool cmd_receive(UsbCommand* cmd) { // Check if there is a usb packet available diff --git a/common/usb_cdc.c b/common/usb_cdc.c index 097d9a4e..c8d5af1c 100644 --- a/common/usb_cdc.c +++ b/common/usb_cdc.c @@ -223,7 +223,6 @@ byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0; void usb_disable() { // Disconnect the USB device AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU; -// SpinDelay(100); // Clear all lingering interrupts if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) { @@ -236,32 +235,31 @@ void usb_disable() { //* \brief This function Activates the USB device //*---------------------------------------------------------------------------- void usb_enable() { - // Set the PLL USB Divider - AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ; - - // Specific Chip USB Initialisation - // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock - AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); - - // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO - // Set in PIO mode and Configure in Output - AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode - AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output - - // Clear for set the Pullup resistor - AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU; - - // Disconnect and reconnect USB controller for 100ms - usb_disable(); - - // Wait for a short while - for (volatile size_t i=0; i<0x100000; i++); -// SpinDelay(100); + // Set the PLL USB Divider + AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ; - // Reconnect USB reconnect - AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU; - AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; + // Specific Chip USB Initialisation + // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock + AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); + + // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO + // Set in PIO mode and Configure in Output + AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode + AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output + + // Clear for set the Pullup resistor + AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU; + + // Disconnect and reconnect USB controller for 100ms + usb_disable(); + + // Wait for a short while + for (volatile size_t i=0; i<0x100000; i++); + + // Reconnect USB reconnect + AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU; + AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; } //*---------------------------------------------------------------------------- @@ -300,28 +298,26 @@ bool usb_poll() //* \brief Read available data from Endpoint OUT //*---------------------------------------------------------------------------- uint32_t usb_read(byte_t* data, size_t len) { - byte_t bank = btReceiveBank; + byte_t bank = btReceiveBank; uint32_t packetSize, nbBytesRcv = 0; - uint32_t time_out = 0; + uint32_t time_out = 0; - while (len) - { + while (len) { if (!usb_check()) break; if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) { packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len); - len -= packetSize; + len -= packetSize; while(packetSize--) data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT]; pUdp->UDP_CSR[AT91C_EP_OUT] &= ~(bank); - if (bank == AT91C_UDP_RX_DATA_BK0) - { + if (bank == AT91C_UDP_RX_DATA_BK0) { bank = AT91C_UDP_RX_DATA_BK1; - } else { + } else { bank = AT91C_UDP_RX_DATA_BK0; - } + } } - if (time_out++ == 0x1fff) break; + if (time_out++ == 0x1fff) break; } btReceiveBank = bank; @@ -353,7 +349,7 @@ uint32_t usb_write(const byte_t* data, const size_t len) { // Wait for the the first bank to be sent while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) { if (!usb_check()) return length; - } + } pUdp->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP); while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP); pUdp->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY; From b1329a02643392dec5090b1f978385a9732e9af8 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 2 Jan 2015 00:09:59 +0100 Subject: [PATCH 69/78] chg: updated the README.txt chg: updated the commands.lua so it is in sync with usb_cnd.c definitions. --- README.txt | 25 +++++++++++++++---------- client/lualibs/commands.lua | 37 ++++++++++++++++++++++++++++++++++--- include/usb_cmd.h | 5 ++--- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/README.txt b/README.txt index 62c29920..05829dac 100644 --- a/README.txt +++ b/README.txt @@ -7,27 +7,32 @@ The official Proxmark repository is found here: https://github.com/Proxmark/prox NEWS: -Whats in this fork? I have scraped the web for different enhancements to the PM3 sourcecode and not all of them ever found their way to the master branch. +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 - * jonor's hf 14a raw timing patch + + * Jonor's hf 14a raw timing patch * Piwi's updates. (usually gets into the master) - * Holimans iclass, (usually gets into the master) - * Marshmellows LF fixes (will go into the master) - * Midnitesnakes Ultralight, Ultralight-c enhancements - * My desfire, Ultralight extras, LF T55xx enhancements, bugs fixes (filelength, hf mf commands ), TNP3xxx lua scripts, Awid26, skidata scripts (will come) - * other osbscury patches like for the sammy-mode, (offline you know), tagidentifications, defaultkeys. + * 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. + +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: -I do tend to rename and move stuff around, the official PM3-GUI from Gaucho will not work so good. *sorry* +I do tend to rename and move stuff around, the official PM3-GUI from Gaucho will not work so well. *sorry* DEVELOPMENT: 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 sourcecode 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. +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: @@ -55,7 +60,7 @@ Solution QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 -And old Qt4 version 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. +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. diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index f88eeae2..d2acb3be 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -47,6 +47,9 @@ local _commands = { CMD_PCF7931_READ = 0x0217, CMD_EM4X_READ_WORD = 0x0218, CMD_EM4X_WRITE_WORD = 0x0219, + CMD_IO_DEMOD_FSK = 0x021A, + CMD_IO_CLONE_TAG = 0x021B, + CMD_EM410X_DEMOD = 0x021c, --/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ --// For the 13.56 MHz tags @@ -61,6 +64,7 @@ local _commands = { CMD_ISO_15693_COMMAND_DONE = 0x0314, CMD_ISO_15693_FIND_AFI = 0x0315, CMD_ISO_15693_DEBUG = 0x0316, + CMD_LF_SNOOP_RAW_ADC_SAMPLES = 0x0317, --// For Hitag2 transponders CMD_SNOOP_HITAG = 0x0370, @@ -77,10 +81,13 @@ local _commands = { CMD_READER_LEGIC_RF = 0x0388, CMD_WRITER_LEGIC_RF = 0x0389, CMD_EPA_PACE_COLLECT_NONCE = 0x038A, + --//CMD_EPA_ = 0x038B, CMD_SNOOP_ICLASS = 0x0392, CMD_SIMULATE_TAG_ICLASS = 0x0393, CMD_READER_ICLASS = 0x0394, + CMD_READER_ICLASS_REPLAY = 0x0395, + CMD_ICLASS_ISO14443A_WRITE = 0x0397, --// For measurements of the antenna tuning CMD_MEASURE_ANTENNA_TUNING = 0x0400, @@ -97,21 +104,45 @@ local _commands = { CMD_MIFARE_EML_MEMSET = 0x0602, CMD_MIFARE_EML_MEMGET = 0x0603, CMD_MIFARE_EML_CARDLOAD = 0x0604, - CMD_MIFARE_EML_CSETBLOCK = 0x0605, - CMD_MIFARE_EML_CGETBLOCK = 0x0606, - + + --// magic chinese card commands + CMD_MIFARE_CSETBLOCK = 0x0605, + CMD_MIFARE_CGETBLOCK = 0x0606, + CMD_MIFARE_CIDENT = 0x0607, + CMD_SIMULATE_MIFARE_CARD = 0x0610, CMD_READER_MIFARE = 0x0611, CMD_MIFARE_NESTED = 0x0612, CMD_MIFARE_READBL = 0x0620, + CMD_MIFAREU_READBL = 0x0720, + CMD_MIFARE_READSC = 0x0621, + CMD_MIFAREU_READCARD = 0x0721, + CMD_MIFARE_WRITEBL = 0x0622, + CMD_MIFAREU_WRITEBL = 0x0722, + CMD_MIFAREU_WRITEBL_COMPAT = 0x0723, + CMD_MIFARE_CHKKEYS = 0x0623, CMD_MIFARE_SNIFFER = 0x0630, + --//ultralightC + CMD_MIFAREUC_AUTH1 = 0x0724, + CMD_MIFAREUC_AUTH2 = 0x0725, + CMD_MIFAREUC_READCARD = 0x0726, + + --// mifare desfire + CMD_MIFARE_DESFIRE_READBL = 0x0728, + CMD_MIFARE_DESFIRE_WRITEBL = 0x0729, + CMD_MIFARE_DESFIRE_AUTH1 = 0x072a, + CMD_MIFARE_DESFIRE_AUTH2 = 0x072b, + CMD_MIFARE_DES_READER = 0x072c, + CMD_MIFARE_DESFIRE_INFO = 0x072d, + CMD_MIFARE_DESFIRE = 0x072e, + CMD_UNKNOWN = 0xFFFF, } diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 18e54e33..111f7ec7 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -114,7 +114,6 @@ typedef struct { #define CMD_SIMULATE_TAG_LEGIC_RF 0x0387 #define CMD_READER_LEGIC_RF 0x0388 #define CMD_WRITER_LEGIC_RF 0x0389 - #define CMD_EPA_PACE_COLLECT_NONCE 0x038A //#define CMD_EPA_ 0x038B @@ -157,9 +156,9 @@ typedef struct { #define CMD_MIFAREU_READCARD 0x0721 #define CMD_MIFARE_WRITEBL 0x0622 -#define CMD_MIFAREU_WRITEBL_COMPAT 0x0722 +#define CMD_MIFAREU_WRITEBL 0x0722 +#define CMD_MIFAREU_WRITEBL_COMPAT 0x0723 -#define CMD_MIFAREU_WRITEBL 0x0723 #define CMD_MIFARE_CHKKEYS 0x0623 #define CMD_MIFARE_SNIFFER 0x0630 From 8d0a3e87d7d2350f4a05698a42f57625e460e5d6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 4 Jan 2015 22:49:54 +0100 Subject: [PATCH 70/78] FIX: a shot at fixing the "_" underscore problem in fileutils.c. This one uses _ifdefine. I hope it works. Linux people can let me know if it works. FIX: changed the DetectASKClock in lfdemod.c to correct detect all clocks in the array. CHG: I like code with more spaces inside of it and tried change some stuff according to our codestyle in HACKING.txt ADD: some zero checks and overflows, god knows where it was. The T55XX commands will be rewritten to use Marshmellows lfdemod.c instead. CHG: Made the graph window smaller. CHG: lf read now does a "data samples" also. (less writing commands) CHG: data samples now defaults to samples size of 20000 --- armsrc/desfire_crypto.c | 6 +- armsrc/lfops.c | 317 +++++++------ client/cmddata.c | 889 +++++++++++++++++++------------------ client/cmdlf.c | 58 +-- client/cmdlfem4x.c | 64 ++- client/cmdlft55xx.c | 53 +-- client/graph.c | 204 +++------ client/graph.h | 8 +- client/loclass/fileutils.c | 6 + client/proxguiqt.cpp | 2 +- client/ui.c | 67 +-- common/lfdemod.c | 881 +++++++++++++++++++----------------- 12 files changed, 1280 insertions(+), 1275 deletions(-) diff --git a/armsrc/desfire_crypto.c b/armsrc/desfire_crypto.c index b77ad8ef..9ea07371 100644 --- a/armsrc/desfire_crypto.c +++ b/armsrc/desfire_crypto.c @@ -321,7 +321,7 @@ void* mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbyt *nbytes = -1; res = NULL; #ifdef WITH_DEBUG - printf ("No room for MAC!"); + Dbprintf ("No room for MAC!"); #endif break; } @@ -336,7 +336,7 @@ void* mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbyt if (0 != memcmp ((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) { #ifdef WITH_DEBUG - printf ("MACing not verified"); + 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 @@ -366,7 +366,7 @@ void* mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbyt ((uint8_t *)data)[*nbytes - 9] = first_cmac_byte; if (0 != memcmp (DESFIRE (tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) { #ifdef WITH_DEBUG - printf ("CMAC NOT verified :-("); + Dbprintf ("CMAC NOT verified :-("); hexdump ((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0); hexdump (DESFIRE (tag)->cmac, 8, "Actual ", 0); #endif diff --git a/armsrc/lfops.c b/armsrc/lfops.c index ea2b0c44..cc9814be 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -64,9 +64,9 @@ void SnoopLFRawAdcSamples(int divisor, int trigger_threshold) // split into two routines so we can avoid timing issues after sending commands // void DoAcquisition125k_internal(int trigger_threshold, bool silent) { - uint8_t *dest = get_bigbufptr_recvrespbuf(); + uint8_t *dest = (uint8_t *)BigBuf; uint16_t i = 0; - memset(dest, 0x00, FREE_BUFFER_SIZE); + memset(dest, 0x00, BIGBUF_SIZE); for(;;) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { @@ -80,7 +80,7 @@ void DoAcquisition125k_internal(int trigger_threshold, bool silent) continue; else trigger_threshold = -1; - if (++i >= FREE_BUFFER_SIZE) break; + if (++i >= BIGBUF_SIZE) break; } } if (!silent){ @@ -161,8 +161,6 @@ void ReadTItag(void) signed char *dest = (signed char *)BigBuf; int n = sizeof(BigBuf); -// int *dest = GraphBuffer; -// int n = GraphTraceLen; // 128 bit shift register [shift3:shift2:shift1:shift0] uint32_t shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0; @@ -569,8 +567,6 @@ void SimulateTagLowFrequency( uint16_t period, uint32_t gap, uint8_t ledcontrol) void SimulateTagLowFrequencyA(int len, int gap) { - //Dbprintf("LEN %d || Gap %d",len, gap); - uint8_t *buf = (uint8_t *)BigBuf; FpgaDownloadAndGo(FPGA_BITSTREAM_LF); @@ -624,7 +620,7 @@ static void fc(int c, uint16_t *n) { int idx; // for when we want an fc8 pattern every 4 logical bits - if(c==0) { + if(c == 0) { dest[((*n)++)]=1; dest[((*n)++)]=1; dest[((*n)++)]=0; @@ -635,7 +631,7 @@ static void fc(int c, uint16_t *n) { dest[((*n)++)]=0; } // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples - if(c==8) { + if(c == 8) { for (idx=0; idx<6; idx++) { dest[((*n)++)]=1; dest[((*n)++)]=1; @@ -649,8 +645,8 @@ static void fc(int c, uint16_t *n) { } // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples - if(c==10) { - for (idx=0; idx<5; idx++) { + if(c == 10) { + for (idx = 0; idx < 5; idx++) { dest[((*n)++)]=1; dest[((*n)++)]=1; dest[((*n)++)]=1; @@ -669,7 +665,7 @@ static void fc(int c, uint16_t *n) { // simulate a HID tag until the button is pressed void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) { - uint16_t n=0, i=0; + uint16_t n = 0, i = 0; /* HID tag bitstream format The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits @@ -680,11 +676,11 @@ void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) */ - if (hi>0xFFF) { + if (hi > 0xFFF) { DbpString("Tags can only have 44 bits."); return; } - fc(0,&n); + fc(0, &n); // special start of frame marker containing invalid bit sequences fc(8, &n); fc(8, &n); // invalid fc(8, &n); fc(10, &n); // logical 0 @@ -693,9 +689,9 @@ void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) WDT_HIT(); // manchester encode bits 43 to 32 - for (i=11; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((hi>>i)&1) { + for (i = 11; i >= 0; i--) { + if ((i % 4) == 3) fc(0, &n); + if ((hi >> i) & 1) { fc(10, &n); fc(8, &n); // low-high transition } else { fc(8, &n); fc(10, &n); // high-low transition @@ -704,9 +700,9 @@ void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) WDT_HIT(); // manchester encode bits 31 to 0 - for (i=31; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((lo>>i)&1) { + for (i = 31; i >= 0; i--) { + if ((i % 4 ) == 3) fc(0, &n); + if ((lo >> i ) & 1) { fc(10, &n); fc(8, &n); // low-high transition } else { fc(8, &n); fc(10, &n); // high-low transition @@ -725,10 +721,8 @@ void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) // loop to get raw HID waveform then FSK demodulate the TAG ID from it void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = get_bigbufptr_recvrespbuf(); - - size_t size=0; //, found=0; - uint32_t hi2=0, hi=0, lo=0; + uint8_t *dest = (uint8_t *)BigBuf; + uint32_t hi2 = 0, hi = 0, lo = 0; // Configure to go in 125Khz listen mode LFSetupFPGAForADC(0, true); @@ -739,77 +733,84 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) if (ledcontrol) LED_A_ON(); DoAcquisition125k_internal(-1,true); - size = sizeof(BigBuf); - if (size < 2000) continue; - // FSK demodulator - int bitLen = HIDdemodFSK(dest,size,&hi2,&hi,&lo); + // FSK demodulator + int bitLen = HIDdemodFSK(dest,BIGBUF_SIZE,&hi2,&hi,&lo); WDT_HIT(); - if (bitLen>0 && lo>0){ + if (bitLen > 0 && lo > 0){ + // final loop, go over previously decoded manchester data and decode into usable tag ID // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 - if (hi2 != 0){ //extra large HID tags - Dbprintf("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - }else { //standard HID tags <38 bits - //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd - uint8_t bitlen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used - uint32_t lo2=0; - lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit - uint8_t idx3 = 1; - while(lo2>1){ //find last bit set to 1 (format len bit) - lo2=lo2>>1; - idx3++; - } - bitlen =idx3+19; - fc =0; - cardnum=0; - if(bitlen==26){ - cardnum = (lo>>1)&0xFFFF; - fc = (lo>>17)&0xFF; - } - if(bitlen==37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } - if(bitlen==34){ - cardnum = (lo>>1)&0xFFFF; - fc= ((hi&1)<<15)|(lo>>17); - } - if(bitlen==35){ - cardnum = (lo>>1)&0xFFFFF; - fc = ((hi&1)<<11)|(lo>>21); - } - } - else { //if bit 38 is not set then 37 bit format is used - bitlen= 37; - fc =0; - cardnum=0; - if(bitlen==37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } - } - //Dbprintf("TAG ID: %x%08x (%d)", - // (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, - (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); - } - if (findone){ - if (ledcontrol) LED_A_OFF(); - return; + + if (hi2 != 0){ + //extra large HID tags + Dbprintf("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, + (unsigned int) hi, + (unsigned int) lo, + (unsigned int) (lo >> 1) & 0xFFFF); + + } else { + //standard HID tags <38 bits + uint8_t bitlen = 0; + uint32_t fc = 0; + uint32_t cardnum = 0; + + if ((( hi >> 5 ) & 1) ==1){//if bit 38 is set then < 37 bit format is used + uint32_t lo2 = 0; + lo2 = (((hi & 31) << 12) | (lo >> 20)); //get bits 21-37 to check for format len bit + uint8_t idx3 = 1; + while(lo2 > 1){ //find last bit set to 1 (format len bit) + lo2 = lo2 >> 1; + idx3++; + } + bitlen =idx3 + 19; + fc = 0; + cardnum = 0; + if(bitlen == 26){ + cardnum = (lo >> 1) & 0xFFFF; + fc = (lo >> 17) & 0xFF; + } + if(bitlen == 37){ + cardnum = (lo >> 1) & 0x7FFFF; + fc = ((hi & 0xF) << 12)|( lo >> 20); + } + if(bitlen == 34){ + cardnum = (lo >> 1) & 0xFFFF; + fc = ((hi & 1) << 15) | (lo >> 17); + } + if(bitlen == 35){ + cardnum = (lo >> 1 ) & 0xFFFFF; + fc = ((hi & 1) << 11 ) | ( lo >> 21); + } } - // reset - hi2 = hi = lo = 0; + else { //if bit 38 is not set then 37 bit format is used + bitlen = 37; + fc = 0; + cardnum = 0; + if(bitlen == 37){ + cardnum = ( lo >> 1) & 0x7FFFF; + fc = ((hi & 0xF) << 12 ) |(lo >> 20); + } + } + Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + (unsigned int) hi, + (unsigned int) lo, + (unsigned int) (lo >> 1) & 0xFFFF, + (unsigned int) bitlen, + (unsigned int) fc, + (unsigned int) cardnum); + } + if (findone){ + if (ledcontrol) LED_A_OFF(); + return; + } + // reset + hi2 = hi = lo = 0; } WDT_HIT(); - //SpinDelay(50); } DbpString("Stopped"); if (ledcontrol) LED_A_OFF(); @@ -818,13 +819,12 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) { uint8_t *dest = (uint8_t *)BigBuf; - - size_t size=0; //, found=0; - uint32_t bitLen=0; - int clk=0, invert=0, errCnt=0; - uint64_t lo=0; + uint32_t bitLen = 0; + int clk = 0, invert = 0, errCnt = 0; + uint64_t lo = 0; + // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(95, true); + LFSetupFPGAForADC(0, true); while(!BUTTON_PRESS()) { @@ -832,37 +832,33 @@ void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) if (ledcontrol) LED_A_ON(); DoAcquisition125k_internal(-1,true); - size = sizeof(BigBuf); - if (size < 2000) continue; + // FSK demodulator - //int askmandemod(uint8_t *BinStream,uint32_t *BitLen,int *clk, int *invert); - bitLen=size; - //Dbprintf("DEBUG: Buffer got"); - errCnt = askmandemod(dest,&bitLen,&clk,&invert); //HIDdemodFSK(dest,size,&hi2,&hi,&lo); - //Dbprintf("DEBUG: ASK Got"); - WDT_HIT(); + bitLen = BIGBUF_SIZE; + errCnt = askmandemod(dest,&bitLen,&clk,&invert); + if ( errCnt < 0 ) continue; - if (errCnt>=0){ - lo = Em410xDecode(dest,bitLen); - //Dbprintf("DEBUG: EM GOT"); - //printEM410x(lo); - if (lo>0){ - 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(); - return; - } - } else { - //Dbprintf("DEBUG: No Tag"); - } WDT_HIT(); - lo = 0; - clk=0; - invert=0; - errCnt=0; - size=0; - //SpinDelay(50); + + lo = Em410xDecode(dest,bitLen); + + if ( lo <= 0) continue; + + 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(); + return; + } + + WDT_HIT(); + lo = clk = invert = errCnt = 0; } DbpString("Stopped"); if (ledcontrol) LED_A_OFF(); @@ -871,30 +867,27 @@ void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) { uint8_t *dest = (uint8_t *)BigBuf; - size_t size=0; - int idx=0; - uint32_t code=0, code2=0; - uint8_t version=0; - uint8_t facilitycode=0; - uint16_t number=0; - // Configure to go in 125Khz listen mode + int idx = 0; + uint32_t code = 0, code2 = 0; + uint8_t version = 0; + uint8_t facilitycode = 0; + uint16_t number = 0; + LFSetupFPGAForADC(0, true); while(!BUTTON_PRESS()) { WDT_HIT(); - if (ledcontrol) LED_A_ON(); - DoAcquisition125k_internal(-1,true); - size = sizeof(BigBuf); - //make sure buffer has data - if (size < 2000) continue; - //fskdemod and get start index - WDT_HIT(); - idx = IOdemodFSK(dest,size); - if (idx>0){ - //valid tag found + DoAcquisition125k_internal(-1, true); + + idx = IOdemodFSK(dest, BIGBUF_SIZE); + + if ( idx < 0 ) + continue; + + WDT_HIT(); //Index map //0 10 20 30 40 50 60 @@ -905,34 +898,34 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) // //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(); - return; - } - code=code2=0; - version=facilitycode=0; - number=0; - idx=0; + 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]); } - WDT_HIT(); + + 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 (findone){ + if (ledcontrol) LED_A_OFF(); + return; + } + code = code2 = 0; + version = facilitycode = 0; + number = 0; + idx = 0; } + DbpString("Stopped"); if (ledcontrol) LED_A_OFF(); } diff --git a/client/cmddata.c b/client/cmddata.c index de564a69..e9499ed8 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -26,37 +26,33 @@ static int CmdHelp(const char *Cmd); int CmdAmp(const char *Cmd) { - int i, rising, falling; - int max = INT_MIN, min = INT_MAX; + int i, rising, falling; + int max = INT_MIN, min = INT_MAX; - for (i = 10; i < GraphTraceLen; ++i) { - if (GraphBuffer[i] > max) - max = GraphBuffer[i]; - if (GraphBuffer[i] < min) - min = GraphBuffer[i]; - } + DetectHighLowInGraph( &max, &min, FALSE); - if (max != min) { - rising = falling= 0; - for (i = 0; i < GraphTraceLen; ++i) { - if (GraphBuffer[i + 1] < GraphBuffer[i]) { - if (rising) { - GraphBuffer[i] = max; - rising = 0; - } - falling = 1; - } - if (GraphBuffer[i + 1] > GraphBuffer[i]) { - if (falling) { - GraphBuffer[i] = min; - falling = 0; - } - rising= 1; - } - } - } - RepaintGraphWindow(); - return 0; + if (max != min) { + rising = falling = 0; + + for (i = 0; i < GraphTraceLen; ++i) { + if (GraphBuffer[i + 1] < GraphBuffer[i]) { + if (rising) { + GraphBuffer[i] = max; + rising = 0; + } + falling = 1; + } + if (GraphBuffer[i + 1] > GraphBuffer[i]) { + if (falling) { + GraphBuffer[i] = min; + falling = 0; + } + rising= 1; + } + } + } + RepaintGraphWindow(); + return 0; } /* @@ -73,118 +69,122 @@ int CmdAmp(const char *Cmd) //this method is dependant on all highs and lows to be the same(or clipped) this creates issues[marshmellow] it also ignores the clock int Cmdaskdemod(const char *Cmd) { - int i; - int c, high = 0, low = 0; + int i; + int c, high = 0, low = 0; - sscanf(Cmd, "%i", &c); + sscanf(Cmd, "%i", &c); - /* Detect high and lows and clock */ - // (AL - clock???) - for (i = 0; i < GraphTraceLen; ++i) - { - if (GraphBuffer[i] > high) - high = GraphBuffer[i]; - else if (GraphBuffer[i] < low) - low = GraphBuffer[i]; - } - high=abs(high*.75); - low=abs(low*.75); - if (c != 0 && c != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - //prime loop - if (GraphBuffer[0] > 0) { - GraphBuffer[0] = 1-c; - } else { - GraphBuffer[0] = c; - } - for (i = 1; i < GraphTraceLen; ++i) { - /* Transitions are detected at each peak - * Transitions are either: - * - we're low: transition if we hit a high - * - we're high: transition if we hit a low - * (we need to do it this way because some tags keep high or - * low for long periods, others just reach the peak and go - * down) - */ - if ((GraphBuffer[i] == high) && (GraphBuffer[i - 1] == c)) { - GraphBuffer[i] = 1 - c; - } else if ((GraphBuffer[i] == low) && (GraphBuffer[i - 1] == (1 - c))){ - GraphBuffer[i] = c; - } else { - /* No transition */ - GraphBuffer[i] = GraphBuffer[i - 1]; - } - } + if (c != 0 && c != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + + DetectHighLowInGraph( &high, &low, FALSE); + + high = abs(high * .75); + low = abs(low * .75); + + //prime loop + if (GraphBuffer[0] > 0) { + GraphBuffer[0] = 1-c; + } else { + GraphBuffer[0] = c; + } + + for (i = 1; i < GraphTraceLen; ++i) { + /* Transitions are detected at each peak + * Transitions are either: + * - we're low: transition if we hit a high + * - we're high: transition if we hit a low + * (we need to do it this way because some tags keep high or + * low for long periods, others just reach the peak and go + * down) + */ + if ((GraphBuffer[i] == high) && (GraphBuffer[i - 1] == c)) { + GraphBuffer[i] = 1 - c; + } else if ((GraphBuffer[i] == low) && (GraphBuffer[i - 1] == (1 - c))){ + GraphBuffer[i] = c; + } else { + /* No transition */ + GraphBuffer[i] = GraphBuffer[i - 1]; + } + } RepaintGraphWindow(); return 0; } -void printBitStream(uint8_t BitStream[], uint32_t bitLen){ - uint32_t i = 0; - if (bitLen<16) { - PrintAndLog("Too few bits found: %d",bitLen); - return; - } - if (bitLen>512) bitLen=512; - for (i = 0; i <= (bitLen-16); i+=16) { - PrintAndLog("%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", - BitStream[i], - BitStream[i+1], - BitStream[i+2], - BitStream[i+3], - BitStream[i+4], - BitStream[i+5], - BitStream[i+6], - BitStream[i+7], - BitStream[i+8], - BitStream[i+9], - BitStream[i+10], - BitStream[i+11], - BitStream[i+12], - BitStream[i+13], - BitStream[i+14], - BitStream[i+15]); - } +void printBitStream(uint8_t bits[], uint32_t bitLen){ + + uint32_t i = 0; + if (bitLen < 16) { + PrintAndLog("Too few bits found: %d",bitLen); + return; + } + if (bitLen > 512) + bitLen = 512; + + if ( ( bitLen % 16 ) > 0) { + bitLen = ((bitLen / 16) * 16); + PrintAndLog("ICE: equally divided with 16 = %d",bitLen); + } + + for (i = 0; i <= ( bitLen - 16); i += 16) { + PrintAndLog("%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", + bits[i], + bits[i+1], + bits[i+2], + bits[i+3], + bits[i+4], + bits[i+5], + bits[i+6], + bits[i+7], + bits[i+8], + bits[i+9], + bits[i+10], + bits[i+11], + bits[i+12], + bits[i+13], + bits[i+14], + bits[i+15]); + } return; } -void printEM410x(uint64_t id) -{ - if (id !=0){ - uint64_t iii=1; - uint64_t id2lo=0; //id2hi=0, - uint32_t ii=0; - uint32_t i=0; - for (ii=5; ii>0;ii--){ - for (i=0;i<8;i++){ - id2lo=(id2lo<<1LL)|((id & (iii<<(i+((ii-1)*8))))>>(i+((ii-1)*8))); - } - } - //output em id - PrintAndLog("EM TAG ID : %010llx", id); - PrintAndLog("Unique TAG ID: %010llx", id2lo); //id2hi, - PrintAndLog("DEZ 8 : %08lld",id & 0xFFFFFF); - PrintAndLog("DEZ 10 : %010lld",id & 0xFFFFFF); - PrintAndLog("DEZ 5.5 : %05lld.%05lld",(id>>16LL) & 0xFFFF,(id & 0xFFFF)); - PrintAndLog("DEZ 3.5A : %03lld.%05lld",(id>>32ll),(id & 0xFFFF)); - PrintAndLog("DEZ 14/IK2 : %014lld",id); - PrintAndLog("DEZ 15/IK3 : %015lld",id2lo); - PrintAndLog("Other : %05lld_%03lld_%08lld",(id&0xFFFF),((id>>16LL) & 0xFF),(id & 0xFFFFFF)); - } - return; + +void printEM410x(uint64_t id) { + + if ( id <= 0 ) return; + + uint64_t id2lo = 0; + uint32_t i,j; + i = j = 0; + + for (j = 5; j > 0; j--){ + for (i = 0; i < 8; i++){ + id2lo = ( id2lo << 1LL)|((id & ( 1 << ( i +( ( j-1 ) * 8 )))) >> ( i + (( j-1) *8 ))); + } + } + //output em id + PrintAndLog("EM TAG ID : %010llx", id); + PrintAndLog("Unique TAG ID: %010llx", id2lo); + PrintAndLog("DEZ 8 : %08lld", id & 0xFFFFFF); + PrintAndLog("DEZ 10 : %010lld", id & 0xFFFFFF); + PrintAndLog("DEZ 5.5 : %05lld.%05lld", (id>>16LL) & 0xFFFF, (id & 0xFFFF)); + PrintAndLog("DEZ 3.5A : %03lld.%05lld", (id>>32ll), (id & 0xFFFF)); + PrintAndLog("DEZ 14/IK2 : %014lld", id); + PrintAndLog("DEZ 15/IK3 : %015lld", id2lo); + PrintAndLog("Other : %05lld_%03lld_%08lld", (id & 0xFFFF), (( id >> 16LL) & 0xFF), (id & 0xFFFFFF)); } int CmdEm410xDecode(const char *Cmd) { - uint64_t id=0; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - uint32_t i=0; - i=getFromGraphBuf(BitStream); - id = Em410xDecode(BitStream,i); - printEM410x(id); - if (id>0) return 1; - return 0; + uint64_t id = 0; + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; + uint32_t len = GetFromGraphBuf(bits); + id = Em410xDecode(bits, len); + printEM410x(id); + if ( id > 0 ) + return 1; + return 0; } //by marshmellow @@ -193,41 +193,42 @@ int CmdEm410xDecode(const char *Cmd) //prints binary found and saves in graphbuffer for further commands int Cmdaskmandemod(const char *Cmd) { - int invert=0; - int clk=0; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - sscanf(Cmd, "%i %i", &clk, &invert); - if (invert != 0 && invert != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - uint32_t BitLen = getFromGraphBuf(BitStream); + int invert = 0; + int clk = 0; - int errCnt=0; - errCnt = askmandemod(BitStream, &BitLen,&clk,&invert); - if (errCnt<0){ //if fatal error (or -1) - // PrintAndLog("no data found %d, errors:%d, bitlen:%d, clock:%d",errCnt,invert,BitLen,clk); - return 0; - } - if (BitLen<16) return 0; - PrintAndLog("\nUsing Clock: %d - Invert: %d - Bits Found: %d",clk,invert,BitLen); + sscanf(Cmd, "%i %i", &clk, &invert); - if (errCnt>0){ - PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); - } - PrintAndLog("ASK/Manchester decoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printBitStream(BitStream,BitLen); - uint64_t lo =0; - lo = Em410xDecode(BitStream,BitLen); - if (lo>0){ - //set GraphBuffer for clone or sim command - setGraphBuf(BitStream,BitLen); - PrintAndLog("EM410x pattern found: "); - printEM410x(lo); - } - //if (BitLen>16) return 1; - return 0; + if (invert != 0 && invert != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; + uint32_t len = GetFromGraphBuf(bits); + + int errCnt = askmandemod(bits, &len, &clk, &invert); + + if (errCnt < 0) return 0; + if (len < 16) return 0; + + PrintAndLog("\nUsing Clock: %d - Invert: %d - Bits Found: %d",clk,invert,len); + + if (errCnt > 0){ + PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); + } + + PrintAndLog("ASK/Manchester decoded bitstream:"); + + printBitStream(bits, len); + uint64_t lo = Em410xDecode(bits, len); + + if (lo > 0){ + SetGraphBuf(bits,len); + PrintAndLog("EM410x pattern found: "); + printEM410x(lo); + return 1; + } + return 0; } //by marshmellow @@ -235,41 +236,42 @@ int Cmdaskmandemod(const char *Cmd) //stricktly take 10 and 01 and convert to 0 and 1 int Cmdmandecoderaw(const char *Cmd) { - int i =0; - int errCnt=0; - int bitnum=0; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - int high = 0, low = 0; - for (;ihigh) high=GraphBuffer[i]; - else if(GraphBuffer[i]1 || low <0 ){ - PrintAndLog("Error: please raw demod the wave first then mancheseter raw decode"); - return 0; - } - bitnum=i; - errCnt=manrawdecode(BitStream,&bitnum); - if (errCnt>=20){ - PrintAndLog("Too many errors: %d",errCnt); - return 0; - } - PrintAndLog("Manchester Decoded - # errors:%d - data:",errCnt); - printBitStream(BitStream,bitnum); - if (errCnt==0){ - //put back in graphbuffer - ClearGraph(0); - for (i=0; i < bitnum; ++i){ - GraphBuffer[i]=BitStream[i]; - } - GraphTraceLen=bitnum; - RepaintGraphWindow(); - uint64_t id = 0; - id = Em410xDecode(BitStream,i); - printEM410x(id); - } - return 1; + int i = 0; + int errCnt = 0; + int bitnum = 0; + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; + int high = 0, low = 0; + + for (; i < GraphTraceLen; ++i){ + if (GraphBuffer[i] > high) high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) low = GraphBuffer[i]; + bits[i] = GraphBuffer[i]; + } + + if (high > 1 || low < 0 ){ + PrintAndLog("Error: please raw demod the wave first then mancheseter raw decode"); + return 0; + } + + bitnum = i; + errCnt = manrawdecode(bits, &bitnum); + + if (errCnt>=20){ + PrintAndLog("Too many errors: %d",errCnt); + return 0; + } + + PrintAndLog("Manchester Decoded - # errors:%d - data:",errCnt); + printBitStream(bits,bitnum); + + if (errCnt==0){ + //put back in graphbuffer + SetGraphBuf(bits, bitnum); + + uint64_t id = Em410xDecode(bits,i); + printEM410x(id); + } + return 1; } //by marshmellow @@ -283,33 +285,35 @@ int Cmdmandecoderaw(const char *Cmd) // width waves vs small width waves to help the decode positioning) or askbiphdemod int CmdBiphaseDecodeRaw(const char *Cmd) { - int i = 0; - int errCnt=0; - int bitnum=0; - int offset=0; - int high=0, low=0; - sscanf(Cmd, "%i", &offset); - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - //get graphbuffer & high and low - for (;ihigh)high=GraphBuffer[i]; - else if(GraphBuffer[i]1 || low <0){ - PrintAndLog("Error: please raw demod the wave first then decode"); - return 0; -} - bitnum=i; - errCnt=BiphaseRawDecode(BitStream,&bitnum, offset); - if (errCnt>=20){ - PrintAndLog("Too many errors attempting to decode: %d",errCnt); - return 0; - } - PrintAndLog("Biphase Decoded using offset: %d - # errors:%d - data:",offset,errCnt); - printBitStream(BitStream,bitnum); - PrintAndLog("\nif bitstream does not look right try offset=1"); - return 1; + int i = 0; + int errCnt = 0; + int bitnum = 0; + int offset = 0; + int high = 0, low = 0; + sscanf(Cmd, "%i", &offset); + + uint8_t bits[MAX_GRAPH_TRACE_LEN]={0}; + + //get graphbuffer & high and low + for (; i high) high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) low = GraphBuffer[i]; + bits[i] = GraphBuffer[i]; + } + if (high > 1 || low < 0){ + PrintAndLog("Error: please raw demod the wave first then decode"); + return 0; + } + bitnum = i; + errCnt = BiphaseRawDecode(bits, &bitnum, offset); + if (errCnt >= 20){ + PrintAndLog("Too many errors attempting to decode: %d", errCnt); + return 0; + } + PrintAndLog("Biphase Decoded using offset: %d - # errors:%d - data:", offset, errCnt); + printBitStream(bits, bitnum); + PrintAndLog("\nif bitstream does not look right try offset=1"); + return 1; } @@ -319,43 +323,49 @@ int CmdBiphaseDecodeRaw(const char *Cmd) //prints binary found and saves in graphbuffer for further commands int Cmdaskrawdemod(const char *Cmd) { - uint32_t i; - int invert=0; - int clk=0; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - sscanf(Cmd, "%i %i", &clk, &invert); - if (invert != 0 && invert != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - int BitLen = getFromGraphBuf(BitStream); - int errCnt=0; - errCnt = askrawdemod(BitStream, &BitLen,&clk,&invert); - if (errCnt==-1){ //throw away static - allow 1 and -1 (in case of threshold command first) - PrintAndLog("no data found"); - return 0; - } - if (BitLen<16) return 0; - PrintAndLog("Using Clock: %d - invert: %d - Bits Found: %d",clk,invert,BitLen); - //PrintAndLog("Data start pos:%d, lastBit:%d, stop pos:%d, numBits:%d",iii,lastBit,i,bitnum); - //move BitStream back to GraphBuffer - - ClearGraph(0); - for (i=0; i < BitLen; ++i){ - GraphBuffer[i]=BitStream[i]; - } - GraphTraceLen=BitLen; - RepaintGraphWindow(); - - //output - if (errCnt>0){ - PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); - } - PrintAndLog("ASK demoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printBitStream(BitStream,BitLen); - - return 1; + int invert = 0; + int clk = 0; + + sscanf(Cmd, "%i %i", &clk, &invert); + + if (invert != 0 && invert != 1 ) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + + if ( clock < 0 ) { + PrintAndLog("Wrong clock argument"); + return 0; + } + + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; + int len = GetFromGraphBuf(bits); + int errCnt = 0; + + errCnt = askrawdemod(bits, &len, &clk, &invert); + + //throw away static - allow 1 and -1 (in case of threshold command first) + if (errCnt == -1) { + PrintAndLog("no data found"); + return 0; + } + + if (len < 16) return 0; + + PrintAndLog("Using Clock: %d - invert: %d - Bits Found: %d",clk,invert,len); + + //move BitStream back to GraphBuffer + SetGraphBuf(bits, len); + + if (errCnt > 0){ + PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); + } + + PrintAndLog("ASK demoded bitstream:"); + + // Now output the bitstream to the scrollback by line of 16 bits + printBitStream(bits,len); + return 1; } int CmdAutoCorr(const char *Cmd) @@ -393,7 +403,7 @@ int CmdAutoCorr(const char *Cmd) int CmdBitsamples(const char *Cmd) { int cnt = 0; - uint8_t got[12288]; + uint8_t got[10000]; GetFromBigBuf(got,sizeof(got),0); WaitForResponse(CMD_ACK,NULL); @@ -426,16 +436,10 @@ int CmdBitstream(const char *Cmd) int hithigh, hitlow, first; /* Detect high and lows and clock */ - for (i = 0; i < GraphTraceLen; ++i) - { - if (GraphBuffer[i] > high) - high = GraphBuffer[i]; - else if (GraphBuffer[i] < low) - low = GraphBuffer[i]; - } + DetectHighLowInGraph( &high, &low, FALSE); /* Get our clock */ - clock = GetClock(Cmd, high, 1); + clock = GetClock(Cmd, 0); gtl = ClearGraph(0); bit = 0; @@ -467,10 +471,6 @@ int CmdBitstream(const char *Cmd) bit ^= 1; AppendGraph(0, clock, bit); -// for (j = 0; j < (int)(clock/2); j++) -// GraphBuffer[(i * clock) + j] = bit ^ 1; -// for (j = (int)(clock/2); j < clock; j++) -// GraphBuffer[(i * clock) + j] = bit; } RepaintGraphWindow(); @@ -499,7 +499,7 @@ int CmdDec(const char *Cmd) // uses data from graphbuffer int CmdDetectClockRate(const char *Cmd) { - GetClock("",0,0); + GetClock("",1); return 0; } @@ -509,43 +509,48 @@ int CmdDetectClockRate(const char *Cmd) //defaults: clock = 50, invert=0, rchigh=10, rclow=8 (RF/10 RF/8 (fsk2a)) int CmdFSKrawdemod(const char *Cmd) { - //raw fsk demod no manchester decoding no start bit finding just get binary from wave - //set defaults - int rfLen = 50; - int invert=0; - int fchigh=10; - int fclow=8; - //set options from parameters entered with the command - sscanf(Cmd, "%i %i %i %i", &rfLen, &invert, &fchigh, &fclow); + //raw fsk demod no manchester decoding no start bit finding just get binary from wave + int rfLen = 50; + int invert = 0; + int fchigh = 10; + int fclow = 8; + + //set options from parameters entered with the command + sscanf(Cmd, "%i %i %i %i", &rfLen, &invert, &fchigh, &fclow); - if (strlen(Cmd)>0 && strlen(Cmd)<=2) { - //rfLen=param_get8(Cmd, 0); //if rfLen option only is used - if (rfLen==1){ - invert=1; //if invert option only is used - rfLen = 50; - } else if(rfLen==0) rfLen=50; - } - PrintAndLog("Args invert: %d - Clock:%d - fchigh:%d - fclow: %d",invert,rfLen,fchigh, fclow); - uint32_t i=0; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - uint32_t BitLen = getFromGraphBuf(BitStream); - int size = fskdemod(BitStream,BitLen,(uint8_t)rfLen,(uint8_t)invert,(uint8_t)fchigh,(uint8_t)fclow); - if (size>0){ - PrintAndLog("FSK decoded bitstream:"); - ClearGraph(0); - for (i=0;i (8*32)+2) size = (8*32)+2; //only output a max of 8 blocks of 32 bits most tags will have full bit stream inside that sample size - printBitStream(BitStream,size); - } else{ - PrintAndLog("no FSK data found"); - } - return 0; + if (strlen(Cmd)>0 && strlen(Cmd)<=2) { + + rfLen = 50; + + //if invert option only is used + if (rfLen == 1){ + invert=1; + } + } + + PrintAndLog("Args invert: %d - Clock:%d - FC high:%d - FC low: %d",invert,rfLen,fchigh, fclow); + + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; + uint32_t len = GetFromGraphBuf(bits); + + int size = fskdemod(bits, len,(uint8_t)rfLen, (uint8_t)invert, (uint8_t)fchigh, (uint8_t)fclow); + + if (size > 0) { + PrintAndLog("FSK decoded bitstream:"); + + SetGraphBuf(bits, size); + + // Now output the bitstream to the scrollback by line of 16 bits + // only output a max of 8 blocks of 32 bits most tags will have full bit stream inside that sample size + if(size > (8*32)+2) + size = (8*32)+2; + printBitStream(bits,size); + } else { + PrintAndLog("no FSK data found"); + } + return 0; } //by marshmellow (based on existing demod + holiman's refactor) @@ -553,70 +558,89 @@ int CmdFSKrawdemod(const char *Cmd) //print full HID Prox ID and some bit format details if found int CmdFSKdemodHID(const char *Cmd) { - //raw fsk demod no manchester decoding no start bit finding just get binary from wave - uint32_t hi2=0, hi=0, lo=0; + //raw fsk demod no manchester decoding no start bit finding just get binary from wave + uint32_t hi2=0, hi=0, lo=0; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - uint32_t BitLen = getFromGraphBuf(BitStream); - //get binary from fsk wave - size_t size = HIDdemodFSK(BitStream,BitLen,&hi2,&hi,&lo); - if (size<0){ - PrintAndLog("Error demoding fsk"); - return 0; - } - if (hi2==0 && hi==0 && lo==0) return 0; - if (hi2 != 0){ //extra large HID tags - PrintAndLog("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - setGraphBuf(BitStream,BitLen); - return 1; - } - else { //standard HID tags <38 bits - //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd - uint8_t fmtLen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used - uint32_t lo2=0; - lo2=(((hi & 15) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit - uint8_t idx3 = 1; - while(lo2>1){ //find last bit set to 1 (format len bit) - lo2=lo2>>1; - idx3++; - } - fmtLen =idx3+19; - fc =0; - cardnum=0; - if(fmtLen==26){ - cardnum = (lo>>1)&0xFFFF; - fc = (lo>>17)&0xFF; - } - if(fmtLen==37){ + uint8_t BitStream[MAX_GRAPH_TRACE_LEN] = {0x00}; + uint32_t BitLen = GetFromGraphBuf(BitStream); + + //get binary from fsk wave + size_t size = HIDdemodFSK(BitStream,BitLen,&hi2,&hi,&lo); + + if (size < 0){ + PrintAndLog("Error demoding fsk"); + return 0; + } + + if (hi2==0 && hi==0 && lo==0) return 0; + + //extra large HID tags + if (hi2 != 0){ + PrintAndLog("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, + (unsigned int) hi, + (unsigned int) lo, + (unsigned int) (lo>>1) & 0xFFFF); + SetGraphBuf(BitStream,BitLen); + return 1; + } else { + //standard HID tags <38 bits + uint8_t fmtLen = 0; + uint32_t fc = 0; + uint32_t cardnum = 0; + + //if bit 38 is set then < 37 bit format is used + if (((hi>>5) & 1)==1){ + uint32_t lo2 = 0; + + //get bits 21-37 to check for format len bit + lo2 = (((hi & 15) << 12) | (lo>>20)); + uint8_t idx3 = 1; + + //find last bit set to 1 (format len bit) + while( lo2 > 1){ + lo2=lo2>>1; + idx3++; + } + fmtLen = idx3 + 19; + fc = 0; + cardnum = 0; + + if(fmtLen==26){ + cardnum = (lo>>1)&0xFFFF; + fc = (lo>>17)&0xFF; + } + if(fmtLen==37){ cardnum = (lo>>1)&0x7FFFF; fc = ((hi&0xF)<<12)|(lo>>20); } - if(fmtLen==34){ + if(fmtLen==34){ cardnum = (lo>>1)&0xFFFF; fc= ((hi&1)<<15)|(lo>>17); - } - if(fmtLen==35){ + } + if(fmtLen==35){ cardnum = (lo>>1)&0xFFFFF; fc = ((hi&1)<<11)|(lo>>21); + } + } else { + //if bit 38 is not set then 37 bit format is used + fmtLen= 37; + fc =0; + cardnum=0; + + if (fmtLen==37){ + cardnum = (lo>>1) & 0x7FFFF; + fc = ((hi&0xF) << 12) | (lo >> 20); } - } - else { //if bit 38 is not set then 37 bit format is used - fmtLen= 37; - fc =0; - cardnum=0; - if(fmtLen==37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } - } - PrintAndLog("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, - (unsigned int) fmtLen, (unsigned int) fc, (unsigned int) cardnum); - setGraphBuf(BitStream,BitLen); + } + PrintAndLog("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + (unsigned int) hi, + (unsigned int) lo, + (unsigned int) (lo>>1) & 0xFFFF, + (unsigned int) fmtLen, + (unsigned int) fc, + (unsigned int) cardnum); + SetGraphBuf(BitStream,BitLen); return 1; } return 0; @@ -627,51 +651,65 @@ int CmdFSKdemodHID(const char *Cmd) //print ioprox ID and some format details int CmdFSKdemodIO(const char *Cmd) { - //raw fsk demod no manchester decoding no start bit finding just get binary from wave - //set defaults - int idx=0; - //something in graphbuffer - if (GraphTraceLen < 65) return 0; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - uint32_t BitLen = getFromGraphBuf(BitStream); - //get binary from fsk wave - idx = IOdemodFSK(BitStream,BitLen); - if (idx<0){ - //PrintAndLog("Error demoding fsk"); - return 0; - } - if (idx==0){ - //PrintAndLog("IO Prox Data not found - FSK Data:"); - //if (BitLen > 92) printBitStream(BitStream,92); - return 0; - } - //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 (raw) - //Handle the data - if (idx+64>BitLen) return 0; - PrintAndLog("%d%d%d%d%d%d%d%d %d",BitStream[idx], BitStream[idx+1], BitStream[idx+2], BitStream[idx+3], BitStream[idx+4], BitStream[idx+5], BitStream[idx+6], BitStream[idx+7], BitStream[idx+8]); - PrintAndLog("%d%d%d%d%d%d%d%d %d",BitStream[idx+9], BitStream[idx+10], BitStream[idx+11],BitStream[idx+12],BitStream[idx+13],BitStream[idx+14],BitStream[idx+15],BitStream[idx+16],BitStream[idx+17]); - PrintAndLog("%d%d%d%d%d%d%d%d %d facility",BitStream[idx+18], BitStream[idx+19], BitStream[idx+20],BitStream[idx+21],BitStream[idx+22],BitStream[idx+23],BitStream[idx+24],BitStream[idx+25],BitStream[idx+26]); - PrintAndLog("%d%d%d%d%d%d%d%d %d version",BitStream[idx+27], BitStream[idx+28], BitStream[idx+29],BitStream[idx+30],BitStream[idx+31],BitStream[idx+32],BitStream[idx+33],BitStream[idx+34],BitStream[idx+35]); - PrintAndLog("%d%d%d%d%d%d%d%d %d code1",BitStream[idx+36], BitStream[idx+37], BitStream[idx+38],BitStream[idx+39],BitStream[idx+40],BitStream[idx+41],BitStream[idx+42],BitStream[idx+43],BitStream[idx+44]); - PrintAndLog("%d%d%d%d%d%d%d%d %d code2",BitStream[idx+45], BitStream[idx+46], BitStream[idx+47],BitStream[idx+48],BitStream[idx+49],BitStream[idx+50],BitStream[idx+51],BitStream[idx+52],BitStream[idx+53]); - PrintAndLog("%d%d%d%d%d%d%d%d %d%d checksum",BitStream[idx+54],BitStream[idx+55],BitStream[idx+56],BitStream[idx+57],BitStream[idx+58],BitStream[idx+59],BitStream[idx+60],BitStream[idx+61],BitStream[idx+62],BitStream[idx+63]); + if (GraphTraceLen < 65) { + PrintAndLog("data samples size is too small"); + return 0; + } - uint32_t code = bytebits_to_byte(BitStream+idx,32); - uint32_t code2 = bytebits_to_byte(BitStream+idx+32,32); - uint8_t version = bytebits_to_byte(BitStream+idx+27,8); //14,4 - uint8_t facilitycode = bytebits_to_byte(BitStream+idx+18,8) ; - uint16_t number = (bytebits_to_byte(BitStream+idx+36,8)<<8)|(bytebits_to_byte(BitStream+idx+45,8)); //36,9 - - PrintAndLog("XSF(%02d)%02x:%05d (%08x%08x)",version,facilitycode,number,code,code2); - setGraphBuf(BitStream,BitLen); - return 1; + //raw fsk demod no manchester decoding no start bit finding just get binary from wave + //set defaults + int idx = 0; + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; + uint32_t bitlen = GetFromGraphBuf(bits); + + //get binary from fsk wave + idx = IOdemodFSK(bits, bitlen); + + if (idx == 0) { + return 0; + } + if (idx == -1) { + PrintAndLog("data samples size is too small"); + return 0; + } + if (idx == -2) { + PrintAndLog("Data samples has too much noice"); + return 0; + } + if (idx == -3){ + PrintAndLog("No good demod"); + return 0; + } + + if (idx+64 > bitlen) return 0; + + //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 (raw) + //Handle the data + + PrintAndLog("%d%d%d%d%d%d%d%d %d", bits[idx] , bits[idx+1], bits[idx+2], bits[idx+3], bits[idx+4], bits[idx+5], bits[idx+6], bits[idx+7], bits[idx+8]); + PrintAndLog("%d%d%d%d%d%d%d%d %d", bits[idx+9] , bits[idx+10], bits[idx+11], bits[idx+12], bits[idx+13], bits[idx+14], bits[idx+15], bits[idx+16], bits[idx+17]); + PrintAndLog("%d%d%d%d%d%d%d%d %d facility", bits[idx+18], bits[idx+19], bits[idx+20], bits[idx+21], bits[idx+22], bits[idx+23], bits[idx+24], bits[idx+25], bits[idx+26]); + PrintAndLog("%d%d%d%d%d%d%d%d %d version", bits[idx+27], bits[idx+28], bits[idx+29], bits[idx+30], bits[idx+31], bits[idx+32], bits[idx+33], bits[idx+34], bits[idx+35]); + PrintAndLog("%d%d%d%d%d%d%d%d %d code1", bits[idx+36], bits[idx+37], bits[idx+38], bits[idx+39], bits[idx+40], bits[idx+41], bits[idx+42], bits[idx+43], bits[idx+44]); + PrintAndLog("%d%d%d%d%d%d%d%d %d code2", bits[idx+45], bits[idx+46], bits[idx+47], bits[idx+48], bits[idx+49], bits[idx+50], bits[idx+51], bits[idx+52], bits[idx+53]); + PrintAndLog("%d%d%d%d%d%d%d%d %d%d checksum", bits[idx+54], bits[idx+55], bits[idx+56], bits[idx+57], bits[idx+58], bits[idx+59], bits[idx+60], bits[idx+61], bits[idx+62], bits[idx+63]); + + uint32_t code = bytebits_to_byte(bits+idx,32); + uint32_t code2 = bytebits_to_byte(bits+idx+32,32); + uint8_t version = bytebits_to_byte(bits+idx+27,8); //14,4 + uint8_t facilitycode = bytebits_to_byte(bits+idx+18,8) ; + uint16_t number = (bytebits_to_byte(bits+idx+36,8)<<8)|(bytebits_to_byte(bits+idx+45,8)); //36,9 + + PrintAndLog("XSF(%02d)%02x:%05d (%08x%08x)", version, facilitycode, number, code, code2); + SetGraphBuf(bits, bitlen); + return 1; } int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating @@ -760,8 +798,7 @@ int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating PrintAndLog("actual data bits start at sample %d", maxPos); PrintAndLog("length %d/%d", highLen, lowLen); - uint8_t bits[46]; - bits[sizeof(bits)-1] = '\0'; + uint8_t bits[46] = {0x00}; // find bit pairs and manchester decode them for (i = 0; i < arraylen(bits) - 1; ++i) { @@ -868,16 +905,17 @@ int CmdHpf(const char *Cmd) int CmdSamples(const char *Cmd) { - uint8_t got[36440] = {0x00}; - + uint8_t got[40000] = {0x00}; + int n = strtol(Cmd, NULL, 0); if (n == 0) n = 20000; + if (n > sizeof(got)) n = sizeof(got); PrintAndLog("Reading %d samples from device memory\n", n); - GetFromBigBuf(got,n,3560); + GetFromBigBuf(got,n,0); WaitForResponse(CMD_ACK,NULL); for (int j = 0; j < n; ++j) { GraphBuffer[j] = ((int)got[j]) - 128; @@ -1034,16 +1072,10 @@ int CmdManchesterDemod(const char *Cmd) uint8_t BitStream[MAX_GRAPH_TRACE_LEN] = {0x00}; /* Detect high and lows */ - for (i = 0; i < GraphTraceLen; i++) - { - if (GraphBuffer[i] > high) - high = GraphBuffer[i]; - else if (GraphBuffer[i] < low) - low = GraphBuffer[i]; - } - + DetectHighLowInGraph( &high, &low, TRUE); + /* Get our clock */ - clock = GetClock(Cmd, high, 1); + clock = GetClock(Cmd, 0); int tolerance = clock/4; /* Detect first transition */ @@ -1201,10 +1233,8 @@ int CmdManchesterMod(const char *Cmd) { int i, j; int bit, lastbit, wave; - int clock = GetClock(Cmd, 0, 1); - int clock1 = GetT55x7Clock( GraphBuffer, GraphTraceLen, 0 ); - PrintAndLog("MAN MOD CLOCKS: %d ice %d", clock,clock1); - + int clock = GetClock(Cmd, 0); + int half = (int)(clock/2); wave = 0; @@ -1373,8 +1403,8 @@ static command_t CommandTable[] = {"help", CmdHelp, 1, "This help"}, {"amp", CmdAmp, 1, "Amplify peaks"}, {"askdemod", Cmdaskdemod, 1, "<0 or 1> -- Attempt to demodulate simple ASK tags"}, - {"askmandemod", Cmdaskmandemod, 1, "[clock] [invert<0 or 1>] -- Attempt to demodulate ASK/Manchester tags and output binary (args optional[clock will try Auto-detect])"}, - {"askrawdemod", Cmdaskrawdemod, 1, "[clock] [invert<0 or 1>] -- Attempt to demodulate ASK tags and output binary (args optional[clock will try Auto-detect])"}, + {"askmandemod", Cmdaskmandemod, 1, "[clock] [invert <0|1>] -- Attempt to demodulate ASK/Manchester tags and output binary"}, + {"askrawdemod", Cmdaskrawdemod, 1, "[clock] [invert <0|1>] -- Attempt to demodulate ASK tags and output binary"}, {"autocorr", CmdAutoCorr, 1, " -- Autocorrelation over window"}, {"biphaserawdecode",CmdBiphaseDecodeRaw,1,"[offset] Biphase decode binary stream already in graph buffer (offset = bit to start decode from)"}, {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"}, @@ -1383,6 +1413,7 @@ static command_t CommandTable[] = {"dec", CmdDec, 1, "Decimate samples"}, {"detectaskclock",CmdDetectClockRate, 1, "Detect ASK clock rate"}, {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, + {"em4xdecode", CmdEm410xDecode, 1, "decode em4x from graph buffer"}, {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"}, {"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate graph window as a HID FSK using raw"}, {"fskiodemod", CmdFSKdemodIO, 1, "Demodulate graph window as an IO Prox FSK using raw"}, diff --git a/client/cmdlf.c b/client/cmdlf.c index 8257a5b3..e445b47b 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -375,6 +375,8 @@ int CmdLFRead(const char *Cmd) // load samples CmdSamples(""); + // show plot + ShowGraphWindow(); return 0; } @@ -460,36 +462,38 @@ int CmdLFSimManchester(const char *Cmd) int CmdLFSnoop(const char *Cmd) { - UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES}; - // 'h' means higher-low-frequency, 134 kHz - c.arg[0] = 0; - c.arg[1] = -1; - if (*Cmd == 0) { - // empty - } else if (*Cmd == 'l') { - sscanf(Cmd, "l %"lli, &c.arg[1]); - } else if(*Cmd == 'h') { - c.arg[0] = 1; - sscanf(Cmd, "h %"lli, &c.arg[1]); - } else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) { - PrintAndLog("use 'snoop' or 'snoop {l,h} [trigger threshold]', or 'snoop [trigger threshold]'"); - return 0; - } - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - - size_t BUFF_SIZE = 8000; - uint8_t data[BUFF_SIZE]; + UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES}; - GetFromBigBuf(data,BUFF_SIZE,3560); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); + // 'h' means higher-low-frequency, 134 kHz + c.arg[0] = 0; + c.arg[1] = -1; + + if (*Cmd == 'l') { + sscanf(Cmd, "l %"lli, &c.arg[1]); + } else if (*Cmd == 'h') { + c.arg[0] = 1; + sscanf(Cmd, "h %"lli, &c.arg[1]); + } else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) { + PrintAndLog("use 'snoop' or 'snoop {l,h} [trigger threshold]', or 'snoop [trigger threshold]'"); + return 0; + } + + SendCommand(&c); + WaitForResponse(CMD_ACK,NULL); + + size_t BUFF_SIZE = 8000; + uint8_t data[BUFF_SIZE]; + + GetFromBigBuf(data,BUFF_SIZE,0); //3560 -- should be offset.. + WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < BUFF_SIZE; j++) { GraphBuffer[j] = ((int)data[j]); } + GraphTraceLen = BUFF_SIZE; - - return 0; + + return 0; } int CmdVchDemod(const char *Cmd) @@ -575,8 +579,8 @@ int CmdLFfind(const char *Cmd) char cmdp = param_getchar(Cmd, 0); if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: lf search [use data from Graphbuffer]"); - PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); + PrintAndLog("Usage: lf search <0|1>"); + PrintAndLog(" , if not set, try reading data from tag."); PrintAndLog(""); PrintAndLog(" sample: lf search"); PrintAndLog(" : lf search 1"); @@ -585,7 +589,7 @@ int CmdLFfind(const char *Cmd) if (!offline || (cmdp != '1') ){ ans = CmdLFRead(""); - } else if (GraphTraceLen<1000) { + } else if (GraphTraceLen < 1000) { PrintAndLog("Data in Graphbuffer was too small."); return 0; } diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 6567ee41..a0cd87ca 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -28,20 +28,16 @@ char *global_em410xId; static int CmdHelp(const char *Cmd); - - int CmdEMdemodASK(const char *Cmd) { - int findone=0; - UsbCommand c={CMD_EM410X_DEMOD}; - if(Cmd[0]=='1') findone=1; - c.arg[0]=findone; - SendCommand(&c); - return 0; + char cmdp = param_getchar(Cmd, 0); + int findone = (cmdp == '1') ? 1 : 0; + UsbCommand c = { CMD_EM410X_DEMOD }; + c.arg[0] = findone; + SendCommand(&c); + return 0; } - - /* Read the ID of an EM410x tag. * Format: * 1111 1111 1 <-- standard non-repeatable header @@ -54,29 +50,25 @@ int CmdEM410xRead(const char *Cmd) { int i, j, clock, header, rows, bit, hithigh, hitlow, first, bit2idx, high, low; int parity[4]; - char id[11]; - char id2[11]; + char id[11] = {0x00}; + char id2[11] = {0x00}; int retested = 0; uint8_t BitStream[MAX_GRAPH_TRACE_LEN]; high = low = 0; - /* Detect high and lows and clock */ - for (i = 0; i < GraphTraceLen; i++) - { - if (GraphBuffer[i] > high) - high = GraphBuffer[i]; - else if (GraphBuffer[i] < low) - low = GraphBuffer[i]; - } + // get clock + clock = GetClock(Cmd, 0); + + // Detect high and lows and clock + DetectHighLowInGraph( &high, &low, TRUE); - /* get clock */ - clock = GetClock(Cmd, high, 0); - - /* parity for our 4 columns */ + PrintAndLog("NUMNUM"); + + // parity for our 4 columns parity[0] = parity[1] = parity[2] = parity[3] = 0; header = rows = 0; - /* manchester demodulate */ + // manchester demodulate bit = bit2idx = 0; for (i = 0; i < (int)(GraphTraceLen / clock); i++) { @@ -87,9 +79,9 @@ int CmdEM410xRead(const char *Cmd) /* Find out if we hit both high and low peaks */ for (j = 0; j < clock; j++) { - if (GraphBuffer[(i * clock) + j] == high) + if (GraphBuffer[(i * clock) + j] >= high) hithigh = 1; - else if (GraphBuffer[(i * clock) + j] == low) + else if (GraphBuffer[(i * clock) + j] <= low) hitlow = 1; /* it doesn't count if it's the first part of our read @@ -109,7 +101,7 @@ int CmdEM410xRead(const char *Cmd) BitStream[bit2idx++] = bit; } - + retest: /* We go till 5 before the graph ends because we'll get that far below */ for (i = 0; i < bit2idx - 5; i++) @@ -189,13 +181,14 @@ retest: } /* if we've already retested after flipping bits, return */ - if (retested++){ - return 0; + if (retested++){ + PrintAndLog("Failed to decode"); + return 0; } /* if this didn't work, try flipping bits */ - for (i = 0; i < bit2idx; i++) - BitStream[i] ^= 1; + for (i = 0; i < bit2idx; i++) + BitStream[i] ^= 1; goto retest; } @@ -290,7 +283,8 @@ int CmdEM410xSim(const char *Cmd) */ int CmdEM410xWatch(const char *Cmd) { - int read_h = (*Cmd == 'h'); + char cmdp = param_getchar(Cmd, 0); + int read_h = (cmdp == 'h'); do { if (ukbhit()) { @@ -551,7 +545,7 @@ int CmdReadWord(const char *Cmd) uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { @@ -591,7 +585,7 @@ int CmdReadWordPWD(const char *Cmd) uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 6ea9d2d3..6f1ada7c 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -22,7 +22,7 @@ #include "data.h" -#define LF_TRACE_BUFF_SIZE 12000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) +#define LF_TRACE_BUFF_SIZE 20000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) #define LF_BITSSTREAM_LEN 1000 // more then 1000 bits shouldn't happend.. 8block * 4 bytes * 8bits = static int CmdHelp(const char *Cmd); @@ -48,7 +48,7 @@ int CmdReadBlk(const char *Cmd) uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { @@ -85,7 +85,7 @@ int CmdReadBlkPWD(const char *Cmd) uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { @@ -166,7 +166,7 @@ int CmdReadTrace(const char *Cmd) uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. + GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. WaitForResponseTimeout(CMD_ACK,NULL, 1500); for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { @@ -249,32 +249,31 @@ int CmdInfo(const char *Cmd){ return 0; } - if ( strlen(Cmd)==0){ + if ( strlen(Cmd) == 0 ){ CmdReadBlk("0"); } uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; - uint8_t * bitstream = bits; - - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); + + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bits, LF_BITSSTREAM_LEN); uint8_t si = 5; - uint32_t bl0 = PackBits(si, 32, bitstream); + uint32_t bl0 = PackBits(si, 32, bits); - uint32_t safer = PackBits(si, 4, bitstream); si += 4; - uint32_t resv = PackBits(si, 7, bitstream); si += 7; - uint32_t dbr = PackBits(si, 3, bitstream); si += 3; - uint32_t extend = PackBits(si, 1, bitstream); si += 1; - uint32_t datamodulation = PackBits(si, 5, bitstream); si += 5; - uint32_t pskcf = PackBits(si, 2, bitstream); si += 2; - uint32_t aor = PackBits(si, 1, bitstream); si += 1; - uint32_t otp = PackBits(si, 1, bitstream); si += 1; - uint32_t maxblk = PackBits(si, 3, bitstream); si += 3; - uint32_t pwd = PackBits(si, 1, bitstream); si += 1; - uint32_t sst = PackBits(si, 1, bitstream); si += 1; - uint32_t fw = PackBits(si, 1, bitstream); si += 1; - uint32_t inv = PackBits(si, 1, bitstream); si += 1; - uint32_t por = PackBits(si, 1, bitstream); si += 1; + uint32_t safer = PackBits(si, 4, bits); si += 4; + uint32_t resv = PackBits(si, 7, bits); si += 7; + uint32_t dbr = PackBits(si, 3, bits); si += 3; + uint32_t extend = PackBits(si, 1, bits); si += 1; + uint32_t datamodulation = PackBits(si, 5, bits); si += 5; + uint32_t pskcf = PackBits(si, 2, bits); si += 2; + uint32_t aor = PackBits(si, 1, bits); si += 1; + uint32_t otp = PackBits(si, 1, bits); si += 1; + uint32_t maxblk = PackBits(si, 3, bits); si += 3; + uint32_t pwd = PackBits(si, 1, bits); si += 1; + uint32_t sst = PackBits(si, 1, bits); si += 1; + uint32_t fw = PackBits(si, 1, bits); si += 1; + uint32_t inv = PackBits(si, 1, bits); si += 1; + uint32_t por = PackBits(si, 1, bits); si += 1; PrintAndLog(""); PrintAndLog("-- T55xx Configuration --------------------------------------"); @@ -295,7 +294,7 @@ int CmdInfo(const char *Cmd){ PrintAndLog(" POR-Delay : %s", (por) ? "Yes":"No"); PrintAndLog("-------------------------------------------------------------"); PrintAndLog(" Raw Data - Page 0"); - PrintAndLog(" Block 0 : 0x%08X %s", bl0, sprint_bin(bitstream+5,32) ); + PrintAndLog(" Block 0 : 0x%08X %s", bl0, sprint_bin(bits+5,32) ); PrintAndLog("-------------------------------------------------------------"); return 0; @@ -357,8 +356,10 @@ int ManchesterDemod(int blockNum){ uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; uint8_t * bitstream = bits; - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); - blockData = PackBits(offset, sizebyte, bitstream); + //manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); + manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bits, LF_BITSSTREAM_LEN); + //blockData = PackBits(offset, sizebyte, bitstream); + blockData = PackBits(offset, sizebyte, bits); if ( blockNum < 0) PrintAndLog(" Decoded : 0x%08X %s", blockData, sprint_bin(bitstream+offset,sizebyte) ); diff --git a/client/graph.c b/client/graph.c index ff5a02e4..d0f6fe74 100644 --- a/client/graph.c +++ b/client/graph.c @@ -49,151 +49,69 @@ int ClearGraph(int redraw) return gtl; } -/* - * Detect clock rate - */ - //decommissioned - has difficulty detecting rf/32 -/* -int DetectClockOld(int peak) +void SetGraphBuf(uint8_t *buff, int size) { - int i; - int clock = 0xFFFF; - int lastpeak = 0; - - // Detect peak if we don't have one - if (!peak) - for (i = 0; i < GraphTraceLen; ++i) - if (GraphBuffer[i] > peak) - peak = GraphBuffer[i]; - - // peak=(int)(peak*.75); - for (i = 1; i < GraphTraceLen; ++i) - { - // If this is the beginning of a peak - if (GraphBuffer[i - 1] != GraphBuffer[i] && GraphBuffer[i] >= peak) - { - // Find lowest difference between peaks - if (lastpeak && i - lastpeak < clock) - clock = i - lastpeak; - lastpeak = i; - } - } + if ( buff == NULL ) return; - return clock; + uint16_t i = 0; + if ( size > MAX_GRAPH_TRACE_LEN ) + size = MAX_GRAPH_TRACE_LEN; + ClearGraph(0); + for (; i < size; ++i){ + GraphBuffer[i] = buff[i]; + } + GraphTraceLen = size; + RepaintGraphWindow(); + return; } -*/ -/* -NOW IN LFDEMOD.C -// by marshmellow -// not perfect especially with lower clocks or VERY good antennas (heavy wave clipping) -// maybe somehow adjust peak trimming value based on samples to fix? -int DetectASKClock(int peak) - { - int i=0; - int low=0; - int clk[]={16,32,40,50,64,100,128,256}; - int loopCnt = 256; - if (GraphTraceLenpeak){ - peak = GraphBuffer[i]; - } - if(GraphBuffer[i]=peak) || (GraphBuffer[ii]<=low)){ - errCnt[clkCnt]=0; - for (i=0; i<((int)(GraphTraceLen/clk[clkCnt])-1); ++i){ - if (GraphBuffer[ii+(i*clk[clkCnt])]>=peak || GraphBuffer[ii+(i*clk[clkCnt])]<=low){ - }else if(GraphBuffer[ii+(i*clk[clkCnt])-tol]>=peak || GraphBuffer[ii+(i*clk[clkCnt])-tol]<=low){ - }else if(GraphBuffer[ii+(i*clk[clkCnt])+tol]>=peak || GraphBuffer[ii+(i*clk[clkCnt])+tol]<=low){ - }else{ //error no peak detected - errCnt[clkCnt]++; - } - } - if(errCnt[clkCnt]==0) return clk[clkCnt]; - if(errCnt[clkCnt]127) GraphBuffer[i]=127; //trim - if (GraphBuffer[i]<-127) GraphBuffer[i]=-127; //trim - buff[i]=(uint8_t)(GraphBuffer[i]+128); - } - return i; + if ( buff == NULL ) return -1; + uint32_t i = 0; + + for (; i < GraphTraceLen; ++i){ + + // trim upper and lower values. + if (GraphBuffer[i] > 127) + GraphBuffer[i] = 127; + else if (GraphBuffer[i] < -127) + GraphBuffer[i] = -127; + + buff[i] = (uint8_t)(GraphBuffer[i] + 128); + } + return i; } /* Get or auto-detect clock rate */ -int GetClock(const char *str, int peak, int verbose) +int GetClock(const char *str, int verbose) { - int clock; + int clock; - sscanf(str, "%i", &clock); - if (!strcmp(str, "")) - clock = 0; + sscanf(str, "%i", &clock); + if (!strcmp(str, "")) + clock = 0; - /* Auto-detect clock */ - if (!clock) - { - uint8_t grph[MAX_GRAPH_TRACE_LEN]={0}; - int size = getFromGraphBuf(grph); - clock = DetectASKClock(grph,size,0); - //clock2 = DetectClock2(peak); - /* Only print this message if we're not looping something */ - if (!verbose) - PrintAndLog("Auto-detected clock rate: %d", clock); - } + /* Auto-detect clock */ + if (!clock) { - return clock; + uint8_t grph[MAX_GRAPH_TRACE_LEN] = {0x00}; + int size = GetFromGraphBuf(grph); + if ( size < 0 ) { + PrintAndLog("Failed to copy from graphbuffer"); + return -1; + } + clock = DetectASKClock(grph, size, 0); + + /* Only print this message if we're not looping something */ + if (verbose) + PrintAndLog("Auto-detected clock rate: %d", clock); + } + return clock; } - -/* A simple test to see if there is any data inside Graphbuffer. -*/ +// A simple test to see if there is any data inside Graphbuffer. bool HasGraphData(){ if ( GraphTraceLen <= 0) { @@ -201,4 +119,26 @@ bool HasGraphData(){ return false; } return true; +} + +// Detect high and lows in Grapbuffer. +// Only loops the first 256 values. +void DetectHighLowInGraph(int *high, int *low, bool addFuzz) { + + uint8_t loopMax = 255; + if ( loopMax > GraphTraceLen) + loopMax = GraphTraceLen; + + for (uint8_t i = 0; i < loopMax; ++i) { + if (GraphBuffer[i] > *high) + *high = GraphBuffer[i]; + else if (GraphBuffer[i] < *low) + *low = GraphBuffer[i]; + } + + //12% fuzz in case highs and lows aren't clipped + if (addFuzz) { + *high = (int)(*high * .88); + *low = (int)(*low * .88); + } } \ No newline at end of file diff --git a/client/graph.h b/client/graph.h index afe23686..c745270d 100644 --- a/client/graph.h +++ b/client/graph.h @@ -13,11 +13,11 @@ void AppendGraph(int redraw, int clock, int bit); int ClearGraph(int redraw); -//int DetectClock(int peak); -int getFromGraphBuf(uint8_t *buff); -int GetClock(const char *str, int peak, int verbose); -void setGraphBuf(uint8_t *buff,int size); +int GetFromGraphBuf(uint8_t *buff); +int GetClock(const char *str, int verbose); +void SetGraphBuf(uint8_t *buff,int size); bool HasGraphData(); +void DetectHighLowInGraph(int *high, int *low, bool addFuzz); #define MAX_GRAPH_TRACE_LEN (1024*128) extern int GraphBuffer[MAX_GRAPH_TRACE_LEN]; diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index deab3137..74c36a4d 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -49,8 +49,14 @@ * @return */ int fileExists(const char *filename) { + +#ifdef _WIN32 struct _stat fileStat; int result = _stat(filename, &fileStat); +#else + struct stat fileStat; + int result = stat(filename, &fileStat); +#endif return result == 0; } diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index a820fe41..3e9bdfd5 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -280,7 +280,7 @@ void ProxWidget::paintEvent(QPaintEvent *event) ProxWidget::ProxWidget(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoint(1) { - resize(600, 500); + resize(600, 300); QPalette palette(QColor(0,0,0,0)); palette.setColor(QPalette::WindowText, QColor(255,255,255)); diff --git a/client/ui.c b/client/ui.c index 5111e295..e464a533 100644 --- a/client/ui.c +++ b/client/ui.c @@ -20,13 +20,14 @@ #include "ui.h" #include "cmdmain.h" #include "cmddata.h" +#include "graph.h" //#include #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"; @@ -37,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; @@ -82,8 +83,7 @@ void PrintAndLog(char *fmt, ...) } va_end(argptr2); - if (flushAfterWrite == 1) //buzzy - { + if (flushAfterWrite == 1) { fflush(NULL); } //release lock @@ -98,74 +98,35 @@ void SetLogFilename(char *fn) int manchester_decode( int * data, const size_t len, uint8_t * dataout, size_t dataoutlen){ int bitlength = 0; - int i, clock, high, low, startindex; + 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 */ - for (i = 0; i < len; i++) { - if (data[i] > high) - high = data[i]; - else if (data[i] < low) - low = data[i]; - } - + DetectHighLowInGraph(&high, &low, TRUE); + /* get clock */ - clock = GetT55x7Clock( data, len, high ); + clock = GetClock("", 0); + startindex = DetectFirstTransition(data, len, high); - //PrintAndLog(" Clock : %d", clock); - if (high != 1) + // decode "raw" bitlength = ManchesterConvertFrom255(data, len, bitStream, dataoutlen, high, low, clock, startindex); else - bitlength= ManchesterConvertFrom1(data, len, bitStream, dataoutlen, clock, startindex); + // decode manchester + bitlength = ManchesterConvertFrom1(data, len, bitStream, dataoutlen, clock, startindex); memcpy(dataout, bitStream, bitlength); free(bitStream); return bitlength; } - - int GetT55x7Clock( const int * data, const size_t len, int peak ){ - - int i,lastpeak,clock; - clock = 0xFFFF; - lastpeak = 0; - - /* Detect peak if we don't have one */ - if (!peak) { - for (i = 0; i < len; ++i) { - if (data[i] > peak) { - peak = data[i]; - } - } - } - - for (i = 1; i < len; ++i) { - /* if this is the beginning of a peak */ - if ( data[i-1] != data[i] && data[i] == peak) { - /* find lowest difference between peaks */ - if (lastpeak && i - lastpeak < clock) - clock = i - lastpeak; - lastpeak = i; - } - } - - // When detected clock is 31 or 33 then then return - int clockmod = clock%8; - if ( clockmod == 0) return clock; - - if ( clockmod == 7 ) clock += 1; - else if ( clockmod == 1 ) clock -= 1; - - return clock; - } int DetectFirstTransition(const int * data, const size_t len, int threshold){ - int i =0; + int i = 0; /* now look for the first threshold */ for (; i < len; ++i) { if (data[i] == threshold) { diff --git a/common/lfdemod.c b/common/lfdemod.c index d30262f3..5ab5e03a 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -8,389 +8,418 @@ // Low frequency commands //----------------------------------------------------------------------------- +#include #include #include #include "lfdemod.h" //by marshmellow //takes 1s and 0s and searches for EM410x format - output EM ID -uint64_t Em410xDecode(uint8_t *BitStream,uint32_t BitLen) +uint64_t Em410xDecode(uint8_t *BitStream, uint32_t BitLen) { - //no arguments needed - built this way in case we want this to be a direct call from "data " cmds in the future - // otherwise could be a void with no arguments - //set defaults - int high=0, low=128; - uint64_t lo=0; //hi=0, + //no arguments needed - built this way in case we want this to be a direct call from "data " cmds in the future + // otherwise could be a void with no arguments + //set defaults + int high = 0, low = 128; + uint64_t lo = 0; + uint32_t i = 0; + uint32_t initLoopMax = 65; - uint32_t i = 0; - uint32_t initLoopMax = 65; - if (initLoopMax>BitLen) initLoopMax=BitLen; + if (initLoopMax > BitLen) + initLoopMax = BitLen; + + for (; i < initLoopMax; ++i) //65 samples should be plenty to find high and low values + { + if (BitStream[i] > high) + high = BitStream[i]; + else if (BitStream[i] < low) + low = BitStream[i]; + } + + if (((high !=1)||(low !=0))){ //allow only 1s and 0s + return 0; + } + + uint8_t parityTest = 0; + // 111111111 bit pattern represent start of frame + uint8_t frame_marker_mask[] = {1,1,1,1,1,1,1,1,1}; + uint32_t idx = 0; + uint32_t j = 0; + uint8_t resetCnt = 0; + while( (idx + 64) < BitLen) { + + restart: - for (;i < initLoopMax; ++i) //65 samples should be plenty to find high and low values - { - if (BitStream[i] > high) - high = BitStream[i]; - else if (BitStream[i] < low) - low = BitStream[i]; - } - if (((high !=1)||(low !=0))){ //allow only 1s and 0s - // PrintAndLog("no data found"); - return 0; - } - uint8_t parityTest=0; - // 111111111 bit pattern represent start of frame - uint8_t frame_marker_mask[] = {1,1,1,1,1,1,1,1,1}; - uint32_t idx = 0; - uint32_t ii=0; - uint8_t resetCnt = 0; - while( (idx + 64) < BitLen) { - restart: // search for a start of frame marker - if ( memcmp(BitStream+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { // frame marker found - idx+=9;//sizeof(frame_marker_mask); - for (i=0; i<10;i++){ - for(ii=0; ii<5; ++ii){ - parityTest += BitStream[(i*5)+ii+idx]; - } - if (parityTest== ((parityTest>>1)<<1)){ - parityTest=0; - for (ii=0; ii<4;++ii){ - //hi = (hi<<1)|(lo>>31); - lo=(lo<<1LL)|(BitStream[(i*5)+ii+idx]); - } - //PrintAndLog("DEBUG: EM parity passed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d,lo: %d",parityTest,i,ii,idx,BitStream[idx+ii+(i*5)-5],BitStream[idx+ii+(i*5)-4],BitStream[idx+ii+(i*5)-3],BitStream[idx+ii+(i*5)-2],BitStream[idx+ii+(i*5)-1],lo); - }else {//parity failed - //PrintAndLog("DEBUG: EM parity failed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d",parityTest,i,ii,idx,BitStream[idx+ii+(i*5)-5],BitStream[idx+ii+(i*5)-4],BitStream[idx+ii+(i*5)-3],BitStream[idx+ii+(i*5)-2],BitStream[idx+ii+(i*5)-1]); - parityTest=0; - idx-=8; - if (resetCnt>5)return 0; - resetCnt++; - goto restart;//continue; - } - } - //skip last 5 bit parity test for simplicity. - return lo; - }else{ - idx++; - } - } - return 0; + if ( memcmp(BitStream+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) { + // frame marker found + idx += 9;//sizeof(frame_marker_mask); + for ( i = 0; i < 10; ++i){ + for( j = 0; j < 5; ++j){ + parityTest += BitStream[(i*5) + j + idx]; + } + if (parityTest == ( (parityTest >> 1) << 1)){ + parityTest = 0; + for (j = 0; j < 4; ++j){ + lo = ( lo << 1LL)|( BitStream[( i * 5 ) + j + idx]); + } + } else { + //parity failed + parityTest = 0; + idx -= 8; + if (resetCnt > 5) return 0; + resetCnt++; + goto restart;//continue; + } + } + //skip last 5 bit parity test for simplicity. + return lo; + } else { + idx++; + } + } + return 0; } //by marshmellow //takes 2 arguments - clock and invert both as integers //attempts to demodulate ask while decoding manchester //prints binary found and saves in graphbuffer for further commands -int askmandemod(uint8_t * BinStream,uint32_t *BitLen,int *clk, int *invert) +int askmandemod(uint8_t *BinStream, uint32_t *BitLen, int *clk, int *invert) { - int i; - int high = 0, low = 128; - *clk=DetectASKClock(BinStream,(size_t)*BitLen,*clk); //clock default + int i; + int high = 0, low = 128; + *clk = DetectASKClock(BinStream, (size_t)*BitLen, *clk); //clock default + + if (*clk < 8 ) *clk = 64; + if (*clk < 32 ) *clk = 32; + if (*invert != 1) *invert = 0; + + uint32_t initLoopMax = 200; + if (initLoopMax > *BitLen) + initLoopMax = *BitLen; + + // Detect high and lows + // 200 samples should be enough to find high and low values + for (i = 0; i < initLoopMax; ++i) { + if (BinStream[i] > high) + high = BinStream[i]; + else if (BinStream[i] < low) + low = BinStream[i]; + } + + //throw away static + if ((high < 158) ) + return -2; - if (*clk<8) *clk =64; - if (*clk<32) *clk=32; - if (*invert != 1) *invert=0; - - uint32_t initLoopMax = 200; - if (initLoopMax>*BitLen) initLoopMax=*BitLen; - - // Detect high and lows - for (i = 0; i < initLoopMax; ++i) //200 samples should be enough to find high and low values - { - if (BinStream[i] > high) - high = BinStream[i]; - else if (BinStream[i] < low) - low = BinStream[i]; - } - if ((high < 158) ){ //throw away static - return -2; - } - //25% fuzz in case highs and lows aren't clipped [marshmellow] - high=(int)((high-128)*.75)+128; - low= (int)((low-128)*.75)+128; + //25% fuzz in case highs and lows aren't clipped [marshmellow] + high = (int)(high * .75); + low = (int)(low+128 * .25); - //PrintAndLog("DEBUG - valid high: %d - valid low: %d",high,low); - int lastBit = 0; //set first clock check - uint32_t bitnum = 0; //output counter - int tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave - if (*clk==32)tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely - int iii = 0; - uint32_t gLen = *BitLen; - if (gLen > 3000) gLen=3000; - uint8_t errCnt =0; - uint32_t bestStart = *BitLen; - uint32_t bestErrCnt = (*BitLen/1000); - uint32_t maxErr = (*BitLen/1000); + int lastBit = 0; // set first clock check + uint32_t bitnum = 0; // output counter + + // clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave + //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely + int tol = ( *clk == 32 ) ? 1 : 0; + + int j = 0; + uint32_t gLen = *BitLen; + + if (gLen > 3000) gLen = 3000; + + uint8_t errCnt = 0; + uint32_t bestStart = *BitLen; + uint32_t bestErrCnt = (*BitLen/1000); + uint32_t maxErr = bestErrCnt; //loop to find first wave that works - for (iii=0; iii < gLen; ++iii){ - if ((BinStream[iii]>=high)||(BinStream[iii]<=low)){ - lastBit=iii-*clk; - errCnt=0; + for (j=0; j < gLen; ++j){ + + if ((BinStream[j] >= high)||(BinStream[j] <= low)){ + lastBit = j - *clk; + errCnt = 0; + //loop through to see if this start location works - for (i = iii; i < *BitLen; ++i) { + for (i = j; i < *BitLen; ++i) { if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ - lastBit+=*clk; + lastBit += *clk; } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ //low found and we are expecting a bar - lastBit+=*clk; + lastBit += *clk; } else { //mid value found or no bar supposed to be here - if ((i-lastBit)>(*clk+tol)){ + if ((i-lastBit) > (*clk + tol)){ //should have hit a high or low based on clock!! errCnt++; - lastBit+=*clk;//skip over until hit too many errors - if (errCnt>(maxErr)) break; //allow 1 error for every 1000 samples else start over + lastBit += *clk;//skip over until hit too many errors + if (errCnt > maxErr) break; //allow 1 error for every 1000 samples else start over } } - if ((i-iii) >(400 * *clk)) break; //got plenty of bits + if ((i-j) >(400 * *clk)) break; //got plenty of bits } //we got more than 64 good bits and not all errors - if ((((i-iii)/ *clk) > (64+errCnt)) && (errCnt (64 + errCnt)) && (errCnt < maxErr)) { //possible good read - if (errCnt==0){ - bestStart=iii; - bestErrCnt=errCnt; + if (errCnt == 0){ + bestStart = j; + bestErrCnt = errCnt; break; //great read - finish } - if (errCnt= high) && ((i-lastBit)>(*clk-tol))){ - lastBit+=*clk; - BinStream[bitnum] = *invert; - bitnum++; - } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ - //low found and we are expecting a bar - lastBit+=*clk; - BinStream[bitnum] = 1-*invert; - bitnum++; - } else { - //mid value found or no bar supposed to be here - if ((i-lastBit)>(*clk+tol)){ - //should have hit a high or low based on clock!! - - if (bitnum > 0){ - BinStream[bitnum]=77; - bitnum++; - } - - lastBit+=*clk;//skip over error - } - } - if (bitnum >=400) break; - } - *BitLen=bitnum; - } else{ - *invert=bestStart; - *clk=iii; - return -1; - } + j = bestStart; + lastBit = bestStart - *clk; + bitnum = 0; + for (i = j; i < *BitLen; ++i) { + if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ + lastBit += *clk; + BinStream[bitnum] = *invert; + bitnum++; + } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ + //low found and we are expecting a bar + lastBit += *clk; + BinStream[bitnum] = 1 - *invert; + bitnum++; + } else { + //mid value found or no bar supposed to be here + if ((i-lastBit) > (*clk+tol)){ + //should have hit a high or low based on clock!! + if (bitnum > 0){ + BinStream[bitnum] = 77; + bitnum++; + } + lastBit += *clk;//skip over error + } + } + if (bitnum >= 400) break; + } + *BitLen = bitnum; + } else { + *invert = bestStart; + *clk = j; + return -1; + } return bestErrCnt; } //by marshmellow //take 10 and 01 and manchester decode //run through 2 times and take least errCnt -int manrawdecode(uint8_t * BitStream, int *bitLen) +int manrawdecode(uint8_t * bits, int *bitlen) { - int bitnum=0; - int errCnt =0; - int i=1; + int bitnum = 0; + int errCnt = 0; int bestErr = 1000; int bestRun = 0; - int ii=1; - for (ii=1;ii<3;++ii){ - i=1; - for (i=i+ii;i<*bitLen-2;i+=2){ - if(BitStream[i]==1 && (BitStream[i+1]==0)){ - } else if((BitStream[i]==0)&& BitStream[i+1]==1){ - } else { - errCnt++; - } - if(bitnum>300) break; + int i = 1; + int j = 1; + + for (; j < 3; ++j){ + i = 1; + for ( i = i + j; i < *bitlen-2; i += 2){ + if ( bits[i]==1 && (bits[i+1]==0)){ + } else if ((bits[i]==0)&& bits[i+1]==1){ + } else { + errCnt++; + } + if(bitnum > 300) break; } - if (bestErr>errCnt){ - bestErr=errCnt; - bestRun=ii; + if (bestErr > errCnt){ + bestErr = errCnt; + bestRun = j; } - errCnt=0; - } - errCnt=bestErr; - if (errCnt<20){ - ii=bestRun; - i=1; - for (i=i+ii;i<*bitLen-2;i+=2){ - if(BitStream[i]==1 && (BitStream[i+1]==0)){ - BitStream[bitnum++]=0; - } else if((BitStream[i]==0)&& BitStream[i+1]==1){ - BitStream[bitnum++]=1; - } else { - BitStream[bitnum++]=77; - //errCnt++; - } - if(bitnum>300) break; + errCnt = 0; + } + errCnt = bestErr; + if (errCnt < 20){ + j = bestRun; + i = 1; + for ( i = i+j; i < *bitlen-2; i += 2){ + if ( bits[i] == 1 && bits[i + 1] == 0 ){ + bits[bitnum++] = 0; + } else if ( bits[i] == 0 && bits[i + 1] == 1 ){ + bits[bitnum++] = 1; + } else { + bits[bitnum++] = 77; + } + if ( bitnum > 300 ) break; } - *bitLen=bitnum; + *bitlen = bitnum; } - return errCnt; + return errCnt; } //by marshmellow //take 01 or 10 = 0 and 11 or 00 = 1 -int BiphaseRawDecode(uint8_t * BitStream, int *bitLen, int offset) +int BiphaseRawDecode(uint8_t * bits, int *bitlen, int offset) { - uint8_t bitnum = 0; - uint32_t errCnt = 0; - uint32_t i = 1; - i=offset; - for (;i<*bitLen-2;i+=2){ - if((BitStream[i]==1 && BitStream[i+1]==0)||(BitStream[i]==0 && BitStream[i+1]==1)){ - BitStream[bitnum++]=1; - } else if((BitStream[i]==0 && BitStream[i+1]==0)||(BitStream[i]==1 && BitStream[i+1]==1)){ - BitStream[bitnum++]=0; - } else { - BitStream[bitnum++]=77; - errCnt++; - } - if(bitnum>250) break; + uint8_t bitnum = 0; + uint32_t errCnt = 0; + uint32_t i = offset; + + for (; i < *bitlen-2; i += 2 ){ + if ( (bits[i]==1 && bits[i+1]==0)|| + (bits[i]==0 && bits[i+1]==1)){ + bits[bitnum++] = 1; + } else if ( (bits[i]==0 && bits[i+1]==0)|| + (bits[i]==1 && bits[i+1]==1)){ + bits[bitnum++] = 0; + } else { + bits[bitnum++] = 77; + errCnt++; + } + if ( bitnum > 250) break; } - *bitLen=bitnum; - return errCnt; + *bitlen = bitnum; + return errCnt; } //by marshmellow //takes 2 arguments - clock and invert both as integers //attempts to demodulate ask only //prints binary found and saves in graphbuffer for further commands -int askrawdemod(uint8_t *BinStream, int *bitLen,int *clk, int *invert) +int askrawdemod(uint8_t *BinStream, int *bitLen, int *clk, int *invert) { uint32_t i; - // int invert=0; //invert default - int high = 0, low = 128; - *clk=DetectASKClock(BinStream,*bitLen,*clk); //clock default - uint8_t BitStream[502] = {0}; - - if (*clk<8) *clk =64; - if (*clk<32) *clk=32; - if (*invert != 1) *invert = 0; - uint32_t initLoopMax = 200; - if (initLoopMax>*bitLen) initLoopMax=*bitLen; + int high = 0, low = 128; + uint8_t BitStream[502] = {0x00}; + + *clk = DetectASKClock(BinStream, *bitLen, *clk); //clock default + + if (*clk < 8) *clk = 64; + if (*clk < 32) *clk = 32; + if (*invert != 1) *invert = 0; + + if (initLoopMax > *bitLen) + initLoopMax = *bitLen; + // Detect high and lows for (i = 0; i < initLoopMax; ++i) //200 samples should be plenty to find high and low values { if (BinStream[i] > high) - high = BinStream[i]; + high = BinStream[i]; else if (BinStream[i] < low) - low = BinStream[i]; + low = BinStream[i]; } - if ((high < 158)){ //throw away static - return -2; - } - //25% fuzz in case highs and lows aren't clipped [marshmellow] - high=(int)((high-128)*.75)+128; - low= (int)((low-128)*.75)+128; + + //throw away static + if ((high < 158)){ + return -2; + } + + //25% fuzz in case highs and lows aren't clipped [marshmellow] + high = (int)(high * .75); + low = (int)(low+128 * .25); + + int lastBit = 0; //set first clock check + uint32_t bitnum = 0; //output counter + + uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave + if (*clk==32) tol = 1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely - int lastBit = 0; //set first clock check - uint32_t bitnum = 0; //output counter - uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave - if (*clk==32) tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely - uint32_t iii = 0; uint32_t gLen = *bitLen; - if (gLen > 500) gLen=500; - uint8_t errCnt =0; - uint32_t bestStart = *bitLen; - uint32_t bestErrCnt = (*bitLen/1000); - uint8_t midBit=0; + if (gLen > 500) gLen = 500; + uint32_t j = 0; + uint8_t errCnt = 0; + uint32_t bestStart = *bitLen; + uint32_t bestErrCnt = (*bitLen / 1000); + uint32_t errCntLimit = bestErrCnt; + uint8_t midBit = 0; + //loop to find first wave that works - for (iii=0; iii < gLen; ++iii){ - if ((BinStream[iii]>=high)||(BinStream[iii]<=low)){ - lastBit=iii-*clk; + for (j = 0; j < gLen; ++j){ + + if ((BinStream[j] >= high)||(BinStream[j] <= low)){ + lastBit = j - *clk; //loop through to see if this start location works - for (i = iii; i < *bitLen; ++i) { + for (i = j; i < *bitLen; ++i) { if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ - lastBit+=*clk; + lastBit += *clk; BitStream[bitnum] = *invert; bitnum++; - midBit=0; + midBit = 0; } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ //low found and we are expecting a bar - lastBit+=*clk; + lastBit += *clk; BitStream[bitnum] = 1-*invert; bitnum++; midBit=0; } else if ((BinStream[i]<=low) && (midBit==0) && ((i-lastBit)>((*clk/2)-tol))){ //mid bar? - midBit=1; - BitStream[bitnum]= 1-*invert; + midBit = 1; + BitStream[bitnum] = 1 - *invert; bitnum++; } else if ((BinStream[i]>=high)&&(midBit==0) && ((i-lastBit)>((*clk/2)-tol))){ //mid bar? - midBit=1; - BitStream[bitnum]= *invert; + midBit = 1; + BitStream[bitnum] = *invert; bitnum++; } else if ((i-lastBit)>((*clk/2)+tol)&&(midBit==0)){ //no mid bar found - midBit=1; - BitStream[bitnum]= BitStream[bitnum-1]; + midBit = 1; + BitStream[bitnum] = BitStream[bitnum-1]; bitnum++; } else { //mid value found or no bar supposed to be here - if ((i-lastBit)>(*clk+tol)){ + if (( i - lastBit) > ( *clk + tol)){ //should have hit a high or low based on clock!! if (bitnum > 0){ - BitStream[bitnum]=77; + BitStream[bitnum] = 77; bitnum++; } errCnt++; - lastBit+=*clk;//skip over until hit too many errors - if (errCnt>((*bitLen/1000))){ //allow 1 error for every 1000 samples else start over - errCnt=0; - bitnum=0;//start over + lastBit += *clk;//skip over until hit too many errors + if (errCnt > errCntLimit){ //allow 1 error for every 1000 samples else start over + errCnt = 0; + bitnum = 0;//start over break; } } } - if (bitnum>500) break; + if (bitnum > 500) break; } //we got more than 64 good bits and not all errors - if ((bitnum > (64+errCnt)) && (errCnt<(*bitLen/1000))) { - //possible good read - if (errCnt==0) break; //great read - finish - if (bestStart == iii) break; //if current run == bestErrCnt run (after exhausted testing) then finish - if (errCnt (64 + errCnt)) && (errCnt < errCntLimit)) { + + //great read - finish + if (errCnt == 0) break; + + //if current run == bestErrCnt run (after exhausted testing) then finish + if (bestStart == j) break; + + //set this as new best run + if (errCnt < bestErrCnt){ + bestErrCnt = errCnt; + bestStart = j; } } } - if (iii>=gLen){ //exhausted test + if (j >= gLen){ //exhausted test //if there was a ok test go back to that one and re-run the best run (then dump after that run) - if (bestErrCnt < (*bitLen/1000)) iii=bestStart; + if (bestErrCnt < errCntLimit) + j = bestStart; } } - if (bitnum>16){ + if (bitnum > 16){ - for (i=0; i < bitnum; ++i){ - BinStream[i]=BitStream[i]; + for (i = 0; i < bitnum; ++i){ + BinStream[i] = BitStream[i]; } *bitLen = bitnum; } else { @@ -403,43 +432,49 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow { uint32_t last_transition = 0; uint32_t idx = 1; - uint32_t maxVal=0; - if (fchigh==0) fchigh=10; - if (fclow==0) fclow=8; + uint32_t maxVal = 0; + + if (fchigh == 0) fchigh = 10; + if (fclow == 0) fclow = 8; + // we do care about the actual theshold value as sometimes near the center of the // wave we may get static that changes direction of wave for one value // if our value is too low it might affect the read. and if our tag or // antenna is weak a setting too high might not see anything. [marshmellow] - if (size<100) return 0; - for(idx=1; idx<100; idx++){ - if(maxVal1 transition if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition - if ((idx-last_transition)<(fclow-2)){ //0-5 = garbage noise + if ( ( idx - last_transition ) <( fclow - 2 ) ) { //0-5 = garbage noise //do nothing with extra garbage - } else if ((idx-last_transition) < (fchigh-1)) { //6-8 = 8 waves + } else if ((idx - last_transition) < ( fchigh - 1 )) { //6-8 = 8 waves dest[numBits]=1; } else { //9+ = 10 waves dest[numBits]=0; @@ -448,7 +483,8 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow numBits++; } } - return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 + //it returns the number of bytes, but each byte represents a bit: 1 or 0 + return numBits; } uint32_t myround2(float f) @@ -458,87 +494,92 @@ uint32_t myround2(float f) } //translate 11111100000 to 10 -size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert,uint8_t fchigh,uint8_t fclow )// uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, +size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert, uint8_t fchigh, uint8_t fclow ) { - uint8_t lastval=dest[0]; - uint32_t idx=0; - size_t numBits=0; - uint32_t n=1; + uint8_t lastval = dest[0]; + uint32_t idx = 0; + uint32_t n = 1; + size_t numBits = 0; - for( idx=1; idx < size; idx++) { + for( idx = 1; idx < size; idx++) { - if (dest[idx]==lastval) { + if (dest[idx] == lastval) { n++; continue; } //if lastval was 1, we have a 1->0 crossing - if ( dest[idx-1]==1 ) { - n=myround2((float)(n+1)/((float)(rfLen)/(float)fclow)); - //n=(n+1) / h2l_crossing_value; - } else {// 0->1 crossing - n=myround2((float)(n+1)/((float)(rfLen-2)/(float)fchigh)); //-2 for fudge factor - //n=(n+1) / l2h_crossing_value; + if ( dest[idx-1] == 1 ) { + n = myround2( (float)( n + 1 ) / ((float)(rfLen)/(float)fclow)); + } else { // 0->1 crossing + n = myround2( (float)( n + 1 ) / ((float)(rfLen-2)/(float)fchigh)); //-2 for fudge factor } if (n == 0) n = 1; if(n < maxConsequtiveBits) //Consecutive { - if(invert==0){ //invert bits + if(invert == 0){ //invert bits memset(dest+numBits, dest[idx-1] , n); }else{ memset(dest+numBits, dest[idx-1]^1 , n); } numBits += n; } - n=0; - lastval=dest[idx]; + n = 0; + lastval = dest[idx]; }//end for return numBits; } + //by marshmellow (from holiman's base) // full fsk demod from GraphBuffer wave to decoded 1s and 0s (no mandemod) int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow) { - // FSK demodulator - size = fsk_wave_demod(dest, size, fchigh, fclow); - size = aggregate_bits(dest, size,rfLen,192,invert,fchigh,fclow); - return size; + // FSK demodulator + size = fsk_wave_demod(dest, size, fchigh, fclow); + if ( size > 0 ) + size = aggregate_bits(dest, size, rfLen, 192, invert, fchigh, fclow); + else + return -1; + return size; } + // loop to get raw HID waveform then FSK demodulate the TAG ID from it int HIDdemodFSK(uint8_t *dest, size_t size, uint32_t *hi2, uint32_t *hi, uint32_t *lo) { - - size_t idx=0; //, found=0; //size=0, + size_t idx = 0; + int numshifts = 0; + // FSK demodulator - size = fskdemod(dest, size,50,0,10,8); + size = fskdemod(dest, size, 50, 0, 10, 8); // final loop, go over previously decoded manchester data and decode into usable tag ID // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 uint8_t frame_marker_mask[] = {1,1,1,0,0,0}; - int numshifts = 0; - idx = 0; + + uint8_t mask_len = sizeof frame_marker_mask / sizeof frame_marker_mask[0]; + //one scan - while( idx + sizeof(frame_marker_mask) < size) { + while( idx + mask_len < size) { // search for a start of frame marker if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) { // frame marker found - idx+=sizeof(frame_marker_mask); + idx += mask_len; while(dest[idx] != dest[idx+1] && idx < size-2) { // Keep going until next frame marker (or error) // Shift in a bit. Start by shifting high registers - *hi2 = (*hi2<<1)|(*hi>>31); - *hi = (*hi<<1)|(*lo>>31); + *hi2 = ( *hi2 << 1 ) | ( *hi >> 31 ); + *hi = ( *hi << 1 ) | ( *lo >> 31 ); //Then, shift in a 0 or one into low if (dest[idx] && !dest[idx+1]) // 1 0 - *lo=(*lo<<1)|0; + *lo = ( *lo << 1 ) | 0; else // 0 1 - *lo=(*lo<<1)|1; + *lo = ( *lo << 1 ) | 1; numshifts++; idx += 2; } // Hopefully, we read a tag and hit upon the next frame marker - if(idx + sizeof(frame_marker_mask) < size) + if(idx + mask_len < size) { if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) { @@ -556,10 +597,12 @@ int HIDdemodFSK(uint8_t *dest, size_t size, uint32_t *hi2, uint32_t *hi, uint32_ return -1; } -uint32_t bytebits_to_byte(uint8_t* src, int numbits) +uint32_t bytebits_to_byte(uint8_t *src, int numbits) { + //HACK: potential overflow in numbits is larger then uint32 bits. + uint32_t num = 0; - for(int i = 0 ; i < numbits ; i++) { + for(int i = 0 ; i < numbits ; ++i) { num = (num << 1) | (*src); src++; } @@ -568,41 +611,54 @@ uint32_t bytebits_to_byte(uint8_t* src, int numbits) int IOdemodFSK(uint8_t *dest, size_t size) { - uint32_t idx=0; //make sure buffer has data - if (size < 66) return -1; + if (size < 100) return -1; + + uint32_t idx = 0; + uint8_t testMax = 0; + //test samples are not just noise - uint8_t testMax=0; - for(idx=0;idx<65;idx++){ - if (testMax170){ - // FSK demodulator - size = fskdemod(dest, size,64,1,10,8); // RF/64 and invert - if (size < 65) return -1; //did we get a good demod? - //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 - uint8_t mask[] = {0,0,0,0,0,0,0,0,0,1}; - for( idx=0; idx < (size - 65); idx++) { - if ( memcmp(dest + idx, mask, sizeof(mask))==0) { - //frame marker found - if (!dest[idx+8] && dest[idx+17]==1 && dest[idx+26]==1 && dest[idx+35]==1 && dest[idx+44]==1 && dest[idx+53]==1){ - //confirmed proper separator bits found - //return start position - return (int) idx; - } - } - } - } + if (testMax < 170) return -2; + + // FSK demodulator + size = fskdemod(dest, size, 64, 1, 10, 8); // RF/64 and invert + + //did we get a good demod? + if (size < 65) return -3; + + //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 + + uint8_t mask[] = {0,0,0,0,0,0,0,0,0,1}; + + for( idx = 0; idx < (size - 65); ++idx) { + if ( memcmp(dest + idx, mask, sizeof(mask))==0) { + //frame marker found + if (!dest[idx+8] && + dest[idx+17] == 1 && + dest[idx+26] == 1 && + dest[idx+35] == 1 && + dest[idx+44] == 1 && + dest[idx+53] == 1){ + //confirmed proper separator bits found + //return start position + return (int) idx; + } + } + } return 0; } @@ -611,67 +667,86 @@ int IOdemodFSK(uint8_t *dest, size_t size) // maybe somehow adjust peak trimming value based on samples to fix? int DetectASKClock(uint8_t dest[], size_t size, int clock) { - int i=0; - int peak=0; - int low=128; - int clk[]={16,32,40,50,64,100,128,256}; - int loopCnt = 256; //don't need to loop through entire array... - if (size peak) + peak = dest[i]; + if(dest[i] < low) + low = dest[i]; + } - //if we already have a valid clock quit - for (;i<8;++i) - if (clk[i]==clock) return clock; + peak = (int)(peak * .75); + low = (int)(low+128 * .25); + + int ii, cnt, bestErr, tol = 0; + int errCnt[clkLen]; + memset(errCnt, 0x00, clkLen); + + int tmpIndex, tmphigh, tmplow; + + //test each valid clock from smallest to greatest to see which lines up + for( cnt = 0; cnt < clkLen; ++cnt ){ - //get high and low peak - for (i=0;ipeak){ - peak = dest[i]; - } - if(dest[i]=peak) || (dest[ii]<=low)){ - errCnt[clkCnt]=0; - // now that we have the first one lined up test rest of wave array - for (i=0; i<((int)(size/clk[clkCnt])-1); ++i){ - if (dest[ii+(i*clk[clkCnt])]>=peak || dest[ii+(i*clk[clkCnt])]<=low){ - }else if(dest[ii+(i*clk[clkCnt])-tol]>=peak || dest[ii+(i*clk[clkCnt])-tol]<=low){ - }else if(dest[ii+(i*clk[clkCnt])+tol]>=peak || dest[ii+(i*clk[clkCnt])+tol]<=low){ - }else{ //error no peak detected - errCnt[clkCnt]++; - } - } - //if we found no errors this is correct one - return this clock - if(errCnt[clkCnt]==0) return clk[clkCnt]; - //if we found errors see if it is lowest so far and save it as best run - if(errCnt[clkCnt] low)) + continue; + + errCnt[cnt] = 0; + + // now that we have the first one lined up test rest of wave array + for ( i = 0; i < ((int)(size / clk[cnt]) - 1); ++i){ + + tmpIndex = ii + (i * clk[cnt] ); + tmplow = dest[ tmpIndex - tol]; + tmphigh = dest[ tmpIndex + tol]; + + if ( dest[tmpIndex] >= peak || dest[tmpIndex] <= low ) { + } + else if ( tmplow >= peak || tmplow <= low){ + } + else if ( tmphigh >= peak || tmphigh <= low){ + } + else + errCnt[cnt]++; //error no peak detected + } + + //if we found no errors this is correct one - return this clock + if ( errCnt[cnt] == 0 ) + return clk[cnt]; + + if ( errCnt[cnt] < bestErr) + bestErr = errCnt[cnt]; + } + // save the least error. + errCnt[cnt] = bestErr; + } + // find best clock which has lowest number of errors + int j = 0, bestIndex = 0; + for (; j < clkLen; ++j){ + if ( errCnt[j] < errCnt[bestIndex] ) + bestIndex = j; + } + return clk[bestIndex]; } From f0cf62cd734219c2f8b012a4e3ba42520344bce4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 4 Jan 2015 23:43:07 +0100 Subject: [PATCH 71/78] FIX: fixed a little bug I introduced from last commit in fskdemod CHG: tab fixes in cmdlf.c and minor code clean up CHG: minor variable name change, printstatement in cmddata.c --- client/cmddata.c | 10 +- client/cmdlf.c | 741 +++++++++++++++++++++++------------------------ common/lfdemod.c | 2 - 3 files changed, 375 insertions(+), 378 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index e9499ed8..8d74750d 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -220,12 +220,12 @@ int Cmdaskmandemod(const char *Cmd) PrintAndLog("ASK/Manchester decoded bitstream:"); printBitStream(bits, len); - uint64_t lo = Em410xDecode(bits, len); - if (lo > 0){ - SetGraphBuf(bits,len); - PrintAndLog("EM410x pattern found: "); - printEM410x(lo); + uint64_t tagid = Em410xDecode(bits, len); + + if (tagid > 0){ + SetGraphBuf(bits, len); + printEM410x(tagid); return 1; } return 0; diff --git a/client/cmdlf.c b/client/cmdlf.c index e445b47b..9a9984d1 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -48,385 +48,386 @@ int CmdLFCommandRead(const char *Cmd) 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; - } + #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; + GraphBuffer[start] = 2; + GraphBuffer[start+1] = -2; + uint8_t bits[64] = {0x00}; - uint8_t bits[64]; + int bit, sum; + i = start; + for (bit = 0; bit < 64; bit++) { + sum = 0; + for (int j = 0; j < 16; j++) { + sum += GraphBuffer[i++]; + } - int bit; - i = start; - 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; - } else { - bits[bit] = 0; - } - PrintAndLog("bit %d sum %d", bit, sum); - } + bits[bit] = (sum > 0) ? 1 : 0; - 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); + } - GraphTraceLen = 32*64; - i = 0; - int phase = 0; - for (bit = 0; bit < 64; bit++) { - if (bits[bit] == 0) { - phase = 0; - } else { - phase = 1; - } - int j; - for (j = 0; j < 32; j++) { - GraphBuffer[i++] = phase; - phase = !phase; - } - } + 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); + } + } - RepaintGraphWindow(); - return 0; + // HACK writing back to graphbuffer. + 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 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; - // 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; - 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); - } 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; - } + int state = -1; + int count = 0; + int i, j; - // Inverting signal if needed - if (first == 1) { - for (i = start; i < rawbit; i++) { - rawbits[i] = !rawbits[i]; - } - } + // worst case with GraphTraceLen=64000 is < 4096 + // under normal conditions it's < 2048 - // Dumping UID - uint8_t bits[224]; - char showbits[225]; - showbits[uidlen]='\0'; - 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; - } + uint8_t rawbits[4096]; + int rawbit = 0; + int worst = 0, worstPos = 0; - //convert UID to HEX - uint32_t uid1, uid2, uid3, uid4, uid5, uid6, uid7; - int idx; - uid1=0; - 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 { - uid3=0; - uid4=0; - uid5=0; - uid6=0; - 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); - 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("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); + } else { + return 0; + } - // Checking UID against next occurrences - for (; i + uidlen <= rawbit;) { - int 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); + // 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; + } - // Remodulating for tag cloning - 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; - } - } + 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; + } - RepaintGraphWindow(); - return 1; + // 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; + } + + //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 { + 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); + + 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); + } + + // 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 + // 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; } int CmdIndalaClone(const char *Cmd) { - unsigned int uid1, uid2, uid3, uid4, uid5, uid6, uid7; - UsbCommand c; - uid1=0; - uid2=0; - uid3=0; - uid4=0; - uid5=0; - uid6=0; - uid7=0; - int n = 0, i = 0; + UsbCommand c; + unsigned int uid1, uid2, uid3, uid4, uid5, uid6, uid7; - 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; - } + uid1 = uid2 = uid3 = uid4 = uid5 = uid6 = uid7 = 0; + int n = 0, i = 0; - SendCommand(&c); - return 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; } int CmdLFRead(const char *Cmd) { - UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K}; - // 'h' means higher-low-frequency, 134 kHz - if(*Cmd == 'h') { - c.arg[0] = 1; - } else if (*Cmd == '\0') { - c.arg[0] = 0; - } else if (sscanf(Cmd, "%"lli, &c.arg[0]) != 1) { - PrintAndLog("Samples 1: 'lf read'"); - PrintAndLog(" 2: 'lf read h'"); - PrintAndLog(" 3: 'lf read '"); - return 0; - } - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - - // load samples - CmdSamples(""); - // show plot - ShowGraphWindow(); - return 0; + UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K}; + + // 'h' means higher-low-frequency, 134 kHz + if(*Cmd == 'h') { + c.arg[0] = 1; + } else if (*Cmd == '\0') { + c.arg[0] = 0; + } else if (sscanf(Cmd, "%"lli, &c.arg[0]) != 1) { + PrintAndLog("Samples 1: 'lf read'"); + PrintAndLog(" 2: 'lf read h'"); + PrintAndLog(" 3: 'lf read '"); + return 0; + } + SendCommand(&c); + WaitForResponse(CMD_ACK,NULL); + + CmdSamples(""); + ShowGraphWindow(); + return 0; } static void ChkBitstream(const char *str) { - int i; + int i; - /* convert to bitstream if necessary */ - for (i = 0; i < (int)(GraphTraceLen / 2); i++) - { - if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) - { - CmdBitstream(str); - break; - } - } + /* convert to bitstream if necessary */ + for (i = 0; i < (int)(GraphTraceLen / 2); i++){ + if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) { + CmdBitstream(str); + break; + } + } } 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); + /* convert to bitstream if necessary */ + ChkBitstream(Cmd); - 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}}; + 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; + 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 CmdLFSimBidir(const char *Cmd) { - /* Set ADC to twice the carrier for a slight supersampling */ + // 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; @@ -435,29 +436,23 @@ int CmdLFSimBidir(const char *Cmd) /* simulate an LF Manchester encoded tag with specified bitstream, clock rate and inter-id gap */ int CmdLFSimManchester(const char *Cmd) { - static int clock, gap; - static char data[1024], gapstring[8]; + static int clock, gap; + static char data[1024], gapstring[8]; - /* get settings/bits */ - sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap); + sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap); - /* clear our graph */ - ClearGraph(0); + ClearGraph(0); - /* fill it with our bitstream */ - for (int i = 0; i < strlen(data) ; ++i) - AppendGraph(0, clock, data[i]- '0'); + for (int i = 0; i < strlen(data) ; ++i) + AppendGraph(0, clock, data[i]- '0'); - /* modulate */ - CmdManchesterMod(""); + CmdManchesterMod(""); - /* show what we've done */ - RepaintGraphWindow(); + RepaintGraphWindow(); - /* simulate */ - sprintf(&gapstring[0], "%i", gap); - CmdLFSim(gapstring); - return 0; + sprintf(&gapstring[0], "%i", gap); + CmdLFSim(gapstring); + return 0; } int CmdLFSnoop(const char *Cmd) @@ -474,24 +469,22 @@ int CmdLFSnoop(const char *Cmd) c.arg[0] = 1; sscanf(Cmd, "h %"lli, &c.arg[1]); } else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) { - PrintAndLog("use 'snoop' or 'snoop {l,h} [trigger threshold]', or 'snoop [trigger threshold]'"); + PrintAndLog("usage 1: snoop"); + PrintAndLog(" 2: snoop {l,h} [trigger threshold]"); + PrintAndLog(" 3: snoop [trigger threshold]"); return 0; } SendCommand(&c); WaitForResponse(CMD_ACK,NULL); - size_t BUFF_SIZE = 8000; - uint8_t data[BUFF_SIZE]; + #define BUFF_SIZE 8000 + uint8_t data[BUFF_SIZE] = {0x00}; - GetFromBigBuf(data,BUFF_SIZE,0); //3560 -- should be offset.. + GetFromBigBuf(data,BUFF_SIZE,0); WaitForResponseTimeout(CMD_ACK,NULL, 1500); - for (int j = 0; j < BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]); - } - - GraphTraceLen = BUFF_SIZE; + SetGraphBuf(data, BUFF_SIZE); return 0; } @@ -596,24 +589,30 @@ int CmdLFfind(const char *Cmd) PrintAndLog("Checking for known tags:"); - ans=Cmdaskmandemod(""); - PrintAndLog("ASK_MAN: %s", (ans)?"YES":"NO" ); + ans = Cmdaskmandemod(""); + PrintAndLog("ASK_MAN: %s", (ans) ? "YES":"NO" ); - ans=CmdFSKdemodHID(""); - PrintAndLog("HID: %s", (ans)?"YES":"NO" ); + ans = CmdFSKdemodHID(""); + PrintAndLog("HID: %s", (ans) ? "YES":"NO" ); - ans=CmdFSKdemodIO(""); - PrintAndLog("IO prox: %s", (ans)?"YES":"NO" ); + ans = CmdFSKdemodIO(""); + PrintAndLog("IO prox: %s", (ans) ? "YES":"NO" ); - ans=CmdIndalaDemod(""); - PrintAndLog("Indala (64): %s", (ans)?"YES":"NO" ); + ans = CmdIndalaDemod(""); + PrintAndLog("Indala (64): %s", (ans) ? "YES":"NO" ); - ans=CmdIndalaDemod("224"); - PrintAndLog("Indala (224): %s", (ans)?"YES":"NO" ); + ans = CmdIndalaDemod("224"); + PrintAndLog("Indala (224): %s", (ans) ? "YES":"NO" ); + // ans = CmdVchDemod(""); + // PrintAndLog("VeriChip: %s", (ans) ? "YES":"NO" ); + + // ans = CmdFlexdemod(""); + // PrintAndLog("FlexPass: %s", (ans) ? "YES":"NO" ); + if (!ans) PrintAndLog("No Known Tags Found!\n"); - + return 0; } diff --git a/common/lfdemod.c b/common/lfdemod.c index 5ab5e03a..873b6305 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -538,8 +538,6 @@ int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t size = fsk_wave_demod(dest, size, fchigh, fclow); if ( size > 0 ) size = aggregate_bits(dest, size, rfLen, 192, invert, fchigh, fclow); - else - return -1; return size; } From d3a22c7dfa87bf5e21d228849a602194be4a0895 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 5 Jan 2015 02:01:24 +0100 Subject: [PATCH 72/78] ADD: Holimans new changes in master. --- armsrc/iclass.c | 259 +++++++++++++++++--------------- armsrc/iso15693.c | 4 +- armsrc/lfops.c | 2 +- client/cmddata.c | 1 + client/cmdhf.c | 280 ++++++++++++++++++++++++++++++++++- client/cmdhf.h | 2 +- client/cmdhf14a.c | 4 +- client/cmdhf15.c | 2 +- client/cmdhficlass.c | 194 ++++++------------------ client/cmdhfmf.c | 6 +- client/cmdlf.c | 4 +- client/cmdlft55xx.c | 1 - client/loclass/cipher.c | 6 +- client/loclass/cipher.h | 6 +- client/loclass/cipherutils.c | 5 +- client/loclass/cipherutils.h | 6 +- client/loclass/fileutils.c | 3 + client/loclass/fileutils.h | 2 +- client/loclass/ikeys.c | 12 +- client/proxmark3.c | 1 - common/iso15693tools.c | 4 +- common/lfdemod.c | 4 +- include/usb_cmd.h | 1 + 23 files changed, 488 insertions(+), 321 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 74705b49..cf1931fd 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1467,97 +1467,142 @@ void setupIclassReader() } +size_t sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries) +{ + while(retries-- > 0) + { + ReaderTransmitIClass(command, cmdsize); + if(expected_size == ReaderReceiveIClass(resp)){ + return 0; + } + } + return 1;//Error +} + +/** + * @brief Talks to an iclass tag, sends the commands to get CSN and CC. + * @param card_data where the CSN and CC are stored for return + * @return 0 = fail + * 1 = Got CSN + * 2 = Got CSN and CC + */ +uint8_t handshakeIclassTag(uint8_t *card_data) +{ + static uint8_t act_all[] = { 0x0a }; + static uint8_t identify[] = { 0x0c }; + static uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static uint8_t readcheck_cc[]= { 0x88, 0x02 }; + uint8_t *resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); + + uint8_t read_status = 0; + + // Send act_all + ReaderTransmitIClass(act_all, 1); + // Card present? + if(!ReaderReceiveIClass(resp)) return read_status;//Fail + //Send Identify + ReaderTransmitIClass(identify, 1); + //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC + uint8_t len = ReaderReceiveIClass(resp); + if(len != 10) return read_status;//Fail + + //Copy the Anti-collision CSN to our select-packet + memcpy(&select[1],resp,8); + //Select the card + ReaderTransmitIClass(select, sizeof(select)); + //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC + len = ReaderReceiveIClass(resp); + if(len != 10) return read_status;//Fail + + //Success - level 1, we got CSN + //Save CSN in response data + memcpy(card_data,resp,8); + + //Flag that we got to at least stage 1, read CSN + read_status = 1; + + // Card selected, now read e-purse (cc) + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + //Save CC (e-purse) in response data + memcpy(card_data+8,resp,8); + + //Got both + read_status = 2; + } + + return read_status; +} + // Reader iClass Anticollission void ReaderIClass(uint8_t arg0) { - uint8_t act_all[] = { 0x0a }; - uint8_t identify[] = { 0x0c }; - uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t readcheck_cc[]= { 0x88, 0x02 }; uint8_t card_data[24]={0}; uint8_t last_csn[8]={0}; - uint8_t *resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); - int read_status= 0; bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; + bool get_cc = arg0 & FLAG_ICLASS_READER_GET_CC; setupIclassReader(); size_t datasize = 0; while(!BUTTON_PRESS()) { + + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); + break; + } WDT_HIT(); - // Send act_all - ReaderTransmitIClass(act_all, 1); - // Card present? - if(ReaderReceiveIClass(resp)) { + read_status = handshakeIclassTag(card_data); - ReaderTransmitIClass(identify, 1); - - if(ReaderReceiveIClass(resp) == 10) { - //Copy the Anti-collision CSN to our select-packet - memcpy(&select[1],resp,8); - //Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2], - // resp[3], resp[4], resp[5], - // resp[6], resp[7]); - //Select the card - ReaderTransmitIClass(select, sizeof(select)); - - if(ReaderReceiveIClass(resp) == 10) { - //Save CSN in response data - memcpy(card_data,resp,8); - datasize += 8; - //Flag that we got to at least stage 1, read CSN - read_status = 1; - - // Card selected - //Dbprintf("Readcheck on Sector 2"); - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); - if(ReaderReceiveIClass(resp) == 8) { - //Save CC (e-purse) in response data - memcpy(card_data+8,resp,8); - datasize += 8; - //Got both - read_status = 2; - } + if(read_status == 0) continue; + if(read_status == 1) datasize = 8; + if(read_status == 2) datasize = 16; 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(!get_cc || (get_cc && read_status == 2)) + { cmd_send(CMD_ACK,read_status,0,0,card_data,datasize); - + if(abort_after_read) { + LED_A_OFF(); + return; + } //Save that we already sent this.... - if(read_status == 2) memcpy(last_csn, card_data, 8); - + } + //If 'get_cc' was specified and we didn't get a CC, we'll just keep trying... + } LED_B_OFF(); - - if(abort_after_read) break; - } - } - } - - if(traceLen > TRACE_SIZE) { - DbpString("Trace full"); - break; - } } + cmd_send(CMD_ACK,0,0,0,card_data, 0); LED_A_OFF(); } void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { - uint8_t act_all[] = { 0x0a }; - uint8_t identify[] = { 0x0c }; - uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t readcheck_cc[]= { 0x88, 0x02 }; + + uint8_t card_data[24]={0}; + uint16_t block_crc_LUT[255] = {0}; + + {//Generate a lookup table for block crc + for(int block = 0; block < 255; block++){ + char bl = block; + block_crc_LUT[block] = iclass_crc16(&bl ,1); + } + } + //Dbprintf("Lookup table: %02x %02x %02x" ,block_crc_LUT[0],block_crc_LUT[1],block_crc_LUT[2]); + uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; uint16_t crc = 0; uint8_t cardsize=0; - bool read_success=false; uint8_t mem=0; static struct memory_t{ @@ -1573,65 +1618,39 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { setupIclassReader(); - for(int i=0;i<1;i++) { + while(!BUTTON_PRESS()) { + + WDT_HIT(); if(traceLen > TRACE_SIZE) { DbpString("Trace full"); break; } - if (BUTTON_PRESS()) break; + uint8_t read_status = handshakeIclassTag(card_data); + if(read_status < 2) continue; - // Send act_all - ReaderTransmitIClass(act_all, 1); - // Card present? - if(ReaderReceiveIClass(resp)) { - ReaderTransmitIClass(identify, 1); - if(ReaderReceiveIClass(resp) == 10) { - // Select card - memcpy(&select[1],resp,8); - ReaderTransmitIClass(select, sizeof(select)); - - if(ReaderReceiveIClass(resp) == 10) { - Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x", - resp[0], resp[1], resp[2], - resp[3], resp[4], resp[5], - resp[6], resp[7]); - } - // Card selected - Dbprintf("Readcheck on Sector 2"); - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); - if(ReaderReceiveIClass(resp) == 8) { - Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x", - resp[0], resp[1], resp[2], - resp[3], resp[4], resp[5], - resp[6], resp[7]); - }else return; - Dbprintf("Authenticate"); //for now replay captured auth (as cc not updated) memcpy(check+5,MAC,4); - //Dbprintf(" AA: %02x %02x %02x %02x", - // check[5], check[6], check[7],check[8]); - ReaderTransmitIClass(check, sizeof(check)); - if(ReaderReceiveIClass(resp) == 4) { - Dbprintf(" AR: %02x %02x %02x %02x", - resp[0], resp[1], resp[2],resp[3]); - }else { + + if(sendCmdGetResponseWithRetries(check, sizeof(check),resp, 4, 5)) + { Dbprintf("Error: Authentication Fail!"); - return; + continue; } - Dbprintf("Dump Contents"); - //first get configuration block - read_success=false; + + //first get configuration block (block 1) + crc = block_crc_LUT[1]; read[1]=1; - uint8_t *blockno=&read[1]; - crc = iclass_crc16((char *)blockno,1); read[2] = crc >> 8; read[3] = crc & 0xff; - while(!read_success){ - ReaderTransmitIClass(read, sizeof(read)); - if(ReaderReceiveIClass(resp) == 10) { - read_success=true; + + if(sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10)) + { + Dbprintf("Dump config (block 1) failed"); + continue; + } + mem=resp[5]; memory.k16= (mem & 0x80); memory.book= (mem & 0x20); @@ -1639,36 +1658,32 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { memory.lockauth= (mem & 0x2); memory.keyaccess= (mem & 0x1); - } - } - if (memory.k16){ - cardsize=255; - }else cardsize=32; + cardsize = memory.k16 ? 255 : 32; + WDT_HIT(); + //then loop around remaining blocks - for(uint8_t j=0; j> 8; read[3] = crc & 0xff; - while(!read_success){ - ReaderTransmitIClass(read, sizeof(read)); - if(ReaderReceiveIClass(resp) == 10) { - read_success=true; + + if(!sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10)) + { Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", - j, resp[0], resp[1], resp[2], + block, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5], resp[6], resp[7]); - } - } - } + + }else{ + Dbprintf("Failed to dump block %d", block); + } } - WDT_HIT(); + //If we got here, let's break + break; } - LED_A_OFF(); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 4a767b56..c4f5f612 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -586,7 +586,7 @@ static void BuildIdentifyRequest(void); //----------------------------------------------------------------------------- void AcquireRawAdcSamplesIso15693(void) { - uint8_t *dest = get_bigbufptr_recvrespbuf(); + uint8_t *dest = (uint8_t *)BigBuf; int c = 0; int getNext = 0; @@ -668,7 +668,7 @@ void AcquireRawAdcSamplesIso15693(void) void RecordRawAdcSamplesIso15693(void) { - uint8_t *dest = get_bigbufptr_recvrespbuf(); + uint8_t *dest = (uint8_t *)BigBuf; int c = 0; int getNext = 0; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index cc9814be..08bae44d 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1879,7 +1879,7 @@ void EM4xLogin(uint32_t Password) { void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { - uint8_t *dest = get_bigbufptr_recvrespbuf(); + uint8_t *dest = (uint8_t *)BigBuf; uint16_t bufferlength = 12000; uint32_t i = 0; diff --git a/client/cmddata.c b/client/cmddata.c index 8d74750d..9a19dca7 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -100,6 +100,7 @@ int Cmdaskdemod(const char *Cmd) * low for long periods, others just reach the peak and go * down) */ + //[marhsmellow] change == to >= for high and <= for low for fuzz if ((GraphBuffer[i] == high) && (GraphBuffer[i - 1] == c)) { GraphBuffer[i] = 1 - c; } else if ((GraphBuffer[i] == low) && (GraphBuffer[i - 1] == (1 - c))){ diff --git a/client/cmdhf.c b/client/cmdhf.c index dda0a669..0ed3f013 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -9,7 +9,7 @@ //----------------------------------------------------------------------------- #include -//#include "proxusb.h" +#include #include "proxmark3.h" #include "graph.h" #include "ui.h" @@ -34,6 +34,279 @@ int CmdHFTune(const char *Cmd) SendCommand(&c); return 0; } +// for the time being. Need better Bigbuf handling. +#define TRACE_SIZE 3000 + +#define ICLASS_CMD_ACTALL 0x0A +#define ICLASS_CMD_IDENTIFY 0x0C +#define ICLASS_CMD_READ 0x0C +#define ICLASS_CMD_SELECT 0x81 +#define ICLASS_CMD_PAGESEL 0x84 +#define ICLASS_CMD_READCHECK 0x88 +#define ICLASS_CMD_CHECK 0x05 +#define ICLASS_CMD_SOF 0x0F +#define ICLASS_CMD_HALT 0x00 + +#define iso14443_CMD_WUPA 0x52 +#define iso14443_CMD_SELECT 0x93 +#define iso14443_CMD_SELECT_2 0x95 +#define iso14443_CMD_REQ 0x26 +#define iso14443_CMD_READBLOCK 0x30 +#define iso14443_CMD_WRITEBLOCK 0xA0 +#define iso14443_CMD_INC 0xC0 +#define iso14443_CMD_DEC 0xC1 +#define iso14443_CMD_RESTORE 0xC2 +#define iso14443_CMD_TRANSFER 0xB0 +#define iso14443_CMD_HALT 0x50 +#define iso14443_CMD_RATS 0xE0 + + +void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch(cmd[0]) + { + case iso14443_CMD_WUPA: snprintf(exp,size,"WUPA"); break; + case iso14443_CMD_SELECT:{ + if(cmdsize > 2) + { + snprintf(exp,size,"SELECT_UID"); break; + }else + { + snprintf(exp,size,"SELECT_ALL"); break; + } + } + case iso14443_CMD_SELECT_2: snprintf(exp,size,"SELECT_2"); break; + case iso14443_CMD_REQ: snprintf(exp,size,"REW"); break; + case iso14443_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case iso14443_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case iso14443_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break; + case iso14443_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; + case iso14443_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; + case iso14443_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break; + case iso14443_CMD_HALT: snprintf(exp,size,"HALT"); break; + case iso14443_CMD_RATS: snprintf(exp,size,"RATS"); break; + default: snprintf(exp,size,"?"); break; + } + return; +} + +void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + + if(cmdsize > 1 && cmd[0] == ICLASS_CMD_READ) + { + snprintf(exp,size,"READ(%d)",cmd[1]); + return; + } + + switch(cmd[0]) + { + case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break; + case ICLASS_CMD_IDENTIFY: snprintf(exp,size,"IDENTIFY"); break; + case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; + case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL"); break; + case ICLASS_CMD_READCHECK: snprintf(exp,size,"READCHECK"); break; + case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; + case ICLASS_CMD_SOF: snprintf(exp,size,"SOF"); break; + case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; + default: snprintf(exp,size,"?"); break; + } + return; +} + + + +uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles) +{ + bool isResponse; + uint16_t duration, data_len,parity_len; + + uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp; + char explanation[30] = {0}; + + first_timestamp = *((uint32_t *)(trace)); + timestamp = *((uint32_t *)(trace + tracepos)); + // Break and stick with current result if buffer was not completely full + if (timestamp == 0x44444444) return TRACE_SIZE; + + tracepos += 4; + duration = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + data_len = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + + if (data_len & 0x8000) { + data_len &= 0x7fff; + isResponse = true; + } else { + isResponse = false; + } + parity_len = (data_len-1)/8 + 1; + + if (tracepos + data_len + parity_len >= TRACE_SIZE) { + return TRACE_SIZE; + } + + uint8_t *frame = trace + tracepos; + tracepos += data_len; + uint8_t *parityBytes = trace + tracepos; + tracepos += parity_len; + + //--- Draw the data column + char line[16][110]; + for (int j = 0; j < data_len; j++) { + int oddparity = 0x01; + int k; + + for (k=0 ; k<8 ; k++) { + oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); + } + + uint8_t parityBits = parityBytes[j>>3]; + + if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]); + } else { + sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]); + } + } + //--- Draw the CRC column + bool crcError = false; + + if (data_len > 2) { + uint8_t b1, b2; + if(iclass) + { + if(!isResponse && data_len == 4 ) { + // Rough guess that this is a command from the reader + // For iClass the command byte is not part of the CRC + ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2); + } + else { + // For other data.. CRC might not be applicable (UPDATE commands etc.) + ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2); + } + + if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { + crcError = true; + } + + }else{//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))) + { + crcError = true; + } + } + } + + } + char *crc = crcError ? "!crc" :" "; + + EndOfTransmissionTimestamp = timestamp + duration; + + if(!isResponse) + { + if(iclass) annotateIclass(explanation,sizeof(explanation),frame,data_len); + else annotateIso14443a(explanation,sizeof(explanation),frame,data_len); + } + + int num_lines = (data_len - 1)/16 + 1; + for (int j = 0; j < num_lines; j++) { + if (j == 0) { + PrintAndLog(" %9d | %9d | %s | %-64s| %s| %s", + (timestamp - first_timestamp), + (EndOfTransmissionTimestamp - first_timestamp), + (isResponse ? "Tag" : "Rdr"), + line[j], + (j == num_lines-1) ? crc : " ", + (j == num_lines-1) ? explanation : ""); + } else { + PrintAndLog(" | | | %-64s| %s| %s", + line[j], + (j == num_lines-1)?crc:" ", + (j == num_lines-1) ? explanation : ""); + } + } + + bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; + + if (showWaitCycles && !isResponse && next_isResponse) { + uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); + if (next_timestamp != 0x44444444) { + PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", + (EndOfTransmissionTimestamp - first_timestamp), + (next_timestamp - first_timestamp), + " ", + (next_timestamp - EndOfTransmissionTimestamp)); + } + } + return tracepos; +} + +int CmdHFList(const char *Cmd) +{ + bool showWaitCycles = false; + char type[40] = {0}; + int tlen = param_getstr(Cmd,0,type); + char param = param_getchar(Cmd, 1); + bool errors = false; + bool iclass = false; + //Validate params + if(tlen == 0 || (strcmp(type, "iclass") != 0 && strcmp(type,"14a") != 0)) + { + errors = true; + } + if(param == 'h' || (param !=0 && param != 'f')) + { + errors = true; + } + + if (errors) { + PrintAndLog("List protocol data in trace buffer."); + PrintAndLog("Usage: hf list [14a|iclass] [f]"); + PrintAndLog(" 14a - interpret data as iso14443a communications"); + PrintAndLog(" iclass - interpret data as iclass communications"); + PrintAndLog(" f - show frame delay times as well"); + PrintAndLog(""); + PrintAndLog("example: hf list 14a f"); + PrintAndLog("example: hf list iclass"); + return 0; + } + if(strcmp(type, "iclass") == 0) + { + iclass = true; + } + + if (param == 'f') { + showWaitCycles = true; + } + + + uint8_t trace[TRACE_SIZE]; + uint16_t tracepos = 0; + GetFromBigBuf(trace, TRACE_SIZE, 0); + WaitForResponse(CMD_ACK, NULL); + + PrintAndLog("Recorded Activity"); + PrintAndLog(""); + PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); + 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("-----------|-----------|-----|-----------------------------------------------------------------|-----|--------------------|"); + + while(tracepos < TRACE_SIZE) + { + tracepos = printTraceLine(tracepos, trace, iclass, showWaitCycles); + } + return 0; +} + static command_t CommandTable[] = { @@ -45,10 +318,11 @@ static command_t CommandTable[] = {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, - {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, - {"mfdes", CmdHFMFDes, 1, "{ MIFARE Desfire RFIDs... }"}, + {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, + {"mfdes", CmdHFMFDes, 1, "{ MIFARE Desfire RFIDs... }"}, {"des", CmdHFDES, 0, "{ MIFARE DESfire}"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, + {"list", CmdHFList, 1, "List protocol data in trace buffer"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf.h b/client/cmdhf.h index ff20a950..026357b5 100644 --- a/client/cmdhf.h +++ b/client/cmdhf.h @@ -13,5 +13,5 @@ int CmdHF(const char *Cmd); int CmdHFTune(const char *Cmd); - +int CmdHFList(const char *Cmd); #endif diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 5798fee6..62d95b4b 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -509,7 +509,7 @@ int CmdHF14ASnoop(const char *Cmd) { if (param_getchar(Cmd, 0) == 'h') { PrintAndLog("It get data from the field and saves it into command buffer."); - PrintAndLog("Buffer accessible from command hf 14a list."); + PrintAndLog("Buffer accessible from command hf list 14a."); PrintAndLog("Usage: hf 14a snoop [c][r]"); PrintAndLog("c - triggered by first data from card"); PrintAndLog("r - triggered by first 7-bit request from reader (REQ,WUP,...)"); @@ -694,7 +694,7 @@ static void waitCmd(uint8_t iSelect) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"list", CmdHF14AList, 0, "List ISO 14443a history"}, + {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"}, {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 76e1ea9c..25ae2a82 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -26,7 +26,7 @@ #include #include #include -//#include "proxusb.h" + #include "proxmark3.h" #include "data.h" #include "graph.h" diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 75c6e2c9..38713220 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -41,152 +41,45 @@ int xorbits_8(uint8_t val) return res & 1; } +#define ICLASS_CMD_ACTALL 0x0A +#define ICLASS_CMD_IDENTIFY 0x0C +#define ICLASS_CMD_READ 0x0C + +#define ICLASS_CMD_SELECT 0x81 +#define ICLASS_CMD_PAGESEL 0x84 +#define ICLASS_CMD_READCHECK 0x88 +#define ICLASS_CMD_CHECK 0x05 +#define ICLASS_CMD_SOF 0x0F +#define ICLASS_CMD_HALT 0x00 + + +void explain(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + + if(cmdsize > 1 && cmd[0] == ICLASS_CMD_READ) + { + snprintf(exp,size,"READ(%d)",cmd[1]); + return; + } + + switch(cmd[0]) + { + case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break; + case ICLASS_CMD_IDENTIFY: snprintf(exp,size,"IDENTIFY"); break; + case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; + case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL"); break; + case ICLASS_CMD_READCHECK: snprintf(exp,size,"READCHECK"); break; + case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; + case ICLASS_CMD_SOF: snprintf(exp,size,"SOF"); break; + case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; + default: snprintf(exp,size,"?"); break; + } + return; +} + int CmdHFiClassList(const char *Cmd) { - bool ShowWaitCycles = false; - char param = param_getchar(Cmd, 0); - - if (param != 0) { - PrintAndLog("List data in trace buffer."); - PrintAndLog("Usage: hf iclass list"); - PrintAndLog("h - help"); - PrintAndLog("sample: hf iclass list"); - return 0; - } - -// for the time being. Need better Bigbuf handling. -#define TRACE_SIZE 3000 - - uint8_t trace[TRACE_SIZE]; - GetFromBigBuf(trace, TRACE_SIZE, 0); - WaitForResponse(CMD_ACK,NULL); - - PrintAndLog("Recorded Activity"); - PrintAndLog(""); - PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); - PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC "); - PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------"); - - uint16_t tracepos = 0; - uint16_t duration; - uint16_t data_len; - uint16_t parity_len; - bool isResponse; - uint32_t timestamp; - uint32_t first_timestamp; - uint32_t EndOfTransmissionTimestamp; - - for (;;) { - - if(tracepos >= TRACE_SIZE) { - break; - } - - timestamp = *((uint32_t *)(trace + tracepos)); - if(tracepos == 0) { - first_timestamp = timestamp; - } - - // Break and stick with current result if buffer was not completely full - if (timestamp == 0x44444444) break; - - tracepos += 4; - duration = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - data_len = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - - if (data_len & 0x8000) { - data_len &= 0x7fff; - isResponse = true; - } else { - isResponse = false; - } - - parity_len = (data_len-1)/8 + 1; - - if (tracepos + data_len + parity_len >= TRACE_SIZE) { - break; - } - - uint8_t *frame = trace + tracepos; - tracepos += data_len; - uint8_t *parityBytes = trace + tracepos; - tracepos += parity_len; - - char line[16][110]; - for (int j = 0; j < data_len; j++) { - int oddparity = 0x01; - int k; - - for (k=0;k<8;k++) { - oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); - } - - uint8_t parityBits = parityBytes[j>>3]; - if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]); - } else { - sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]); - } - - } - - char *crc = ""; - if (data_len > 2) { - uint8_t b1, b2; - if(!isResponse && data_len == 4 ) { - // Rough guess that this is a command from the reader - // For iClass the command byte is not part of the CRC - ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2); - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - crc = "!crc"; - } - } - else { - // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2); - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - crc = "!crc"; - } - } - } - - EndOfTransmissionTimestamp = timestamp + duration; - - int num_lines = (data_len - 1)/16 + 1; - for (int j = 0; j < num_lines; j++) { - if (j == 0) { - PrintAndLog(" %9d | %9d | %s | %-64s| %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (isResponse ? "Tag" : "Rdr"), - line[j], - (j == num_lines-1)?crc:""); - } else { - PrintAndLog(" | | | %-64s| %s", - line[j], - (j == num_lines-1)?crc:""); - } - } - - bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; - - if (ShowWaitCycles && !isResponse && next_isResponse) { - uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); - if (next_timestamp != 0x44444444) { - PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", - (EndOfTransmissionTimestamp - first_timestamp), - (next_timestamp - first_timestamp), - " ", - (next_timestamp - EndOfTransmissionTimestamp)); - } - } - - } - + PrintAndLog("Deprecated command, use 'hf list iclass' instead"); return 0; } @@ -321,7 +214,11 @@ int CmdHFiClassReader(const char *Cmd) uint8_t * data = resp.d.asBytes; PrintAndLog("isOk:%02x", isOK); - + if( isOK == 0){ + //Aborted + PrintAndLog("Quitting..."); + return 0; + } if(isOK > 0) { PrintAndLog("CSN: %s",sprint_hex(data,8)); @@ -424,7 +321,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) UsbCommand c = {CMD_READER_ICLASS, {0}}; - c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE; + c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE| FLAG_ICLASS_READER_GET_CC; if(!fake_dummy_test) SendCommand(&c); @@ -577,13 +474,10 @@ int CmdHFiClass_iso14443A_write(const char *Cmd) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"list", CmdHFiClassList, 0, "List iClass history"}, + {"list", CmdHFiClassList, 0, "[Deprecated] List iClass history"}, {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"}, {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"}, {"reader",CmdHFiClassReader, 0, "Read an iClass tag"}, - {"replay",CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"}, - {"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"}, - {"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"}, {"replay", CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"}, {"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"}, {"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"}, diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index f32ae444..49928c9a 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1223,9 +1223,6 @@ int CmdHF14AMfELoad(const char *Cmd) return 1; } -// for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { -// for(blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) { - blockNum = 0; while(!feof(f)){ memset(buf, 0, sizeof(buf)); @@ -1243,6 +1240,7 @@ int CmdHF14AMfELoad(const char *Cmd) if(strlen(buf) && feof(f)) break; PrintAndLog("File content error. Block data must include 32 HEX symbols"); + fclose(f); return 2; } @@ -1252,6 +1250,7 @@ int CmdHF14AMfELoad(const char *Cmd) if (mfEmlSetMem(buf8, blockNum, 1)) { PrintAndLog("Cant set emul block: %3d", blockNum); + fclose(f); return 3; } blockNum++; @@ -1262,7 +1261,6 @@ int CmdHF14AMfELoad(const char *Cmd) if ((blockNum != numBlocks)) { PrintAndLog("File content error. Got %d must be %d blocks.",blockNum, numBlocks); - fclose(f); return 4; } PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename); diff --git a/client/cmdlf.c b/client/cmdlf.c index 9a9984d1..e38eee51 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -139,9 +139,7 @@ int CmdIndalaDemod(const char *Cmd) uint8_t rawbits[4096]; int rawbit = 0; int worst = 0, worstPos = 0; - - PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32); - + // 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)) { diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 6f1ada7c..24685eb9 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -26,7 +26,6 @@ #define LF_BITSSTREAM_LEN 1000 // more then 1000 bits shouldn't happend.. 8block * 4 bytes * 8bits = static int CmdHelp(const char *Cmd); - int CmdReadBlk(const char *Cmd) { int block = -1; diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 9c1c2cfd..1c9dae8b 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -30,13 +30,9 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * + * along with IClassCipher. If not, see . ****************************************************************************/ - #include "cipher.h" #include "cipherutils.h" #include diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h index 176a2976..314a560a 100644 --- a/client/loclass/cipher.h +++ b/client/loclass/cipher.h @@ -30,13 +30,9 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * + * along with IClassCipher. If not, see . ****************************************************************************/ - #ifndef CIPHER_H #define CIPHER_H #include diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index f9c62273..f82a11ce 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -30,10 +30,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * + * along with IClassCipher. If not, see . ****************************************************************************/ #include diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h index cb090f69..e2338534 100644 --- a/client/loclass/cipherutils.h +++ b/client/loclass/cipherutils.h @@ -30,13 +30,9 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * + * along with IClassCipher. If not, see . ****************************************************************************/ - #ifndef CIPHERUTILS_H #define CIPHERUTILS_H #include diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index 74c36a4d..443070c1 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -79,6 +79,7 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si FILE *fh=fopen(fileName,"wb"); if(!fh) { PrintAndLog("Failed to write to file '%s'", fileName); + free(fh); return 1; } fwrite(data, 1, datalen, fh); @@ -94,10 +95,12 @@ int loadFile(const char *fileName, void* data, size_t datalen) FILE *filehandle = fopen(fileName, "rb"); if(!filehandle) { PrintAndLog("Failed to read from file '%s'", fileName); + free(filehandle); return 1; } fread(data,datalen,1,filehandle); fclose(filehandle); + free(filehandle); return 0; } /** diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h index 02cfcef9..405c9704 100644 --- a/client/loclass/fileutils.h +++ b/client/loclass/fileutils.h @@ -64,7 +64,7 @@ int loadFile(const char *fileName, void* data, size_t datalen); * Utility function to print to console. This is used consistently within the library instead * of printf, but it actually only calls printf. The reason to have this method is to *make it simple to plug this library into proxmark, which has this function already to - * write also to a logfile. When doing so, just delete this function. + * write also to a logfile. When doing so, just point this function to use PrintAndLog * @param fmt */ void prnlog(char *fmt, ...); diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index 4c5bba2b..fccd71d8 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -18,6 +18,10 @@ * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and * Milosch Meriac in the paper "Dismantling IClass". * + * This is a reference implementation of iclass key diversification. I'm sure it can be + * optimized heavily. It is written for ease of understanding and correctness, please take it + * and tweak it and make a super fast version instead, using this for testing and verification. + * Copyright (C) 2014 Martin Holst Swende * * This is free software: you can redistribute it and/or modify @@ -30,12 +34,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * + * along with IClassCipher. If not, see . ****************************************************************************/ - /** @@ -403,7 +403,7 @@ void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]) //Calculate HASH0(DES)) uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8); - uint64_t crypted_csn_swapped = swapZvalues(crypt_csn); + //uint64_t crypted_csn_swapped = swapZvalues(crypt_csn); hash0(crypt_csn,div_key); } diff --git a/client/proxmark3.c b/client/proxmark3.c index 66571144..4b463f1d 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -47,7 +47,6 @@ void SendCommand(UsbCommand *c) { PrintAndLog("Sending bytes to proxmark failed - offline"); return; } - /** The while-loop below causes hangups at times, when the pm3 unit is unresponsive or disconnected. The main console thread is alive, but comm thread just spins here. diff --git a/common/iso15693tools.c b/common/iso15693tools.c index 964059ce..0ec5492b 100644 --- a/common/iso15693tools.c +++ b/common/iso15693tools.c @@ -66,11 +66,11 @@ char* Iso15693sprintUID(char *target,uint8_t *uid) { return target; } -unsigned short iclass_crc16(char *data_p, unsigned short length) +uint16_t iclass_crc16(char *data_p, unsigned short length) { unsigned char i; unsigned int data; - unsigned int crc = 0xffff; + uint16_t crc = 0xffff; if (length == 0) return (~crc); diff --git a/common/lfdemod.c b/common/lfdemod.c index 873b6305..eb5a4d95 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -621,8 +621,8 @@ int IOdemodFSK(uint8_t *dest, size_t size) testMax = dest[idx]; } - //if not just noise - if (testMax < 170) return -2; + //if not, just noise + if (testMax < 20) return -2; // FSK demodulator size = fskdemod(dest, size, 64, 1, 10, 8); // RF/64 and invert diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 111f7ec7..ecdf8ac1 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -188,6 +188,7 @@ typedef struct { //Iclass reader flags #define FLAG_ICLASS_READER_ONLY_ONCE 0x01 +#define FLAG_ICLASS_READER_GET_CC 0x02 // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ From 0452ec6c906c2389c761c1dd6b0a4b5f67defe32 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 5 Jan 2015 15:12:48 +0100 Subject: [PATCH 73/78] FIX: downloaded a fresh clone from my fork, and took away the build-errors. --- client/cmdhfepa.c | 2 +- client/cmdlfawid26.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index ecdb311c..afcdb0fa 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -54,7 +54,7 @@ int CmdHFEPACollectPACENonces(const char *Cmd) size_t nonce_length = resp.arg[1]; char *nonce = (char *) malloc(2 * nonce_length + 1); for(int j = 0; j < nonce_length; j++) { - snprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]); + sprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]); } // print nonce PrintAndLog("Length: %d, Nonce: %s", nonce_length, nonce); diff --git a/client/cmdlfawid26.c b/client/cmdlfawid26.c index 71f227f2..48e599db 100644 --- a/client/cmdlfawid26.c +++ b/client/cmdlfawid26.c @@ -57,11 +57,12 @@ int CmdClone(const char *Cmd) // 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]; - int site; - int id; + //uint8_t i, tmp[96], tmp1[7]; + //uint8_t tmp[96] = {0x00}; + //int site; + //int id; - if(!hextobinarray(tmp, awid26)) + //if(!hextobinarray(tmp, awid26)) return false; // // data is in blocks of 4 bits - every 4th bit is parity, except the first From 052bbe08d0c1b6a66eb88cd1c0b04a83a372a8a4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 5 Jan 2015 16:31:19 +0100 Subject: [PATCH 74/78] TEST of creating branch simular to PM3master. --- README.txt | 129 +- armsrc/LCD.c | 2 +- armsrc/Makefile | 16 +- armsrc/aes.c | 1168 ----------- armsrc/aes.h | 30 - armsrc/appmain.c | 87 +- armsrc/apps.h | 96 +- armsrc/crapto1.c | 6 +- armsrc/des.c | 383 ---- armsrc/des.h | 107 - armsrc/desfire_crypto.c | 642 ------ armsrc/desfire_crypto.h | 14 - armsrc/desfire_key.c | 155 -- armsrc/desfire_key.h | 17 - armsrc/epa.c | 17 +- armsrc/fpgaloader.c | 3 +- armsrc/hitag2.c | 14 +- armsrc/iclass.c | 134 +- armsrc/iso14443.c | 4 +- armsrc/iso14443a.c | 402 ++-- armsrc/iso14443a.h | 10 +- armsrc/iso15693.c | 64 +- armsrc/legicrf.c | 6 +- armsrc/lfops.c | 3054 ++++++++++++++-------------- armsrc/mifarecmd.c | 223 +- armsrc/mifarecmd.h | 7 +- armsrc/mifaredesfire.c | 521 ----- armsrc/mifaredesfire.h | 15 - armsrc/mifaresniff.h | 6 +- armsrc/mifareutil.c | 258 +-- armsrc/mifareutil.h | 14 +- armsrc/start.c | 2 +- armsrc/string.c | 5 - armsrc/string.h | 8 +- armsrc/util.c | 42 +- armsrc/util.h | 6 +- client/Makefile | 27 +- client/cmddata.c | 1086 +++++----- client/cmddata.h | 3 +- client/cmdhf.c | 10 +- client/cmdhf14a.c | 199 +- client/cmdhf14b.c | 15 +- client/cmdhf15.c | 30 +- client/cmdhfdes.c | 69 - client/cmdhfdes.h | 27 - client/cmdhfepa.c | 2 +- client/cmdhficlass.c | 157 +- client/cmdhflegic.c | 21 +- client/cmdhfmf.c | 557 ++--- client/cmdhfmf.h | 6 +- client/cmdhfmfdes.c | 685 ------- client/cmdhfmfdes.h | 75 - client/cmdhfmfdesfire.c | 250 --- client/cmdhfmfdesfire.h | 5 - client/cmdhfmfu.c | 1157 ----------- client/cmdhfmfu.h | 16 - client/cmdhw.c | 5 +- client/cmdlf.c | 717 +++---- client/cmdlfawid26.c | 208 -- client/cmdlfawid26.h | 18 - client/cmdlfem4x.c | 469 +---- client/cmdlfem4x.h | 1 - client/cmdlfhid.c | 10 +- client/cmdlfhitag.c | 72 +- client/cmdlfio.c | 20 +- client/cmdlft55xx.c | 435 +--- client/cmdlft55xx.h | 9 +- client/cmdmain.c | 87 +- client/cmdmain.h | 2 +- client/data.h | 3 - client/flash.c | 14 +- client/flasher.c | 2 +- client/graph.c | 233 ++- client/graph.h | 11 +- client/loclass/cipher.c | 40 +- client/loclass/cipher.h | 14 +- client/loclass/cipherutils.c | 14 +- client/loclass/cipherutils.h | 14 +- client/loclass/elite_crack.c | 56 +- client/loclass/elite_crack.h | 39 - client/loclass/fileutils.c | 80 +- client/loclass/fileutils.h | 48 +- client/loclass/hash1_brute.c | 92 - client/loclass/hash1_brute.h | 5 - client/loclass/ikeys.c | 16 +- client/loclass/ikeys.h | 38 - client/loclass/main.c | 33 +- client/lualibs/commands.lua | 47 +- client/lualibs/default_toys.lua | 63 - client/lualibs/html_dumplib.lua | 16 +- client/lualibs/htmlskel.lua | 1 - client/lualibs/md5.lua | 384 ---- client/lualibs/mf_default_keys.lua | 20 +- client/lualibs/read14a.lua | 1 - client/lualibs/utils.lua | 173 +- client/mifarehost.c | 12 +- client/nonce2key/crapto1.c | 9 +- client/proxguiqt.cpp | 2 +- client/proxmark3.c | 2 +- client/proxmark3.h | 2 +- client/scripting.c | 56 +- client/scripts/formatMifare.lua | 10 +- client/scripts/mifare_autopwn.lua | 2 - client/scripts/tnp3dump.lua | 272 --- client/scripts/tnp3sim.lua | 355 ---- client/ui.c | 405 +--- client/ui.h | 13 - client/util.c | 151 +- client/util.h | 14 - common/Makefile.common | 6 +- common/cmd.c | 4 +- common/cmd.h | 4 +- common/crc.h | 48 - common/crc16.c | 23 - common/crc16.h | 5 +- common/crc32.c | 35 - common/crc32.h | 15 - common/desfire.h | 179 -- common/iso14443crc.c | 2 +- common/iso14443crc.h | 2 +- common/iso15693tools.c | 2 +- common/legic_prng.c | 2 +- common/lfdemod.c | 1253 ++++++------ common/usb_cdc.c | 68 +- common/usb_cdc.h | 2 +- cp2tau | 4 - iceman.txt | 0 include/at91sam7s512.h | 2 +- include/crc.h.old | 48 - include/mifare.h | 2 +- include/proxmark3.h | 3 +- include/usb_cmd.h | 11 +- tools/mkversion.pl | 2 +- 133 files changed, 4428 insertions(+), 14173 deletions(-) delete mode 100644 armsrc/aes.c delete mode 100644 armsrc/aes.h delete mode 100644 armsrc/des.c delete mode 100644 armsrc/des.h delete mode 100644 armsrc/desfire_crypto.c delete mode 100644 armsrc/desfire_crypto.h delete mode 100644 armsrc/desfire_key.c delete mode 100644 armsrc/desfire_key.h delete mode 100644 armsrc/mifaredesfire.c delete mode 100644 armsrc/mifaredesfire.h delete mode 100644 client/cmdhfdes.c delete mode 100644 client/cmdhfdes.h delete mode 100644 client/cmdhfmfdes.c delete mode 100644 client/cmdhfmfdes.h delete mode 100644 client/cmdhfmfdesfire.c delete mode 100644 client/cmdhfmfdesfire.h delete mode 100644 client/cmdhfmfu.c delete mode 100644 client/cmdhfmfu.h delete mode 100644 client/cmdlfawid26.c delete mode 100644 client/cmdlfawid26.h delete mode 100644 client/loclass/hash1_brute.c delete mode 100644 client/loclass/hash1_brute.h delete mode 100644 client/lualibs/default_toys.lua delete mode 100644 client/lualibs/md5.lua delete mode 100644 client/scripts/tnp3dump.lua delete mode 100644 client/scripts/tnp3sim.lua delete mode 100644 common/crc.h delete mode 100644 common/crc32.c delete mode 100644 common/crc32.h delete mode 100644 common/desfire.h delete mode 100644 cp2tau delete mode 100644 iceman.txt delete mode 100644 include/crc.h.old diff --git a/README.txt b/README.txt index 05829dac..cb2c7f3c 100644 --- a/README.txt +++ b/README.txt @@ -1,68 +1,87 @@ -The iceman fork. - NOTICE: +(2014-03-26) +This is now the official Proxmark repository! -The official Proxmark repository is found here: https://github.com/Proxmark/proxmark3 +INTRODUCTION: +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. -NEWS: +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. -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 +RESOURCES: - * 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. - -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: - -I do tend to rename and move stuff around, the official PM3-GUI from Gaucho will not work so well. *sorry* - - + * 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: -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. +The tools required to build or run the project will vary depending on +your operating system. Please refer to the Wiki for details. -Common errors linux/macOS finds -Error: - * loclass/fileutils.c:15:2: warning: implicit declaration of function ‘_stat’ [-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 - + * https://github.com/Proxmark/proxmark3/wiki -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. +OBTAINING HARDWARE: + +The Proxmark 3 is available for purcahse (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: -January 2015, Sweden -iceman at host iuse.se \ No newline at end of file +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 diff --git a/armsrc/LCD.c b/armsrc/LCD.c index 87be5e3a..65d64ac9 100644 --- a/armsrc/LCD.c +++ b/armsrc/LCD.c @@ -6,7 +6,7 @@ // LCD code //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "LCD.h" #include "fonts.h" diff --git a/armsrc/Makefile b/armsrc/Makefile index 69e4738a..f87cf0a1 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -10,16 +10,15 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line #in the next section to remove that particular feature from compilation -APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -fno-strict-aliasing +APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG #-DWITH_LCD #SRC_LCD = fonts.c LCD.c SRC_LF = lfops.c hitag2.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 desfire_key.c desfire_crypto.c mifaredesfire.c -SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c +SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c +SRC_ISO14443b = iso14443.c +SRC_CRAPTO1 = crapto1.c crypto1.c THUMBSRC = start.c \ $(SRC_LCD) \ @@ -35,14 +34,15 @@ THUMBSRC = start.c \ # These are to be compiled in ARM mode ARMSRC = fpgaloader.c \ legicrf.c \ + iso14443crc.c \ + crc16.c \ lfdemod.c \ $(SRC_ISO14443a) \ $(SRC_ISO14443b) \ $(SRC_CRAPTO1) \ - $(SRC_CRC) \ legic_prng.c \ - iclass.c - + iclass.c \ + crc.c # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS += -I. diff --git a/armsrc/aes.c b/armsrc/aes.c deleted file mode 100644 index 3df006bb..00000000 --- a/armsrc/aes.c +++ /dev/null @@ -1,1168 +0,0 @@ -#include "stdio.h" -#include "aes.h" - -static const unsigned int Te0[256] = { - 0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL, - 0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL, - 0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL, - 0xe7fefe19UL, 0xb5d7d762UL, 0x4dababe6UL, 0xec76769aUL, - 0x8fcaca45UL, 0x1f82829dUL, 0x89c9c940UL, 0xfa7d7d87UL, - 0xeffafa15UL, 0xb25959ebUL, 0x8e4747c9UL, 0xfbf0f00bUL, - 0x41adadecUL, 0xb3d4d467UL, 0x5fa2a2fdUL, 0x45afafeaUL, - 0x239c9cbfUL, 0x53a4a4f7UL, 0xe4727296UL, 0x9bc0c05bUL, - 0x75b7b7c2UL, 0xe1fdfd1cUL, 0x3d9393aeUL, 0x4c26266aUL, - 0x6c36365aUL, 0x7e3f3f41UL, 0xf5f7f702UL, 0x83cccc4fUL, - 0x6834345cUL, 0x51a5a5f4UL, 0xd1e5e534UL, 0xf9f1f108UL, - 0xe2717193UL, 0xabd8d873UL, 0x62313153UL, 0x2a15153fUL, - 0x0804040cUL, 0x95c7c752UL, 0x46232365UL, 0x9dc3c35eUL, - 0x30181828UL, 0x379696a1UL, 0x0a05050fUL, 0x2f9a9ab5UL, - 0x0e070709UL, 0x24121236UL, 0x1b80809bUL, 0xdfe2e23dUL, - 0xcdebeb26UL, 0x4e272769UL, 0x7fb2b2cdUL, 0xea75759fUL, - 0x1209091bUL, 0x1d83839eUL, 0x582c2c74UL, 0x341a1a2eUL, - 0x361b1b2dUL, 0xdc6e6eb2UL, 0xb45a5aeeUL, 0x5ba0a0fbUL, - 0xa45252f6UL, 0x763b3b4dUL, 0xb7d6d661UL, 0x7db3b3ceUL, - 0x5229297bUL, 0xdde3e33eUL, 0x5e2f2f71UL, 0x13848497UL, - 0xa65353f5UL, 0xb9d1d168UL, 0x00000000UL, 0xc1eded2cUL, - 0x40202060UL, 0xe3fcfc1fUL, 0x79b1b1c8UL, 0xb65b5bedUL, - 0xd46a6abeUL, 0x8dcbcb46UL, 0x67bebed9UL, 0x7239394bUL, - 0x944a4adeUL, 0x984c4cd4UL, 0xb05858e8UL, 0x85cfcf4aUL, - 0xbbd0d06bUL, 0xc5efef2aUL, 0x4faaaae5UL, 0xedfbfb16UL, - 0x864343c5UL, 0x9a4d4dd7UL, 0x66333355UL, 0x11858594UL, - 0x8a4545cfUL, 0xe9f9f910UL, 0x04020206UL, 0xfe7f7f81UL, - 0xa05050f0UL, 0x783c3c44UL, 0x259f9fbaUL, 0x4ba8a8e3UL, - 0xa25151f3UL, 0x5da3a3feUL, 0x804040c0UL, 0x058f8f8aUL, - 0x3f9292adUL, 0x219d9dbcUL, 0x70383848UL, 0xf1f5f504UL, - 0x63bcbcdfUL, 0x77b6b6c1UL, 0xafdada75UL, 0x42212163UL, - 0x20101030UL, 0xe5ffff1aUL, 0xfdf3f30eUL, 0xbfd2d26dUL, - 0x81cdcd4cUL, 0x180c0c14UL, 0x26131335UL, 0xc3ecec2fUL, - 0xbe5f5fe1UL, 0x359797a2UL, 0x884444ccUL, 0x2e171739UL, - 0x93c4c457UL, 0x55a7a7f2UL, 0xfc7e7e82UL, 0x7a3d3d47UL, - 0xc86464acUL, 0xba5d5de7UL, 0x3219192bUL, 0xe6737395UL, - 0xc06060a0UL, 0x19818198UL, 0x9e4f4fd1UL, 0xa3dcdc7fUL, - 0x44222266UL, 0x542a2a7eUL, 0x3b9090abUL, 0x0b888883UL, - 0x8c4646caUL, 0xc7eeee29UL, 0x6bb8b8d3UL, 0x2814143cUL, - 0xa7dede79UL, 0xbc5e5ee2UL, 0x160b0b1dUL, 0xaddbdb76UL, - 0xdbe0e03bUL, 0x64323256UL, 0x743a3a4eUL, 0x140a0a1eUL, - 0x924949dbUL, 0x0c06060aUL, 0x4824246cUL, 0xb85c5ce4UL, - 0x9fc2c25dUL, 0xbdd3d36eUL, 0x43acacefUL, 0xc46262a6UL, - 0x399191a8UL, 0x319595a4UL, 0xd3e4e437UL, 0xf279798bUL, - 0xd5e7e732UL, 0x8bc8c843UL, 0x6e373759UL, 0xda6d6db7UL, - 0x018d8d8cUL, 0xb1d5d564UL, 0x9c4e4ed2UL, 0x49a9a9e0UL, - 0xd86c6cb4UL, 0xac5656faUL, 0xf3f4f407UL, 0xcfeaea25UL, - 0xca6565afUL, 0xf47a7a8eUL, 0x47aeaee9UL, 0x10080818UL, - 0x6fbabad5UL, 0xf0787888UL, 0x4a25256fUL, 0x5c2e2e72UL, - 0x381c1c24UL, 0x57a6a6f1UL, 0x73b4b4c7UL, 0x97c6c651UL, - 0xcbe8e823UL, 0xa1dddd7cUL, 0xe874749cUL, 0x3e1f1f21UL, - 0x964b4bddUL, 0x61bdbddcUL, 0x0d8b8b86UL, 0x0f8a8a85UL, - 0xe0707090UL, 0x7c3e3e42UL, 0x71b5b5c4UL, 0xcc6666aaUL, - 0x904848d8UL, 0x06030305UL, 0xf7f6f601UL, 0x1c0e0e12UL, - 0xc26161a3UL, 0x6a35355fUL, 0xae5757f9UL, 0x69b9b9d0UL, - 0x17868691UL, 0x99c1c158UL, 0x3a1d1d27UL, 0x279e9eb9UL, - 0xd9e1e138UL, 0xebf8f813UL, 0x2b9898b3UL, 0x22111133UL, - 0xd26969bbUL, 0xa9d9d970UL, 0x078e8e89UL, 0x339494a7UL, - 0x2d9b9bb6UL, 0x3c1e1e22UL, 0x15878792UL, 0xc9e9e920UL, - 0x87cece49UL, 0xaa5555ffUL, 0x50282878UL, 0xa5dfdf7aUL, - 0x038c8c8fUL, 0x59a1a1f8UL, 0x09898980UL, 0x1a0d0d17UL, - 0x65bfbfdaUL, 0xd7e6e631UL, 0x844242c6UL, 0xd06868b8UL, - 0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL, - 0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL, -}; -static const unsigned int Te1[256] = { - 0xa5c66363UL, 0x84f87c7cUL, 0x99ee7777UL, 0x8df67b7bUL, - 0x0dfff2f2UL, 0xbdd66b6bUL, 0xb1de6f6fUL, 0x5491c5c5UL, - 0x50603030UL, 0x03020101UL, 0xa9ce6767UL, 0x7d562b2bUL, - 0x19e7fefeUL, 0x62b5d7d7UL, 0xe64dababUL, 0x9aec7676UL, - 0x458fcacaUL, 0x9d1f8282UL, 0x4089c9c9UL, 0x87fa7d7dUL, - 0x15effafaUL, 0xebb25959UL, 0xc98e4747UL, 0x0bfbf0f0UL, - 0xec41adadUL, 0x67b3d4d4UL, 0xfd5fa2a2UL, 0xea45afafUL, - 0xbf239c9cUL, 0xf753a4a4UL, 0x96e47272UL, 0x5b9bc0c0UL, - 0xc275b7b7UL, 0x1ce1fdfdUL, 0xae3d9393UL, 0x6a4c2626UL, - 0x5a6c3636UL, 0x417e3f3fUL, 0x02f5f7f7UL, 0x4f83ccccUL, - 0x5c683434UL, 0xf451a5a5UL, 0x34d1e5e5UL, 0x08f9f1f1UL, - 0x93e27171UL, 0x73abd8d8UL, 0x53623131UL, 0x3f2a1515UL, - 0x0c080404UL, 0x5295c7c7UL, 0x65462323UL, 0x5e9dc3c3UL, - 0x28301818UL, 0xa1379696UL, 0x0f0a0505UL, 0xb52f9a9aUL, - 0x090e0707UL, 0x36241212UL, 0x9b1b8080UL, 0x3ddfe2e2UL, - 0x26cdebebUL, 0x694e2727UL, 0xcd7fb2b2UL, 0x9fea7575UL, - 0x1b120909UL, 0x9e1d8383UL, 0x74582c2cUL, 0x2e341a1aUL, - 0x2d361b1bUL, 0xb2dc6e6eUL, 0xeeb45a5aUL, 0xfb5ba0a0UL, - 0xf6a45252UL, 0x4d763b3bUL, 0x61b7d6d6UL, 0xce7db3b3UL, - 0x7b522929UL, 0x3edde3e3UL, 0x715e2f2fUL, 0x97138484UL, - 0xf5a65353UL, 0x68b9d1d1UL, 0x00000000UL, 0x2cc1ededUL, - 0x60402020UL, 0x1fe3fcfcUL, 0xc879b1b1UL, 0xedb65b5bUL, - 0xbed46a6aUL, 0x468dcbcbUL, 0xd967bebeUL, 0x4b723939UL, - 0xde944a4aUL, 0xd4984c4cUL, 0xe8b05858UL, 0x4a85cfcfUL, - 0x6bbbd0d0UL, 0x2ac5efefUL, 0xe54faaaaUL, 0x16edfbfbUL, - 0xc5864343UL, 0xd79a4d4dUL, 0x55663333UL, 0x94118585UL, - 0xcf8a4545UL, 0x10e9f9f9UL, 0x06040202UL, 0x81fe7f7fUL, - 0xf0a05050UL, 0x44783c3cUL, 0xba259f9fUL, 0xe34ba8a8UL, - 0xf3a25151UL, 0xfe5da3a3UL, 0xc0804040UL, 0x8a058f8fUL, - 0xad3f9292UL, 0xbc219d9dUL, 0x48703838UL, 0x04f1f5f5UL, - 0xdf63bcbcUL, 0xc177b6b6UL, 0x75afdadaUL, 0x63422121UL, - 0x30201010UL, 0x1ae5ffffUL, 0x0efdf3f3UL, 0x6dbfd2d2UL, - 0x4c81cdcdUL, 0x14180c0cUL, 0x35261313UL, 0x2fc3ececUL, - 0xe1be5f5fUL, 0xa2359797UL, 0xcc884444UL, 0x392e1717UL, - 0x5793c4c4UL, 0xf255a7a7UL, 0x82fc7e7eUL, 0x477a3d3dUL, - 0xacc86464UL, 0xe7ba5d5dUL, 0x2b321919UL, 0x95e67373UL, - 0xa0c06060UL, 0x98198181UL, 0xd19e4f4fUL, 0x7fa3dcdcUL, - 0x66442222UL, 0x7e542a2aUL, 0xab3b9090UL, 0x830b8888UL, - 0xca8c4646UL, 0x29c7eeeeUL, 0xd36bb8b8UL, 0x3c281414UL, - 0x79a7dedeUL, 0xe2bc5e5eUL, 0x1d160b0bUL, 0x76addbdbUL, - 0x3bdbe0e0UL, 0x56643232UL, 0x4e743a3aUL, 0x1e140a0aUL, - 0xdb924949UL, 0x0a0c0606UL, 0x6c482424UL, 0xe4b85c5cUL, - 0x5d9fc2c2UL, 0x6ebdd3d3UL, 0xef43acacUL, 0xa6c46262UL, - 0xa8399191UL, 0xa4319595UL, 0x37d3e4e4UL, 0x8bf27979UL, - 0x32d5e7e7UL, 0x438bc8c8UL, 0x596e3737UL, 0xb7da6d6dUL, - 0x8c018d8dUL, 0x64b1d5d5UL, 0xd29c4e4eUL, 0xe049a9a9UL, - 0xb4d86c6cUL, 0xfaac5656UL, 0x07f3f4f4UL, 0x25cfeaeaUL, - 0xafca6565UL, 0x8ef47a7aUL, 0xe947aeaeUL, 0x18100808UL, - 0xd56fbabaUL, 0x88f07878UL, 0x6f4a2525UL, 0x725c2e2eUL, - 0x24381c1cUL, 0xf157a6a6UL, 0xc773b4b4UL, 0x5197c6c6UL, - 0x23cbe8e8UL, 0x7ca1ddddUL, 0x9ce87474UL, 0x213e1f1fUL, - 0xdd964b4bUL, 0xdc61bdbdUL, 0x860d8b8bUL, 0x850f8a8aUL, - 0x90e07070UL, 0x427c3e3eUL, 0xc471b5b5UL, 0xaacc6666UL, - 0xd8904848UL, 0x05060303UL, 0x01f7f6f6UL, 0x121c0e0eUL, - 0xa3c26161UL, 0x5f6a3535UL, 0xf9ae5757UL, 0xd069b9b9UL, - 0x91178686UL, 0x5899c1c1UL, 0x273a1d1dUL, 0xb9279e9eUL, - 0x38d9e1e1UL, 0x13ebf8f8UL, 0xb32b9898UL, 0x33221111UL, - 0xbbd26969UL, 0x70a9d9d9UL, 0x89078e8eUL, 0xa7339494UL, - 0xb62d9b9bUL, 0x223c1e1eUL, 0x92158787UL, 0x20c9e9e9UL, - 0x4987ceceUL, 0xffaa5555UL, 0x78502828UL, 0x7aa5dfdfUL, - 0x8f038c8cUL, 0xf859a1a1UL, 0x80098989UL, 0x171a0d0dUL, - 0xda65bfbfUL, 0x31d7e6e6UL, 0xc6844242UL, 0xb8d06868UL, - 0xc3824141UL, 0xb0299999UL, 0x775a2d2dUL, 0x111e0f0fUL, - 0xcb7bb0b0UL, 0xfca85454UL, 0xd66dbbbbUL, 0x3a2c1616UL, -}; -static const unsigned int Te2[256] = { - 0x63a5c663UL, 0x7c84f87cUL, 0x7799ee77UL, 0x7b8df67bUL, - 0xf20dfff2UL, 0x6bbdd66bUL, 0x6fb1de6fUL, 0xc55491c5UL, - 0x30506030UL, 0x01030201UL, 0x67a9ce67UL, 0x2b7d562bUL, - 0xfe19e7feUL, 0xd762b5d7UL, 0xabe64dabUL, 0x769aec76UL, - 0xca458fcaUL, 0x829d1f82UL, 0xc94089c9UL, 0x7d87fa7dUL, - 0xfa15effaUL, 0x59ebb259UL, 0x47c98e47UL, 0xf00bfbf0UL, - 0xadec41adUL, 0xd467b3d4UL, 0xa2fd5fa2UL, 0xafea45afUL, - 0x9cbf239cUL, 0xa4f753a4UL, 0x7296e472UL, 0xc05b9bc0UL, - 0xb7c275b7UL, 0xfd1ce1fdUL, 0x93ae3d93UL, 0x266a4c26UL, - 0x365a6c36UL, 0x3f417e3fUL, 0xf702f5f7UL, 0xcc4f83ccUL, - 0x345c6834UL, 0xa5f451a5UL, 0xe534d1e5UL, 0xf108f9f1UL, - 0x7193e271UL, 0xd873abd8UL, 0x31536231UL, 0x153f2a15UL, - 0x040c0804UL, 0xc75295c7UL, 0x23654623UL, 0xc35e9dc3UL, - 0x18283018UL, 0x96a13796UL, 0x050f0a05UL, 0x9ab52f9aUL, - 0x07090e07UL, 0x12362412UL, 0x809b1b80UL, 0xe23ddfe2UL, - 0xeb26cdebUL, 0x27694e27UL, 0xb2cd7fb2UL, 0x759fea75UL, - 0x091b1209UL, 0x839e1d83UL, 0x2c74582cUL, 0x1a2e341aUL, - 0x1b2d361bUL, 0x6eb2dc6eUL, 0x5aeeb45aUL, 0xa0fb5ba0UL, - 0x52f6a452UL, 0x3b4d763bUL, 0xd661b7d6UL, 0xb3ce7db3UL, - 0x297b5229UL, 0xe33edde3UL, 0x2f715e2fUL, 0x84971384UL, - 0x53f5a653UL, 0xd168b9d1UL, 0x00000000UL, 0xed2cc1edUL, - 0x20604020UL, 0xfc1fe3fcUL, 0xb1c879b1UL, 0x5bedb65bUL, - 0x6abed46aUL, 0xcb468dcbUL, 0xbed967beUL, 0x394b7239UL, - 0x4ade944aUL, 0x4cd4984cUL, 0x58e8b058UL, 0xcf4a85cfUL, - 0xd06bbbd0UL, 0xef2ac5efUL, 0xaae54faaUL, 0xfb16edfbUL, - 0x43c58643UL, 0x4dd79a4dUL, 0x33556633UL, 0x85941185UL, - 0x45cf8a45UL, 0xf910e9f9UL, 0x02060402UL, 0x7f81fe7fUL, - 0x50f0a050UL, 0x3c44783cUL, 0x9fba259fUL, 0xa8e34ba8UL, - 0x51f3a251UL, 0xa3fe5da3UL, 0x40c08040UL, 0x8f8a058fUL, - 0x92ad3f92UL, 0x9dbc219dUL, 0x38487038UL, 0xf504f1f5UL, - 0xbcdf63bcUL, 0xb6c177b6UL, 0xda75afdaUL, 0x21634221UL, - 0x10302010UL, 0xff1ae5ffUL, 0xf30efdf3UL, 0xd26dbfd2UL, - 0xcd4c81cdUL, 0x0c14180cUL, 0x13352613UL, 0xec2fc3ecUL, - 0x5fe1be5fUL, 0x97a23597UL, 0x44cc8844UL, 0x17392e17UL, - 0xc45793c4UL, 0xa7f255a7UL, 0x7e82fc7eUL, 0x3d477a3dUL, - 0x64acc864UL, 0x5de7ba5dUL, 0x192b3219UL, 0x7395e673UL, - 0x60a0c060UL, 0x81981981UL, 0x4fd19e4fUL, 0xdc7fa3dcUL, - 0x22664422UL, 0x2a7e542aUL, 0x90ab3b90UL, 0x88830b88UL, - 0x46ca8c46UL, 0xee29c7eeUL, 0xb8d36bb8UL, 0x143c2814UL, - 0xde79a7deUL, 0x5ee2bc5eUL, 0x0b1d160bUL, 0xdb76addbUL, - 0xe03bdbe0UL, 0x32566432UL, 0x3a4e743aUL, 0x0a1e140aUL, - 0x49db9249UL, 0x060a0c06UL, 0x246c4824UL, 0x5ce4b85cUL, - 0xc25d9fc2UL, 0xd36ebdd3UL, 0xacef43acUL, 0x62a6c462UL, - 0x91a83991UL, 0x95a43195UL, 0xe437d3e4UL, 0x798bf279UL, - 0xe732d5e7UL, 0xc8438bc8UL, 0x37596e37UL, 0x6db7da6dUL, - 0x8d8c018dUL, 0xd564b1d5UL, 0x4ed29c4eUL, 0xa9e049a9UL, - 0x6cb4d86cUL, 0x56faac56UL, 0xf407f3f4UL, 0xea25cfeaUL, - 0x65afca65UL, 0x7a8ef47aUL, 0xaee947aeUL, 0x08181008UL, - 0xbad56fbaUL, 0x7888f078UL, 0x256f4a25UL, 0x2e725c2eUL, - 0x1c24381cUL, 0xa6f157a6UL, 0xb4c773b4UL, 0xc65197c6UL, - 0xe823cbe8UL, 0xdd7ca1ddUL, 0x749ce874UL, 0x1f213e1fUL, - 0x4bdd964bUL, 0xbddc61bdUL, 0x8b860d8bUL, 0x8a850f8aUL, - 0x7090e070UL, 0x3e427c3eUL, 0xb5c471b5UL, 0x66aacc66UL, - 0x48d89048UL, 0x03050603UL, 0xf601f7f6UL, 0x0e121c0eUL, - 0x61a3c261UL, 0x355f6a35UL, 0x57f9ae57UL, 0xb9d069b9UL, - 0x86911786UL, 0xc15899c1UL, 0x1d273a1dUL, 0x9eb9279eUL, - 0xe138d9e1UL, 0xf813ebf8UL, 0x98b32b98UL, 0x11332211UL, - 0x69bbd269UL, 0xd970a9d9UL, 0x8e89078eUL, 0x94a73394UL, - 0x9bb62d9bUL, 0x1e223c1eUL, 0x87921587UL, 0xe920c9e9UL, - 0xce4987ceUL, 0x55ffaa55UL, 0x28785028UL, 0xdf7aa5dfUL, - 0x8c8f038cUL, 0xa1f859a1UL, 0x89800989UL, 0x0d171a0dUL, - 0xbfda65bfUL, 0xe631d7e6UL, 0x42c68442UL, 0x68b8d068UL, - 0x41c38241UL, 0x99b02999UL, 0x2d775a2dUL, 0x0f111e0fUL, - 0xb0cb7bb0UL, 0x54fca854UL, 0xbbd66dbbUL, 0x163a2c16UL, -}; -static const unsigned int Te3[256] = { - 0x6363a5c6UL, 0x7c7c84f8UL, 0x777799eeUL, 0x7b7b8df6UL, - 0xf2f20dffUL, 0x6b6bbdd6UL, 0x6f6fb1deUL, 0xc5c55491UL, - 0x30305060UL, 0x01010302UL, 0x6767a9ceUL, 0x2b2b7d56UL, - 0xfefe19e7UL, 0xd7d762b5UL, 0xababe64dUL, 0x76769aecUL, - 0xcaca458fUL, 0x82829d1fUL, 0xc9c94089UL, 0x7d7d87faUL, - 0xfafa15efUL, 0x5959ebb2UL, 0x4747c98eUL, 0xf0f00bfbUL, - 0xadadec41UL, 0xd4d467b3UL, 0xa2a2fd5fUL, 0xafafea45UL, - 0x9c9cbf23UL, 0xa4a4f753UL, 0x727296e4UL, 0xc0c05b9bUL, - 0xb7b7c275UL, 0xfdfd1ce1UL, 0x9393ae3dUL, 0x26266a4cUL, - 0x36365a6cUL, 0x3f3f417eUL, 0xf7f702f5UL, 0xcccc4f83UL, - 0x34345c68UL, 0xa5a5f451UL, 0xe5e534d1UL, 0xf1f108f9UL, - 0x717193e2UL, 0xd8d873abUL, 0x31315362UL, 0x15153f2aUL, - 0x04040c08UL, 0xc7c75295UL, 0x23236546UL, 0xc3c35e9dUL, - 0x18182830UL, 0x9696a137UL, 0x05050f0aUL, 0x9a9ab52fUL, - 0x0707090eUL, 0x12123624UL, 0x80809b1bUL, 0xe2e23ddfUL, - 0xebeb26cdUL, 0x2727694eUL, 0xb2b2cd7fUL, 0x75759feaUL, - 0x09091b12UL, 0x83839e1dUL, 0x2c2c7458UL, 0x1a1a2e34UL, - 0x1b1b2d36UL, 0x6e6eb2dcUL, 0x5a5aeeb4UL, 0xa0a0fb5bUL, - 0x5252f6a4UL, 0x3b3b4d76UL, 0xd6d661b7UL, 0xb3b3ce7dUL, - 0x29297b52UL, 0xe3e33eddUL, 0x2f2f715eUL, 0x84849713UL, - 0x5353f5a6UL, 0xd1d168b9UL, 0x00000000UL, 0xeded2cc1UL, - 0x20206040UL, 0xfcfc1fe3UL, 0xb1b1c879UL, 0x5b5bedb6UL, - 0x6a6abed4UL, 0xcbcb468dUL, 0xbebed967UL, 0x39394b72UL, - 0x4a4ade94UL, 0x4c4cd498UL, 0x5858e8b0UL, 0xcfcf4a85UL, - 0xd0d06bbbUL, 0xefef2ac5UL, 0xaaaae54fUL, 0xfbfb16edUL, - 0x4343c586UL, 0x4d4dd79aUL, 0x33335566UL, 0x85859411UL, - 0x4545cf8aUL, 0xf9f910e9UL, 0x02020604UL, 0x7f7f81feUL, - 0x5050f0a0UL, 0x3c3c4478UL, 0x9f9fba25UL, 0xa8a8e34bUL, - 0x5151f3a2UL, 0xa3a3fe5dUL, 0x4040c080UL, 0x8f8f8a05UL, - 0x9292ad3fUL, 0x9d9dbc21UL, 0x38384870UL, 0xf5f504f1UL, - 0xbcbcdf63UL, 0xb6b6c177UL, 0xdada75afUL, 0x21216342UL, - 0x10103020UL, 0xffff1ae5UL, 0xf3f30efdUL, 0xd2d26dbfUL, - 0xcdcd4c81UL, 0x0c0c1418UL, 0x13133526UL, 0xecec2fc3UL, - 0x5f5fe1beUL, 0x9797a235UL, 0x4444cc88UL, 0x1717392eUL, - 0xc4c45793UL, 0xa7a7f255UL, 0x7e7e82fcUL, 0x3d3d477aUL, - 0x6464acc8UL, 0x5d5de7baUL, 0x19192b32UL, 0x737395e6UL, - 0x6060a0c0UL, 0x81819819UL, 0x4f4fd19eUL, 0xdcdc7fa3UL, - 0x22226644UL, 0x2a2a7e54UL, 0x9090ab3bUL, 0x8888830bUL, - 0x4646ca8cUL, 0xeeee29c7UL, 0xb8b8d36bUL, 0x14143c28UL, - 0xdede79a7UL, 0x5e5ee2bcUL, 0x0b0b1d16UL, 0xdbdb76adUL, - 0xe0e03bdbUL, 0x32325664UL, 0x3a3a4e74UL, 0x0a0a1e14UL, - 0x4949db92UL, 0x06060a0cUL, 0x24246c48UL, 0x5c5ce4b8UL, - 0xc2c25d9fUL, 0xd3d36ebdUL, 0xacacef43UL, 0x6262a6c4UL, - 0x9191a839UL, 0x9595a431UL, 0xe4e437d3UL, 0x79798bf2UL, - 0xe7e732d5UL, 0xc8c8438bUL, 0x3737596eUL, 0x6d6db7daUL, - 0x8d8d8c01UL, 0xd5d564b1UL, 0x4e4ed29cUL, 0xa9a9e049UL, - 0x6c6cb4d8UL, 0x5656faacUL, 0xf4f407f3UL, 0xeaea25cfUL, - 0x6565afcaUL, 0x7a7a8ef4UL, 0xaeaee947UL, 0x08081810UL, - 0xbabad56fUL, 0x787888f0UL, 0x25256f4aUL, 0x2e2e725cUL, - 0x1c1c2438UL, 0xa6a6f157UL, 0xb4b4c773UL, 0xc6c65197UL, - 0xe8e823cbUL, 0xdddd7ca1UL, 0x74749ce8UL, 0x1f1f213eUL, - 0x4b4bdd96UL, 0xbdbddc61UL, 0x8b8b860dUL, 0x8a8a850fUL, - 0x707090e0UL, 0x3e3e427cUL, 0xb5b5c471UL, 0x6666aaccUL, - 0x4848d890UL, 0x03030506UL, 0xf6f601f7UL, 0x0e0e121cUL, - 0x6161a3c2UL, 0x35355f6aUL, 0x5757f9aeUL, 0xb9b9d069UL, - 0x86869117UL, 0xc1c15899UL, 0x1d1d273aUL, 0x9e9eb927UL, - 0xe1e138d9UL, 0xf8f813ebUL, 0x9898b32bUL, 0x11113322UL, - 0x6969bbd2UL, 0xd9d970a9UL, 0x8e8e8907UL, 0x9494a733UL, - 0x9b9bb62dUL, 0x1e1e223cUL, 0x87879215UL, 0xe9e920c9UL, - 0xcece4987UL, 0x5555ffaaUL, 0x28287850UL, 0xdfdf7aa5UL, - 0x8c8c8f03UL, 0xa1a1f859UL, 0x89898009UL, 0x0d0d171aUL, - 0xbfbfda65UL, 0xe6e631d7UL, 0x4242c684UL, 0x6868b8d0UL, - 0x4141c382UL, 0x9999b029UL, 0x2d2d775aUL, 0x0f0f111eUL, - 0xb0b0cb7bUL, 0x5454fca8UL, 0xbbbbd66dUL, 0x16163a2cUL, -}; -static const unsigned int Te4[256] = { - 0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL, - 0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL, - 0x30303030UL, 0x01010101UL, 0x67676767UL, 0x2b2b2b2bUL, - 0xfefefefeUL, 0xd7d7d7d7UL, 0xababababUL, 0x76767676UL, - 0xcacacacaUL, 0x82828282UL, 0xc9c9c9c9UL, 0x7d7d7d7dUL, - 0xfafafafaUL, 0x59595959UL, 0x47474747UL, 0xf0f0f0f0UL, - 0xadadadadUL, 0xd4d4d4d4UL, 0xa2a2a2a2UL, 0xafafafafUL, - 0x9c9c9c9cUL, 0xa4a4a4a4UL, 0x72727272UL, 0xc0c0c0c0UL, - 0xb7b7b7b7UL, 0xfdfdfdfdUL, 0x93939393UL, 0x26262626UL, - 0x36363636UL, 0x3f3f3f3fUL, 0xf7f7f7f7UL, 0xccccccccUL, - 0x34343434UL, 0xa5a5a5a5UL, 0xe5e5e5e5UL, 0xf1f1f1f1UL, - 0x71717171UL, 0xd8d8d8d8UL, 0x31313131UL, 0x15151515UL, - 0x04040404UL, 0xc7c7c7c7UL, 0x23232323UL, 0xc3c3c3c3UL, - 0x18181818UL, 0x96969696UL, 0x05050505UL, 0x9a9a9a9aUL, - 0x07070707UL, 0x12121212UL, 0x80808080UL, 0xe2e2e2e2UL, - 0xebebebebUL, 0x27272727UL, 0xb2b2b2b2UL, 0x75757575UL, - 0x09090909UL, 0x83838383UL, 0x2c2c2c2cUL, 0x1a1a1a1aUL, - 0x1b1b1b1bUL, 0x6e6e6e6eUL, 0x5a5a5a5aUL, 0xa0a0a0a0UL, - 0x52525252UL, 0x3b3b3b3bUL, 0xd6d6d6d6UL, 0xb3b3b3b3UL, - 0x29292929UL, 0xe3e3e3e3UL, 0x2f2f2f2fUL, 0x84848484UL, - 0x53535353UL, 0xd1d1d1d1UL, 0x00000000UL, 0xededededUL, - 0x20202020UL, 0xfcfcfcfcUL, 0xb1b1b1b1UL, 0x5b5b5b5bUL, - 0x6a6a6a6aUL, 0xcbcbcbcbUL, 0xbebebebeUL, 0x39393939UL, - 0x4a4a4a4aUL, 0x4c4c4c4cUL, 0x58585858UL, 0xcfcfcfcfUL, - 0xd0d0d0d0UL, 0xefefefefUL, 0xaaaaaaaaUL, 0xfbfbfbfbUL, - 0x43434343UL, 0x4d4d4d4dUL, 0x33333333UL, 0x85858585UL, - 0x45454545UL, 0xf9f9f9f9UL, 0x02020202UL, 0x7f7f7f7fUL, - 0x50505050UL, 0x3c3c3c3cUL, 0x9f9f9f9fUL, 0xa8a8a8a8UL, - 0x51515151UL, 0xa3a3a3a3UL, 0x40404040UL, 0x8f8f8f8fUL, - 0x92929292UL, 0x9d9d9d9dUL, 0x38383838UL, 0xf5f5f5f5UL, - 0xbcbcbcbcUL, 0xb6b6b6b6UL, 0xdadadadaUL, 0x21212121UL, - 0x10101010UL, 0xffffffffUL, 0xf3f3f3f3UL, 0xd2d2d2d2UL, - 0xcdcdcdcdUL, 0x0c0c0c0cUL, 0x13131313UL, 0xececececUL, - 0x5f5f5f5fUL, 0x97979797UL, 0x44444444UL, 0x17171717UL, - 0xc4c4c4c4UL, 0xa7a7a7a7UL, 0x7e7e7e7eUL, 0x3d3d3d3dUL, - 0x64646464UL, 0x5d5d5d5dUL, 0x19191919UL, 0x73737373UL, - 0x60606060UL, 0x81818181UL, 0x4f4f4f4fUL, 0xdcdcdcdcUL, - 0x22222222UL, 0x2a2a2a2aUL, 0x90909090UL, 0x88888888UL, - 0x46464646UL, 0xeeeeeeeeUL, 0xb8b8b8b8UL, 0x14141414UL, - 0xdedededeUL, 0x5e5e5e5eUL, 0x0b0b0b0bUL, 0xdbdbdbdbUL, - 0xe0e0e0e0UL, 0x32323232UL, 0x3a3a3a3aUL, 0x0a0a0a0aUL, - 0x49494949UL, 0x06060606UL, 0x24242424UL, 0x5c5c5c5cUL, - 0xc2c2c2c2UL, 0xd3d3d3d3UL, 0xacacacacUL, 0x62626262UL, - 0x91919191UL, 0x95959595UL, 0xe4e4e4e4UL, 0x79797979UL, - 0xe7e7e7e7UL, 0xc8c8c8c8UL, 0x37373737UL, 0x6d6d6d6dUL, - 0x8d8d8d8dUL, 0xd5d5d5d5UL, 0x4e4e4e4eUL, 0xa9a9a9a9UL, - 0x6c6c6c6cUL, 0x56565656UL, 0xf4f4f4f4UL, 0xeaeaeaeaUL, - 0x65656565UL, 0x7a7a7a7aUL, 0xaeaeaeaeUL, 0x08080808UL, - 0xbabababaUL, 0x78787878UL, 0x25252525UL, 0x2e2e2e2eUL, - 0x1c1c1c1cUL, 0xa6a6a6a6UL, 0xb4b4b4b4UL, 0xc6c6c6c6UL, - 0xe8e8e8e8UL, 0xddddddddUL, 0x74747474UL, 0x1f1f1f1fUL, - 0x4b4b4b4bUL, 0xbdbdbdbdUL, 0x8b8b8b8bUL, 0x8a8a8a8aUL, - 0x70707070UL, 0x3e3e3e3eUL, 0xb5b5b5b5UL, 0x66666666UL, - 0x48484848UL, 0x03030303UL, 0xf6f6f6f6UL, 0x0e0e0e0eUL, - 0x61616161UL, 0x35353535UL, 0x57575757UL, 0xb9b9b9b9UL, - 0x86868686UL, 0xc1c1c1c1UL, 0x1d1d1d1dUL, 0x9e9e9e9eUL, - 0xe1e1e1e1UL, 0xf8f8f8f8UL, 0x98989898UL, 0x11111111UL, - 0x69696969UL, 0xd9d9d9d9UL, 0x8e8e8e8eUL, 0x94949494UL, - 0x9b9b9b9bUL, 0x1e1e1e1eUL, 0x87878787UL, 0xe9e9e9e9UL, - 0xcecececeUL, 0x55555555UL, 0x28282828UL, 0xdfdfdfdfUL, - 0x8c8c8c8cUL, 0xa1a1a1a1UL, 0x89898989UL, 0x0d0d0d0dUL, - 0xbfbfbfbfUL, 0xe6e6e6e6UL, 0x42424242UL, 0x68686868UL, - 0x41414141UL, 0x99999999UL, 0x2d2d2d2dUL, 0x0f0f0f0fUL, - 0xb0b0b0b0UL, 0x54545454UL, 0xbbbbbbbbUL, 0x16161616UL, -}; -static const unsigned int Td0[256] = { - 0x51f4a750UL, 0x7e416553UL, 0x1a17a4c3UL, 0x3a275e96UL, - 0x3bab6bcbUL, 0x1f9d45f1UL, 0xacfa58abUL, 0x4be30393UL, - 0x2030fa55UL, 0xad766df6UL, 0x88cc7691UL, 0xf5024c25UL, - 0x4fe5d7fcUL, 0xc52acbd7UL, 0x26354480UL, 0xb562a38fUL, - 0xdeb15a49UL, 0x25ba1b67UL, 0x45ea0e98UL, 0x5dfec0e1UL, - 0xc32f7502UL, 0x814cf012UL, 0x8d4697a3UL, 0x6bd3f9c6UL, - 0x038f5fe7UL, 0x15929c95UL, 0xbf6d7aebUL, 0x955259daUL, - 0xd4be832dUL, 0x587421d3UL, 0x49e06929UL, 0x8ec9c844UL, - 0x75c2896aUL, 0xf48e7978UL, 0x99583e6bUL, 0x27b971ddUL, - 0xbee14fb6UL, 0xf088ad17UL, 0xc920ac66UL, 0x7dce3ab4UL, - 0x63df4a18UL, 0xe51a3182UL, 0x97513360UL, 0x62537f45UL, - 0xb16477e0UL, 0xbb6bae84UL, 0xfe81a01cUL, 0xf9082b94UL, - 0x70486858UL, 0x8f45fd19UL, 0x94de6c87UL, 0x527bf8b7UL, - 0xab73d323UL, 0x724b02e2UL, 0xe31f8f57UL, 0x6655ab2aUL, - 0xb2eb2807UL, 0x2fb5c203UL, 0x86c57b9aUL, 0xd33708a5UL, - 0x302887f2UL, 0x23bfa5b2UL, 0x02036abaUL, 0xed16825cUL, - 0x8acf1c2bUL, 0xa779b492UL, 0xf307f2f0UL, 0x4e69e2a1UL, - 0x65daf4cdUL, 0x0605bed5UL, 0xd134621fUL, 0xc4a6fe8aUL, - 0x342e539dUL, 0xa2f355a0UL, 0x058ae132UL, 0xa4f6eb75UL, - 0x0b83ec39UL, 0x4060efaaUL, 0x5e719f06UL, 0xbd6e1051UL, - 0x3e218af9UL, 0x96dd063dUL, 0xdd3e05aeUL, 0x4de6bd46UL, - 0x91548db5UL, 0x71c45d05UL, 0x0406d46fUL, 0x605015ffUL, - 0x1998fb24UL, 0xd6bde997UL, 0x894043ccUL, 0x67d99e77UL, - 0xb0e842bdUL, 0x07898b88UL, 0xe7195b38UL, 0x79c8eedbUL, - 0xa17c0a47UL, 0x7c420fe9UL, 0xf8841ec9UL, 0x00000000UL, - 0x09808683UL, 0x322bed48UL, 0x1e1170acUL, 0x6c5a724eUL, - 0xfd0efffbUL, 0x0f853856UL, 0x3daed51eUL, 0x362d3927UL, - 0x0a0fd964UL, 0x685ca621UL, 0x9b5b54d1UL, 0x24362e3aUL, - 0x0c0a67b1UL, 0x9357e70fUL, 0xb4ee96d2UL, 0x1b9b919eUL, - 0x80c0c54fUL, 0x61dc20a2UL, 0x5a774b69UL, 0x1c121a16UL, - 0xe293ba0aUL, 0xc0a02ae5UL, 0x3c22e043UL, 0x121b171dUL, - 0x0e090d0bUL, 0xf28bc7adUL, 0x2db6a8b9UL, 0x141ea9c8UL, - 0x57f11985UL, 0xaf75074cUL, 0xee99ddbbUL, 0xa37f60fdUL, - 0xf701269fUL, 0x5c72f5bcUL, 0x44663bc5UL, 0x5bfb7e34UL, - 0x8b432976UL, 0xcb23c6dcUL, 0xb6edfc68UL, 0xb8e4f163UL, - 0xd731dccaUL, 0x42638510UL, 0x13972240UL, 0x84c61120UL, - 0x854a247dUL, 0xd2bb3df8UL, 0xaef93211UL, 0xc729a16dUL, - 0x1d9e2f4bUL, 0xdcb230f3UL, 0x0d8652ecUL, 0x77c1e3d0UL, - 0x2bb3166cUL, 0xa970b999UL, 0x119448faUL, 0x47e96422UL, - 0xa8fc8cc4UL, 0xa0f03f1aUL, 0x567d2cd8UL, 0x223390efUL, - 0x87494ec7UL, 0xd938d1c1UL, 0x8ccaa2feUL, 0x98d40b36UL, - 0xa6f581cfUL, 0xa57ade28UL, 0xdab78e26UL, 0x3fadbfa4UL, - 0x2c3a9de4UL, 0x5078920dUL, 0x6a5fcc9bUL, 0x547e4662UL, - 0xf68d13c2UL, 0x90d8b8e8UL, 0x2e39f75eUL, 0x82c3aff5UL, - 0x9f5d80beUL, 0x69d0937cUL, 0x6fd52da9UL, 0xcf2512b3UL, - 0xc8ac993bUL, 0x10187da7UL, 0xe89c636eUL, 0xdb3bbb7bUL, - 0xcd267809UL, 0x6e5918f4UL, 0xec9ab701UL, 0x834f9aa8UL, - 0xe6956e65UL, 0xaaffe67eUL, 0x21bccf08UL, 0xef15e8e6UL, - 0xbae79bd9UL, 0x4a6f36ceUL, 0xea9f09d4UL, 0x29b07cd6UL, - 0x31a4b2afUL, 0x2a3f2331UL, 0xc6a59430UL, 0x35a266c0UL, - 0x744ebc37UL, 0xfc82caa6UL, 0xe090d0b0UL, 0x33a7d815UL, - 0xf104984aUL, 0x41ecdaf7UL, 0x7fcd500eUL, 0x1791f62fUL, - 0x764dd68dUL, 0x43efb04dUL, 0xccaa4d54UL, 0xe49604dfUL, - 0x9ed1b5e3UL, 0x4c6a881bUL, 0xc12c1fb8UL, 0x4665517fUL, - 0x9d5eea04UL, 0x018c355dUL, 0xfa877473UL, 0xfb0b412eUL, - 0xb3671d5aUL, 0x92dbd252UL, 0xe9105633UL, 0x6dd64713UL, - 0x9ad7618cUL, 0x37a10c7aUL, 0x59f8148eUL, 0xeb133c89UL, - 0xcea927eeUL, 0xb761c935UL, 0xe11ce5edUL, 0x7a47b13cUL, - 0x9cd2df59UL, 0x55f2733fUL, 0x1814ce79UL, 0x73c737bfUL, - 0x53f7cdeaUL, 0x5ffdaa5bUL, 0xdf3d6f14UL, 0x7844db86UL, - 0xcaaff381UL, 0xb968c43eUL, 0x3824342cUL, 0xc2a3405fUL, - 0x161dc372UL, 0xbce2250cUL, 0x283c498bUL, 0xff0d9541UL, - 0x39a80171UL, 0x080cb3deUL, 0xd8b4e49cUL, 0x6456c190UL, - 0x7bcb8461UL, 0xd532b670UL, 0x486c5c74UL, 0xd0b85742UL, -}; -static const unsigned int Td1[256] = { - 0x5051f4a7UL, 0x537e4165UL, 0xc31a17a4UL, 0x963a275eUL, - 0xcb3bab6bUL, 0xf11f9d45UL, 0xabacfa58UL, 0x934be303UL, - 0x552030faUL, 0xf6ad766dUL, 0x9188cc76UL, 0x25f5024cUL, - 0xfc4fe5d7UL, 0xd7c52acbUL, 0x80263544UL, 0x8fb562a3UL, - 0x49deb15aUL, 0x6725ba1bUL, 0x9845ea0eUL, 0xe15dfec0UL, - 0x02c32f75UL, 0x12814cf0UL, 0xa38d4697UL, 0xc66bd3f9UL, - 0xe7038f5fUL, 0x9515929cUL, 0xebbf6d7aUL, 0xda955259UL, - 0x2dd4be83UL, 0xd3587421UL, 0x2949e069UL, 0x448ec9c8UL, - 0x6a75c289UL, 0x78f48e79UL, 0x6b99583eUL, 0xdd27b971UL, - 0xb6bee14fUL, 0x17f088adUL, 0x66c920acUL, 0xb47dce3aUL, - 0x1863df4aUL, 0x82e51a31UL, 0x60975133UL, 0x4562537fUL, - 0xe0b16477UL, 0x84bb6baeUL, 0x1cfe81a0UL, 0x94f9082bUL, - 0x58704868UL, 0x198f45fdUL, 0x8794de6cUL, 0xb7527bf8UL, - 0x23ab73d3UL, 0xe2724b02UL, 0x57e31f8fUL, 0x2a6655abUL, - 0x07b2eb28UL, 0x032fb5c2UL, 0x9a86c57bUL, 0xa5d33708UL, - 0xf2302887UL, 0xb223bfa5UL, 0xba02036aUL, 0x5ced1682UL, - 0x2b8acf1cUL, 0x92a779b4UL, 0xf0f307f2UL, 0xa14e69e2UL, - 0xcd65daf4UL, 0xd50605beUL, 0x1fd13462UL, 0x8ac4a6feUL, - 0x9d342e53UL, 0xa0a2f355UL, 0x32058ae1UL, 0x75a4f6ebUL, - 0x390b83ecUL, 0xaa4060efUL, 0x065e719fUL, 0x51bd6e10UL, - 0xf93e218aUL, 0x3d96dd06UL, 0xaedd3e05UL, 0x464de6bdUL, - 0xb591548dUL, 0x0571c45dUL, 0x6f0406d4UL, 0xff605015UL, - 0x241998fbUL, 0x97d6bde9UL, 0xcc894043UL, 0x7767d99eUL, - 0xbdb0e842UL, 0x8807898bUL, 0x38e7195bUL, 0xdb79c8eeUL, - 0x47a17c0aUL, 0xe97c420fUL, 0xc9f8841eUL, 0x00000000UL, - 0x83098086UL, 0x48322bedUL, 0xac1e1170UL, 0x4e6c5a72UL, - 0xfbfd0effUL, 0x560f8538UL, 0x1e3daed5UL, 0x27362d39UL, - 0x640a0fd9UL, 0x21685ca6UL, 0xd19b5b54UL, 0x3a24362eUL, - 0xb10c0a67UL, 0x0f9357e7UL, 0xd2b4ee96UL, 0x9e1b9b91UL, - 0x4f80c0c5UL, 0xa261dc20UL, 0x695a774bUL, 0x161c121aUL, - 0x0ae293baUL, 0xe5c0a02aUL, 0x433c22e0UL, 0x1d121b17UL, - 0x0b0e090dUL, 0xadf28bc7UL, 0xb92db6a8UL, 0xc8141ea9UL, - 0x8557f119UL, 0x4caf7507UL, 0xbbee99ddUL, 0xfda37f60UL, - 0x9ff70126UL, 0xbc5c72f5UL, 0xc544663bUL, 0x345bfb7eUL, - 0x768b4329UL, 0xdccb23c6UL, 0x68b6edfcUL, 0x63b8e4f1UL, - 0xcad731dcUL, 0x10426385UL, 0x40139722UL, 0x2084c611UL, - 0x7d854a24UL, 0xf8d2bb3dUL, 0x11aef932UL, 0x6dc729a1UL, - 0x4b1d9e2fUL, 0xf3dcb230UL, 0xec0d8652UL, 0xd077c1e3UL, - 0x6c2bb316UL, 0x99a970b9UL, 0xfa119448UL, 0x2247e964UL, - 0xc4a8fc8cUL, 0x1aa0f03fUL, 0xd8567d2cUL, 0xef223390UL, - 0xc787494eUL, 0xc1d938d1UL, 0xfe8ccaa2UL, 0x3698d40bUL, - 0xcfa6f581UL, 0x28a57adeUL, 0x26dab78eUL, 0xa43fadbfUL, - 0xe42c3a9dUL, 0x0d507892UL, 0x9b6a5fccUL, 0x62547e46UL, - 0xc2f68d13UL, 0xe890d8b8UL, 0x5e2e39f7UL, 0xf582c3afUL, - 0xbe9f5d80UL, 0x7c69d093UL, 0xa96fd52dUL, 0xb3cf2512UL, - 0x3bc8ac99UL, 0xa710187dUL, 0x6ee89c63UL, 0x7bdb3bbbUL, - 0x09cd2678UL, 0xf46e5918UL, 0x01ec9ab7UL, 0xa8834f9aUL, - 0x65e6956eUL, 0x7eaaffe6UL, 0x0821bccfUL, 0xe6ef15e8UL, - 0xd9bae79bUL, 0xce4a6f36UL, 0xd4ea9f09UL, 0xd629b07cUL, - 0xaf31a4b2UL, 0x312a3f23UL, 0x30c6a594UL, 0xc035a266UL, - 0x37744ebcUL, 0xa6fc82caUL, 0xb0e090d0UL, 0x1533a7d8UL, - 0x4af10498UL, 0xf741ecdaUL, 0x0e7fcd50UL, 0x2f1791f6UL, - 0x8d764dd6UL, 0x4d43efb0UL, 0x54ccaa4dUL, 0xdfe49604UL, - 0xe39ed1b5UL, 0x1b4c6a88UL, 0xb8c12c1fUL, 0x7f466551UL, - 0x049d5eeaUL, 0x5d018c35UL, 0x73fa8774UL, 0x2efb0b41UL, - 0x5ab3671dUL, 0x5292dbd2UL, 0x33e91056UL, 0x136dd647UL, - 0x8c9ad761UL, 0x7a37a10cUL, 0x8e59f814UL, 0x89eb133cUL, - 0xeecea927UL, 0x35b761c9UL, 0xede11ce5UL, 0x3c7a47b1UL, - 0x599cd2dfUL, 0x3f55f273UL, 0x791814ceUL, 0xbf73c737UL, - 0xea53f7cdUL, 0x5b5ffdaaUL, 0x14df3d6fUL, 0x867844dbUL, - 0x81caaff3UL, 0x3eb968c4UL, 0x2c382434UL, 0x5fc2a340UL, - 0x72161dc3UL, 0x0cbce225UL, 0x8b283c49UL, 0x41ff0d95UL, - 0x7139a801UL, 0xde080cb3UL, 0x9cd8b4e4UL, 0x906456c1UL, - 0x617bcb84UL, 0x70d532b6UL, 0x74486c5cUL, 0x42d0b857UL, -}; -static const unsigned int Td2[256] = { - 0xa75051f4UL, 0x65537e41UL, 0xa4c31a17UL, 0x5e963a27UL, - 0x6bcb3babUL, 0x45f11f9dUL, 0x58abacfaUL, 0x03934be3UL, - 0xfa552030UL, 0x6df6ad76UL, 0x769188ccUL, 0x4c25f502UL, - 0xd7fc4fe5UL, 0xcbd7c52aUL, 0x44802635UL, 0xa38fb562UL, - 0x5a49deb1UL, 0x1b6725baUL, 0x0e9845eaUL, 0xc0e15dfeUL, - 0x7502c32fUL, 0xf012814cUL, 0x97a38d46UL, 0xf9c66bd3UL, - 0x5fe7038fUL, 0x9c951592UL, 0x7aebbf6dUL, 0x59da9552UL, - 0x832dd4beUL, 0x21d35874UL, 0x692949e0UL, 0xc8448ec9UL, - 0x896a75c2UL, 0x7978f48eUL, 0x3e6b9958UL, 0x71dd27b9UL, - 0x4fb6bee1UL, 0xad17f088UL, 0xac66c920UL, 0x3ab47dceUL, - 0x4a1863dfUL, 0x3182e51aUL, 0x33609751UL, 0x7f456253UL, - 0x77e0b164UL, 0xae84bb6bUL, 0xa01cfe81UL, 0x2b94f908UL, - 0x68587048UL, 0xfd198f45UL, 0x6c8794deUL, 0xf8b7527bUL, - 0xd323ab73UL, 0x02e2724bUL, 0x8f57e31fUL, 0xab2a6655UL, - 0x2807b2ebUL, 0xc2032fb5UL, 0x7b9a86c5UL, 0x08a5d337UL, - 0x87f23028UL, 0xa5b223bfUL, 0x6aba0203UL, 0x825ced16UL, - 0x1c2b8acfUL, 0xb492a779UL, 0xf2f0f307UL, 0xe2a14e69UL, - 0xf4cd65daUL, 0xbed50605UL, 0x621fd134UL, 0xfe8ac4a6UL, - 0x539d342eUL, 0x55a0a2f3UL, 0xe132058aUL, 0xeb75a4f6UL, - 0xec390b83UL, 0xefaa4060UL, 0x9f065e71UL, 0x1051bd6eUL, - 0x8af93e21UL, 0x063d96ddUL, 0x05aedd3eUL, 0xbd464de6UL, - 0x8db59154UL, 0x5d0571c4UL, 0xd46f0406UL, 0x15ff6050UL, - 0xfb241998UL, 0xe997d6bdUL, 0x43cc8940UL, 0x9e7767d9UL, - 0x42bdb0e8UL, 0x8b880789UL, 0x5b38e719UL, 0xeedb79c8UL, - 0x0a47a17cUL, 0x0fe97c42UL, 0x1ec9f884UL, 0x00000000UL, - 0x86830980UL, 0xed48322bUL, 0x70ac1e11UL, 0x724e6c5aUL, - 0xfffbfd0eUL, 0x38560f85UL, 0xd51e3daeUL, 0x3927362dUL, - 0xd9640a0fUL, 0xa621685cUL, 0x54d19b5bUL, 0x2e3a2436UL, - 0x67b10c0aUL, 0xe70f9357UL, 0x96d2b4eeUL, 0x919e1b9bUL, - 0xc54f80c0UL, 0x20a261dcUL, 0x4b695a77UL, 0x1a161c12UL, - 0xba0ae293UL, 0x2ae5c0a0UL, 0xe0433c22UL, 0x171d121bUL, - 0x0d0b0e09UL, 0xc7adf28bUL, 0xa8b92db6UL, 0xa9c8141eUL, - 0x198557f1UL, 0x074caf75UL, 0xddbbee99UL, 0x60fda37fUL, - 0x269ff701UL, 0xf5bc5c72UL, 0x3bc54466UL, 0x7e345bfbUL, - 0x29768b43UL, 0xc6dccb23UL, 0xfc68b6edUL, 0xf163b8e4UL, - 0xdccad731UL, 0x85104263UL, 0x22401397UL, 0x112084c6UL, - 0x247d854aUL, 0x3df8d2bbUL, 0x3211aef9UL, 0xa16dc729UL, - 0x2f4b1d9eUL, 0x30f3dcb2UL, 0x52ec0d86UL, 0xe3d077c1UL, - 0x166c2bb3UL, 0xb999a970UL, 0x48fa1194UL, 0x642247e9UL, - 0x8cc4a8fcUL, 0x3f1aa0f0UL, 0x2cd8567dUL, 0x90ef2233UL, - 0x4ec78749UL, 0xd1c1d938UL, 0xa2fe8ccaUL, 0x0b3698d4UL, - 0x81cfa6f5UL, 0xde28a57aUL, 0x8e26dab7UL, 0xbfa43fadUL, - 0x9de42c3aUL, 0x920d5078UL, 0xcc9b6a5fUL, 0x4662547eUL, - 0x13c2f68dUL, 0xb8e890d8UL, 0xf75e2e39UL, 0xaff582c3UL, - 0x80be9f5dUL, 0x937c69d0UL, 0x2da96fd5UL, 0x12b3cf25UL, - 0x993bc8acUL, 0x7da71018UL, 0x636ee89cUL, 0xbb7bdb3bUL, - 0x7809cd26UL, 0x18f46e59UL, 0xb701ec9aUL, 0x9aa8834fUL, - 0x6e65e695UL, 0xe67eaaffUL, 0xcf0821bcUL, 0xe8e6ef15UL, - 0x9bd9bae7UL, 0x36ce4a6fUL, 0x09d4ea9fUL, 0x7cd629b0UL, - 0xb2af31a4UL, 0x23312a3fUL, 0x9430c6a5UL, 0x66c035a2UL, - 0xbc37744eUL, 0xcaa6fc82UL, 0xd0b0e090UL, 0xd81533a7UL, - 0x984af104UL, 0xdaf741ecUL, 0x500e7fcdUL, 0xf62f1791UL, - 0xd68d764dUL, 0xb04d43efUL, 0x4d54ccaaUL, 0x04dfe496UL, - 0xb5e39ed1UL, 0x881b4c6aUL, 0x1fb8c12cUL, 0x517f4665UL, - 0xea049d5eUL, 0x355d018cUL, 0x7473fa87UL, 0x412efb0bUL, - 0x1d5ab367UL, 0xd25292dbUL, 0x5633e910UL, 0x47136dd6UL, - 0x618c9ad7UL, 0x0c7a37a1UL, 0x148e59f8UL, 0x3c89eb13UL, - 0x27eecea9UL, 0xc935b761UL, 0xe5ede11cUL, 0xb13c7a47UL, - 0xdf599cd2UL, 0x733f55f2UL, 0xce791814UL, 0x37bf73c7UL, - 0xcdea53f7UL, 0xaa5b5ffdUL, 0x6f14df3dUL, 0xdb867844UL, - 0xf381caafUL, 0xc43eb968UL, 0x342c3824UL, 0x405fc2a3UL, - 0xc372161dUL, 0x250cbce2UL, 0x498b283cUL, 0x9541ff0dUL, - 0x017139a8UL, 0xb3de080cUL, 0xe49cd8b4UL, 0xc1906456UL, - 0x84617bcbUL, 0xb670d532UL, 0x5c74486cUL, 0x5742d0b8UL, -}; -static const unsigned int Td3[256] = { - 0xf4a75051UL, 0x4165537eUL, 0x17a4c31aUL, 0x275e963aUL, - 0xab6bcb3bUL, 0x9d45f11fUL, 0xfa58abacUL, 0xe303934bUL, - 0x30fa5520UL, 0x766df6adUL, 0xcc769188UL, 0x024c25f5UL, - 0xe5d7fc4fUL, 0x2acbd7c5UL, 0x35448026UL, 0x62a38fb5UL, - 0xb15a49deUL, 0xba1b6725UL, 0xea0e9845UL, 0xfec0e15dUL, - 0x2f7502c3UL, 0x4cf01281UL, 0x4697a38dUL, 0xd3f9c66bUL, - 0x8f5fe703UL, 0x929c9515UL, 0x6d7aebbfUL, 0x5259da95UL, - 0xbe832dd4UL, 0x7421d358UL, 0xe0692949UL, 0xc9c8448eUL, - 0xc2896a75UL, 0x8e7978f4UL, 0x583e6b99UL, 0xb971dd27UL, - 0xe14fb6beUL, 0x88ad17f0UL, 0x20ac66c9UL, 0xce3ab47dUL, - 0xdf4a1863UL, 0x1a3182e5UL, 0x51336097UL, 0x537f4562UL, - 0x6477e0b1UL, 0x6bae84bbUL, 0x81a01cfeUL, 0x082b94f9UL, - 0x48685870UL, 0x45fd198fUL, 0xde6c8794UL, 0x7bf8b752UL, - 0x73d323abUL, 0x4b02e272UL, 0x1f8f57e3UL, 0x55ab2a66UL, - 0xeb2807b2UL, 0xb5c2032fUL, 0xc57b9a86UL, 0x3708a5d3UL, - 0x2887f230UL, 0xbfa5b223UL, 0x036aba02UL, 0x16825cedUL, - 0xcf1c2b8aUL, 0x79b492a7UL, 0x07f2f0f3UL, 0x69e2a14eUL, - 0xdaf4cd65UL, 0x05bed506UL, 0x34621fd1UL, 0xa6fe8ac4UL, - 0x2e539d34UL, 0xf355a0a2UL, 0x8ae13205UL, 0xf6eb75a4UL, - 0x83ec390bUL, 0x60efaa40UL, 0x719f065eUL, 0x6e1051bdUL, - 0x218af93eUL, 0xdd063d96UL, 0x3e05aeddUL, 0xe6bd464dUL, - 0x548db591UL, 0xc45d0571UL, 0x06d46f04UL, 0x5015ff60UL, - 0x98fb2419UL, 0xbde997d6UL, 0x4043cc89UL, 0xd99e7767UL, - 0xe842bdb0UL, 0x898b8807UL, 0x195b38e7UL, 0xc8eedb79UL, - 0x7c0a47a1UL, 0x420fe97cUL, 0x841ec9f8UL, 0x00000000UL, - 0x80868309UL, 0x2bed4832UL, 0x1170ac1eUL, 0x5a724e6cUL, - 0x0efffbfdUL, 0x8538560fUL, 0xaed51e3dUL, 0x2d392736UL, - 0x0fd9640aUL, 0x5ca62168UL, 0x5b54d19bUL, 0x362e3a24UL, - 0x0a67b10cUL, 0x57e70f93UL, 0xee96d2b4UL, 0x9b919e1bUL, - 0xc0c54f80UL, 0xdc20a261UL, 0x774b695aUL, 0x121a161cUL, - 0x93ba0ae2UL, 0xa02ae5c0UL, 0x22e0433cUL, 0x1b171d12UL, - 0x090d0b0eUL, 0x8bc7adf2UL, 0xb6a8b92dUL, 0x1ea9c814UL, - 0xf1198557UL, 0x75074cafUL, 0x99ddbbeeUL, 0x7f60fda3UL, - 0x01269ff7UL, 0x72f5bc5cUL, 0x663bc544UL, 0xfb7e345bUL, - 0x4329768bUL, 0x23c6dccbUL, 0xedfc68b6UL, 0xe4f163b8UL, - 0x31dccad7UL, 0x63851042UL, 0x97224013UL, 0xc6112084UL, - 0x4a247d85UL, 0xbb3df8d2UL, 0xf93211aeUL, 0x29a16dc7UL, - 0x9e2f4b1dUL, 0xb230f3dcUL, 0x8652ec0dUL, 0xc1e3d077UL, - 0xb3166c2bUL, 0x70b999a9UL, 0x9448fa11UL, 0xe9642247UL, - 0xfc8cc4a8UL, 0xf03f1aa0UL, 0x7d2cd856UL, 0x3390ef22UL, - 0x494ec787UL, 0x38d1c1d9UL, 0xcaa2fe8cUL, 0xd40b3698UL, - 0xf581cfa6UL, 0x7ade28a5UL, 0xb78e26daUL, 0xadbfa43fUL, - 0x3a9de42cUL, 0x78920d50UL, 0x5fcc9b6aUL, 0x7e466254UL, - 0x8d13c2f6UL, 0xd8b8e890UL, 0x39f75e2eUL, 0xc3aff582UL, - 0x5d80be9fUL, 0xd0937c69UL, 0xd52da96fUL, 0x2512b3cfUL, - 0xac993bc8UL, 0x187da710UL, 0x9c636ee8UL, 0x3bbb7bdbUL, - 0x267809cdUL, 0x5918f46eUL, 0x9ab701ecUL, 0x4f9aa883UL, - 0x956e65e6UL, 0xffe67eaaUL, 0xbccf0821UL, 0x15e8e6efUL, - 0xe79bd9baUL, 0x6f36ce4aUL, 0x9f09d4eaUL, 0xb07cd629UL, - 0xa4b2af31UL, 0x3f23312aUL, 0xa59430c6UL, 0xa266c035UL, - 0x4ebc3774UL, 0x82caa6fcUL, 0x90d0b0e0UL, 0xa7d81533UL, - 0x04984af1UL, 0xecdaf741UL, 0xcd500e7fUL, 0x91f62f17UL, - 0x4dd68d76UL, 0xefb04d43UL, 0xaa4d54ccUL, 0x9604dfe4UL, - 0xd1b5e39eUL, 0x6a881b4cUL, 0x2c1fb8c1UL, 0x65517f46UL, - 0x5eea049dUL, 0x8c355d01UL, 0x877473faUL, 0x0b412efbUL, - 0x671d5ab3UL, 0xdbd25292UL, 0x105633e9UL, 0xd647136dUL, - 0xd7618c9aUL, 0xa10c7a37UL, 0xf8148e59UL, 0x133c89ebUL, - 0xa927eeceUL, 0x61c935b7UL, 0x1ce5ede1UL, 0x47b13c7aUL, - 0xd2df599cUL, 0xf2733f55UL, 0x14ce7918UL, 0xc737bf73UL, - 0xf7cdea53UL, 0xfdaa5b5fUL, 0x3d6f14dfUL, 0x44db8678UL, - 0xaff381caUL, 0x68c43eb9UL, 0x24342c38UL, 0xa3405fc2UL, - 0x1dc37216UL, 0xe2250cbcUL, 0x3c498b28UL, 0x0d9541ffUL, - 0xa8017139UL, 0x0cb3de08UL, 0xb4e49cd8UL, 0x56c19064UL, - 0xcb84617bUL, 0x32b670d5UL, 0x6c5c7448UL, 0xb85742d0UL, -}; -static const unsigned int Td4[256] = { - 0x52525252UL, 0x09090909UL, 0x6a6a6a6aUL, 0xd5d5d5d5UL, - 0x30303030UL, 0x36363636UL, 0xa5a5a5a5UL, 0x38383838UL, - 0xbfbfbfbfUL, 0x40404040UL, 0xa3a3a3a3UL, 0x9e9e9e9eUL, - 0x81818181UL, 0xf3f3f3f3UL, 0xd7d7d7d7UL, 0xfbfbfbfbUL, - 0x7c7c7c7cUL, 0xe3e3e3e3UL, 0x39393939UL, 0x82828282UL, - 0x9b9b9b9bUL, 0x2f2f2f2fUL, 0xffffffffUL, 0x87878787UL, - 0x34343434UL, 0x8e8e8e8eUL, 0x43434343UL, 0x44444444UL, - 0xc4c4c4c4UL, 0xdedededeUL, 0xe9e9e9e9UL, 0xcbcbcbcbUL, - 0x54545454UL, 0x7b7b7b7bUL, 0x94949494UL, 0x32323232UL, - 0xa6a6a6a6UL, 0xc2c2c2c2UL, 0x23232323UL, 0x3d3d3d3dUL, - 0xeeeeeeeeUL, 0x4c4c4c4cUL, 0x95959595UL, 0x0b0b0b0bUL, - 0x42424242UL, 0xfafafafaUL, 0xc3c3c3c3UL, 0x4e4e4e4eUL, - 0x08080808UL, 0x2e2e2e2eUL, 0xa1a1a1a1UL, 0x66666666UL, - 0x28282828UL, 0xd9d9d9d9UL, 0x24242424UL, 0xb2b2b2b2UL, - 0x76767676UL, 0x5b5b5b5bUL, 0xa2a2a2a2UL, 0x49494949UL, - 0x6d6d6d6dUL, 0x8b8b8b8bUL, 0xd1d1d1d1UL, 0x25252525UL, - 0x72727272UL, 0xf8f8f8f8UL, 0xf6f6f6f6UL, 0x64646464UL, - 0x86868686UL, 0x68686868UL, 0x98989898UL, 0x16161616UL, - 0xd4d4d4d4UL, 0xa4a4a4a4UL, 0x5c5c5c5cUL, 0xccccccccUL, - 0x5d5d5d5dUL, 0x65656565UL, 0xb6b6b6b6UL, 0x92929292UL, - 0x6c6c6c6cUL, 0x70707070UL, 0x48484848UL, 0x50505050UL, - 0xfdfdfdfdUL, 0xededededUL, 0xb9b9b9b9UL, 0xdadadadaUL, - 0x5e5e5e5eUL, 0x15151515UL, 0x46464646UL, 0x57575757UL, - 0xa7a7a7a7UL, 0x8d8d8d8dUL, 0x9d9d9d9dUL, 0x84848484UL, - 0x90909090UL, 0xd8d8d8d8UL, 0xababababUL, 0x00000000UL, - 0x8c8c8c8cUL, 0xbcbcbcbcUL, 0xd3d3d3d3UL, 0x0a0a0a0aUL, - 0xf7f7f7f7UL, 0xe4e4e4e4UL, 0x58585858UL, 0x05050505UL, - 0xb8b8b8b8UL, 0xb3b3b3b3UL, 0x45454545UL, 0x06060606UL, - 0xd0d0d0d0UL, 0x2c2c2c2cUL, 0x1e1e1e1eUL, 0x8f8f8f8fUL, - 0xcacacacaUL, 0x3f3f3f3fUL, 0x0f0f0f0fUL, 0x02020202UL, - 0xc1c1c1c1UL, 0xafafafafUL, 0xbdbdbdbdUL, 0x03030303UL, - 0x01010101UL, 0x13131313UL, 0x8a8a8a8aUL, 0x6b6b6b6bUL, - 0x3a3a3a3aUL, 0x91919191UL, 0x11111111UL, 0x41414141UL, - 0x4f4f4f4fUL, 0x67676767UL, 0xdcdcdcdcUL, 0xeaeaeaeaUL, - 0x97979797UL, 0xf2f2f2f2UL, 0xcfcfcfcfUL, 0xcecececeUL, - 0xf0f0f0f0UL, 0xb4b4b4b4UL, 0xe6e6e6e6UL, 0x73737373UL, - 0x96969696UL, 0xacacacacUL, 0x74747474UL, 0x22222222UL, - 0xe7e7e7e7UL, 0xadadadadUL, 0x35353535UL, 0x85858585UL, - 0xe2e2e2e2UL, 0xf9f9f9f9UL, 0x37373737UL, 0xe8e8e8e8UL, - 0x1c1c1c1cUL, 0x75757575UL, 0xdfdfdfdfUL, 0x6e6e6e6eUL, - 0x47474747UL, 0xf1f1f1f1UL, 0x1a1a1a1aUL, 0x71717171UL, - 0x1d1d1d1dUL, 0x29292929UL, 0xc5c5c5c5UL, 0x89898989UL, - 0x6f6f6f6fUL, 0xb7b7b7b7UL, 0x62626262UL, 0x0e0e0e0eUL, - 0xaaaaaaaaUL, 0x18181818UL, 0xbebebebeUL, 0x1b1b1b1bUL, - 0xfcfcfcfcUL, 0x56565656UL, 0x3e3e3e3eUL, 0x4b4b4b4bUL, - 0xc6c6c6c6UL, 0xd2d2d2d2UL, 0x79797979UL, 0x20202020UL, - 0x9a9a9a9aUL, 0xdbdbdbdbUL, 0xc0c0c0c0UL, 0xfefefefeUL, - 0x78787878UL, 0xcdcdcdcdUL, 0x5a5a5a5aUL, 0xf4f4f4f4UL, - 0x1f1f1f1fUL, 0xddddddddUL, 0xa8a8a8a8UL, 0x33333333UL, - 0x88888888UL, 0x07070707UL, 0xc7c7c7c7UL, 0x31313131UL, - 0xb1b1b1b1UL, 0x12121212UL, 0x10101010UL, 0x59595959UL, - 0x27272727UL, 0x80808080UL, 0xececececUL, 0x5f5f5f5fUL, - 0x60606060UL, 0x51515151UL, 0x7f7f7f7fUL, 0xa9a9a9a9UL, - 0x19191919UL, 0xb5b5b5b5UL, 0x4a4a4a4aUL, 0x0d0d0d0dUL, - 0x2d2d2d2dUL, 0xe5e5e5e5UL, 0x7a7a7a7aUL, 0x9f9f9f9fUL, - 0x93939393UL, 0xc9c9c9c9UL, 0x9c9c9c9cUL, 0xefefefefUL, - 0xa0a0a0a0UL, 0xe0e0e0e0UL, 0x3b3b3b3bUL, 0x4d4d4d4dUL, - 0xaeaeaeaeUL, 0x2a2a2a2aUL, 0xf5f5f5f5UL, 0xb0b0b0b0UL, - 0xc8c8c8c8UL, 0xebebebebUL, 0xbbbbbbbbUL, 0x3c3c3c3cUL, - 0x83838383UL, 0x53535353UL, 0x99999999UL, 0x61616161UL, - 0x17171717UL, 0x2b2b2b2bUL, 0x04040404UL, 0x7e7e7e7eUL, - 0xbabababaUL, 0x77777777UL, 0xd6d6d6d6UL, 0x26262626UL, - 0xe1e1e1e1UL, 0x69696969UL, 0x14141414UL, 0x63636363UL, - 0x55555555UL, 0x21212121UL, 0x0c0c0c0cUL, 0x7d7d7d7dUL, -}; -static const unsigned int rcon[] = { - 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, - 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, - 0x1B000000UL, 0x36000000UL, -}; - -#define GETU32(pt) (((unsigned int)(pt)[0] << 24) ^ \ - ((unsigned int)(pt)[1] << 16) ^ \ - ((unsigned int)(pt)[2] << 8) ^ \ - ((unsigned int)(pt)[3])) - -#define PUTU32(ct, st) { (ct)[0] = (unsigned char)((st) >> 24); \ - (ct)[1] = (unsigned char)((st) >> 16); \ - (ct)[2] = (unsigned char)((st) >> 8); \ - (ct)[3] = (unsigned char)(st); } - -/* -* Expand the cipher key into the encryption key schedule and return the -* number of rounds for the given cipher key size. -*/ -int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBytes) -{ - int i = 0; - unsigned int temp; - - rk[0] = GETU32(cipherKey ); - rk[1] = GETU32(cipherKey + 4); - rk[2] = GETU32(cipherKey + 8); - rk[3] = GETU32(cipherKey + 12); - if (keyBytes == 16) { // 128 bits - for (;;) { - temp = rk[3]; - rk[4] = rk[0] ^ - (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ - (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ - (Te4[(temp ) & 0xff] & 0x0000ff00) ^ - (Te4[(temp >> 24) ] & 0x000000ff) ^ - rcon[i]; - rk[5] = rk[1] ^ rk[4]; - rk[6] = rk[2] ^ rk[5]; - rk[7] = rk[3] ^ rk[6]; - if (++i == 10) { - return 10; - } - rk += 4; - } - } - rk[4] = GETU32(cipherKey + 16); - rk[5] = GETU32(cipherKey + 20); - if (keyBytes == 24) { // 192 bits - for (;;) { - temp = rk[ 5]; - rk[ 6] = rk[ 0] ^ - (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ - (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ - (Te4[(temp ) & 0xff] & 0x0000ff00) ^ - (Te4[(temp >> 24) ] & 0x000000ff) ^ - rcon[i]; - rk[ 7] = rk[ 1] ^ rk[ 6]; - rk[ 8] = rk[ 2] ^ rk[ 7]; - rk[ 9] = rk[ 3] ^ rk[ 8]; - if (++i == 8) { - return 12; - } - rk[10] = rk[ 4] ^ rk[ 9]; - rk[11] = rk[ 5] ^ rk[10]; - rk += 6; - } - } - rk[6] = GETU32(cipherKey + 24); - rk[7] = GETU32(cipherKey + 28); - if (keyBytes == 32) { // 256 bits - for (;;) { - temp = rk[ 7]; - rk[ 8] = rk[ 0] ^ - (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ - (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ - (Te4[(temp ) & 0xff] & 0x0000ff00) ^ - (Te4[(temp >> 24) ] & 0x000000ff) ^ - rcon[i]; - rk[ 9] = rk[ 1] ^ rk[ 8]; - rk[10] = rk[ 2] ^ rk[ 9]; - rk[11] = rk[ 3] ^ rk[10]; - if (++i == 7) { - return 14; - } - temp = rk[11]; - rk[12] = rk[ 4] ^ - (Te4[(temp >> 24) ] & 0xff000000) ^ - (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(temp ) & 0xff] & 0x000000ff); - rk[13] = rk[ 5] ^ rk[12]; - rk[14] = rk[ 6] ^ rk[13]; - rk[15] = rk[ 7] ^ rk[14]; - - rk += 8; - } - } - return 0; -} - -/* -* Expand the cipher key into encryption and decryption key schedule and -* return the number of rounds for the given cipher key size. -*/ -int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char cipherKey[], int keyBytes) -{ - int Nr, i; - - // expand the cipher key - Nr = aes_setkey_enc(rk, cipherKey, keyBytes); - // invert the order of the first round keys - rrk += Nr * 4; - rrk[0] = rk[0]; - rrk[1] = rk[1]; - rrk[2] = rk[2]; - rrk[3] = rk[3]; - - /* - * apply the inverse MixColumn transform to all round keys but the first - * and the last - */ - for (i = 1; i < Nr; i++) { - rrk -= 4; - rk += 4; - rrk[0] = - Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ - Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ - Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ - Td3[Te4[(rk[0] ) & 0xff] & 0xff]; - rrk[1] = - Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ - Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ - Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ - Td3[Te4[(rk[1] ) & 0xff] & 0xff]; - rrk[2] = - Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ - Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ - Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ - Td3[Te4[(rk[2] ) & 0xff] & 0xff]; - rrk[3] = - Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ - Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ - Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ - Td3[Te4[(rk[3] ) & 0xff] & 0xff]; - } - // invert the order of the last round keys - rrk -= 4; - rk += 4; - rrk[0] = rk[0]; - rrk[1] = rk[1]; - rrk[2] = rk[2]; - rrk[3] = rk[3]; - - return Nr; -} - -/* -* Encrypt the plain text into cipher -*/ -void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) -{ - unsigned int s0, s1, s2, s3, t0, t1, t2, t3, *iv; - const unsigned int *rk; - int r; - - rk = pCtx->Ek; - iv = pCtx->Iv; - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(pt ) ^ rk[0]; - s1 = GETU32(pt + 4) ^ rk[1]; - s2 = GETU32(pt + 8) ^ rk[2]; - s3 = GETU32(pt + 12) ^ rk[3]; - if (pCtx->Mode) { - s0 = s0 ^ iv[0]; - s1 = s1 ^ iv[1]; - s2 = s2 ^ iv[2]; - s3 = s3 ^ iv[3]; - } - /* - * Nr - 1 full rounds: - */ - r = pCtx->Nr >> 1; - for (;;) { - t0 = - Te0[(s0 >> 24) ] ^ - Te1[(s1 >> 16) & 0xff] ^ - Te2[(s2 >> 8) & 0xff] ^ - Te3[(s3 ) & 0xff] ^ - rk[4]; - t1 = - Te0[(s1 >> 24) ] ^ - Te1[(s2 >> 16) & 0xff] ^ - Te2[(s3 >> 8) & 0xff] ^ - Te3[(s0 ) & 0xff] ^ - rk[5]; - t2 = - Te0[(s2 >> 24) ] ^ - Te1[(s3 >> 16) & 0xff] ^ - Te2[(s0 >> 8) & 0xff] ^ - Te3[(s1 ) & 0xff] ^ - rk[6]; - t3 = - Te0[(s3 >> 24) ] ^ - Te1[(s0 >> 16) & 0xff] ^ - Te2[(s1 >> 8) & 0xff] ^ - Te3[(s2 ) & 0xff] ^ - rk[7]; - - rk += 8; - if (--r == 0) { - break; - } - - s0 = - Te0[(t0 >> 24) ] ^ - Te1[(t1 >> 16) & 0xff] ^ - Te2[(t2 >> 8) & 0xff] ^ - Te3[(t3 ) & 0xff] ^ - rk[0]; - s1 = - Te0[(t1 >> 24) ] ^ - Te1[(t2 >> 16) & 0xff] ^ - Te2[(t3 >> 8) & 0xff] ^ - Te3[(t0 ) & 0xff] ^ - rk[1]; - s2 = - Te0[(t2 >> 24) ] ^ - Te1[(t3 >> 16) & 0xff] ^ - Te2[(t0 >> 8) & 0xff] ^ - Te3[(t1 ) & 0xff] ^ - rk[2]; - s3 = - Te0[(t3 >> 24) ] ^ - Te1[(t0 >> 16) & 0xff] ^ - Te2[(t1 >> 8) & 0xff] ^ - Te3[(t2 ) & 0xff] ^ - rk[3]; - } - /* - * apply last round and - * map cipher state to byte array block: - */ - s0 = - (Te4[(t0 >> 24) ] & 0xff000000) ^ - (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t3 ) & 0xff] & 0x000000ff) ^ - rk[0]; - PUTU32(ct , s0); - s1 = - (Te4[(t1 >> 24) ] & 0xff000000) ^ - (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t0 ) & 0xff] & 0x000000ff) ^ - rk[1]; - PUTU32(ct + 4, s1); - s2 = - (Te4[(t2 >> 24) ] & 0xff000000) ^ - (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t1 ) & 0xff] & 0x000000ff) ^ - rk[2]; - PUTU32(ct + 8, s2); - s3 = - (Te4[(t3 >> 24) ] & 0xff000000) ^ - (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t2 ) & 0xff] & 0x000000ff) ^ - rk[3]; - PUTU32(ct + 12, s3); - - if (pCtx->Mode) { - iv[0] = s0; - iv[1] = s1; - iv[2] = s2; - iv[3] = s3; - } -} - -/* -* Decrypt the cipher into plain text -*/ -void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) -{ - unsigned int s0, s1, s2, s3, t0, t1, t2, t3, v0, v1, v2, v3, *iv; - const unsigned int *rk; - int r; - - rk = pCtx->Dk; - iv = pCtx->Iv; - /* - * map byte array block to cipher state - * and add initial round key: - */ - v0 = GETU32(ct ); s0 = v0 ^ rk[0]; - v1 = GETU32(ct + 4); s1 = v1 ^ rk[1]; - v2 = GETU32(ct + 8); s2 = v2 ^ rk[2]; - v3 = GETU32(ct + 12); s3 = v3 ^ rk[3]; - /* - * Nr - 1 full rounds: - */ - r = pCtx->Nr >> 1; - for (;;) { - t0 = - Td0[(s0 >> 24) ] ^ - Td1[(s3 >> 16) & 0xff] ^ - Td2[(s2 >> 8) & 0xff] ^ - Td3[(s1 ) & 0xff] ^ - rk[4]; - t1 = - Td0[(s1 >> 24) ] ^ - Td1[(s0 >> 16) & 0xff] ^ - Td2[(s3 >> 8) & 0xff] ^ - Td3[(s2 ) & 0xff] ^ - rk[5]; - t2 = - Td0[(s2 >> 24) ] ^ - Td1[(s1 >> 16) & 0xff] ^ - Td2[(s0 >> 8) & 0xff] ^ - Td3[(s3 ) & 0xff] ^ - rk[6]; - t3 = - Td0[(s3 >> 24) ] ^ - Td1[(s2 >> 16) & 0xff] ^ - Td2[(s1 >> 8) & 0xff] ^ - Td3[(s0 ) & 0xff] ^ - rk[7]; - - rk += 8; - if (--r == 0) { - break; - } - - s0 = - Td0[(t0 >> 24) ] ^ - Td1[(t3 >> 16) & 0xff] ^ - Td2[(t2 >> 8) & 0xff] ^ - Td3[(t1 ) & 0xff] ^ - rk[0]; - s1 = - Td0[(t1 >> 24) ] ^ - Td1[(t0 >> 16) & 0xff] ^ - Td2[(t3 >> 8) & 0xff] ^ - Td3[(t2 ) & 0xff] ^ - rk[1]; - s2 = - Td0[(t2 >> 24) ] ^ - Td1[(t1 >> 16) & 0xff] ^ - Td2[(t0 >> 8) & 0xff] ^ - Td3[(t3 ) & 0xff] ^ - rk[2]; - s3 = - Td0[(t3 >> 24) ] ^ - Td1[(t2 >> 16) & 0xff] ^ - Td2[(t1 >> 8) & 0xff] ^ - Td3[(t0 ) & 0xff] ^ - rk[3]; - } - /* - * apply last round and - * map cipher state to byte array block: - */ - s0 = - (Td4[(t0 >> 24) ] & 0xff000000) ^ - (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ - (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t1 ) & 0xff] & 0x000000ff) ^ - rk[0]; - s1 = - (Td4[(t1 >> 24) ] & 0xff000000) ^ - (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ - (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t2 ) & 0xff] & 0x000000ff) ^ - rk[1]; - s2 = - (Td4[(t2 >> 24) ] & 0xff000000) ^ - (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ - (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t3 ) & 0xff] & 0x000000ff) ^ - rk[2]; - s3 = - (Td4[(t3 >> 24) ] & 0xff000000) ^ - (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ - (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t0 ) & 0xff] & 0x000000ff) ^ - rk[3]; - - if (pCtx->Mode) { - s0 = s0 ^ iv[0]; iv[0] = v0; - s1 = s1 ^ iv[1]; iv[1] = v1; - s2 = s2 ^ iv[2]; iv[2] = v2; - s3 = s3 ^ iv[3]; iv[3] = v3; - } - - PUTU32(pt , s0); - PUTU32(pt + 4, s1); - PUTU32(pt + 8, s2); - PUTU32(pt + 12, s3); -} - -////////////////////////////////////////////////////////////////////////////// -// API functions // -////////////////////////////////////////////////////////////////////////////// - -/* -* initialize AES context -*/ -int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode) -{ - if (pKey == 0 || pCtx == 0 || (KeyLen != KEY128 && KeyLen != KEY192 && KeyLen != KEY256)) - return -1; - - // generate key schedule - pCtx->Nr = AesGenKeySched(pCtx->Ek, pCtx->Dk, pKey, KeyLen); - - // initialize IV - if (pIV != 0) { - pCtx->Iv[0] = GETU32(pIV ); - pCtx->Iv[1] = GETU32(pIV + 4 ); - pCtx->Iv[2] = GETU32(pIV + 8 ); - pCtx->Iv[3] = GETU32(pIV + 12); - } - - // mode - pCtx->Mode = Mode; - - return 0; -} - -/* -* Encrypt plain text -*/ -int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen) -{ - int i; - - if (pData == 0 || pCipher == 0 || pCtx == 0 || (DataLen & 0xf) != 0) - return -1; - - for (i = 0; i < DataLen; i += BLOCKSZ) { - // encrypt block by block - AesEncBlk(pCtx, pData, pCipher); - pCipher += BLOCKSZ; - pData += BLOCKSZ; - } - return DataLen; -} - -/* -* Decrypt cipher -*/ -int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen) -{ - int i; - - if (pData == 0 || pCipher == 0 || pCtx == 0 || (CipherLen & 0xf) != 0) - return -1; - - for (i = 0; i < CipherLen; i += BLOCKSZ) { - // decrypt block by block - AesDecBlk(pCtx, pCipher, pData); - pCipher += BLOCKSZ; - pData += BLOCKSZ; - } - return CipherLen; -} - -////////////////////////////////////////////////////////////////////////////// -// Sample main program // -////////////////////////////////////////////////////////////////////////////// - -#ifndef EMBEDDED -int main() -{ - AesCtx ctx; - unsigned char iv[] = "INI VECTINI VECT"; - unsigned char key[] = "This is a sample AESKey"; - unsigned char databuf[] = "Data : AES Test"; // must be in multiple of 16 - - // initialize context and encrypt data at one end - - if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) - printf("init error\n"); - - if (AesEncrypt(&ctx, databuf, databuf, sizeof databuf) < 0) - printf("error in encryption\n"); - - // initialize context and decrypt cipher at other end - - if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) - printf("init error\n"); - - if (AesDecrypt(&ctx, databuf, databuf, sizeof databuf) < 0) - printf("error in decryption\n"); - - printf("%s\n", databuf); - - return 0; -} -#endif \ No newline at end of file diff --git a/armsrc/aes.h b/armsrc/aes.h deleted file mode 100644 index 85944873..00000000 --- a/armsrc/aes.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -* AES Cryptographic Algorithm Header File. Include this header file in -* your source which uses these given APIs. (This source is kept under -* public domain) -*/ - -// AES context structure -typedef struct { - unsigned int Ek[60]; - unsigned int Dk[60]; - unsigned int Iv[4]; - unsigned char Nr; - unsigned char Mode; -} AesCtx; - -// key length in bytes -#define KEY128 16 -#define KEY192 24 -#define KEY256 32 -// block size in bytes -#define BLOCKSZ 16 -// mode -#define EBC 0 -#define CBC 1 - -// AES API function prototype - -int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode); -int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen); -int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen); \ No newline at end of file diff --git a/armsrc/appmain.c b/armsrc/appmain.c index dbbbe6bd..3c92a7fd 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -10,20 +10,19 @@ // executes. //----------------------------------------------------------------------------- -#include "../common/usb_cdc.h" -#include "../common/cmd.h" +#include "usb_cdc.h" +#include "cmd.h" -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "printf.h" #include "string.h" + #include - #include "legicrf.h" -#include "../include/hitag2.h" - +#include #ifdef WITH_LCD #include "LCD.h" @@ -37,7 +36,7 @@ // is the order in which they go out on the wire. //============================================================================= -#define TOSEND_BUFFER_SIZE (9*MAX_FRAME_SIZE + 1 + 1 + 2) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits +#define TOSEND_BUFFER_SIZE (9*MAX_FRAME_SIZE + 1 + 1 + 2) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits uint8_t ToSend[TOSEND_BUFFER_SIZE]; int ToSendMax; static int ToSendBit; @@ -69,7 +68,7 @@ void ToSendStuffBit(int b) ToSendBit++; - if(ToSendMax >= sizeof(ToSend)) { + if(ToSendMax >= sizeof(ToSend)) { ToSendBit = 0; DbpString("ToSendStuffBit overflowed!"); } @@ -173,7 +172,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 @@ -207,7 +206,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); @@ -218,9 +217,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) @@ -362,7 +361,7 @@ void SamyRun() for (;;) { usb_poll(); - WDT_HIT(); + WDT_HIT(); // Was our button held down or pressed? int button_pressed = BUTTON_HELD(1000); @@ -626,7 +625,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 @@ -669,8 +668,9 @@ void UsbPacketReceived(uint8_t *packet, int len) WriteTItag(c->arg[0],c->arg[1],c->arg[2]); break; case CMD_SIMULATE_TAG_125K: - SimulateTagLowFrequency(c->arg[0], c->arg[1], 0); - //SimulateTagLowFrequencyA(c->arg[0], c->arg[1]); + LED_A_ON(); + SimulateTagLowFrequency(c->arg[0], c->arg[1], 1); + LED_A_OFF(); break; case CMD_LF_SIMULATE_BIDIR: SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]); @@ -792,10 +792,6 @@ 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]); break; @@ -805,17 +801,8 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFAREU_READBL: MifareUReadBlock(c->arg[0],c->d.asBytes); break; - case CMD_MIFAREUC_AUTH1: - MifareUC_Auth1(c->arg[0],c->d.asBytes); - break; - case CMD_MIFAREUC_AUTH2: - MifareUC_Auth2(c->arg[0],c->d.asBytes); - break; case CMD_MIFAREU_READCARD: - MifareUReadCard(c->arg[0],c->arg[1],c->d.asBytes); - break; - case CMD_MIFAREUC_READCARD: - MifareUReadCard(c->arg[0],c->arg[1],c->d.asBytes); + MifareUReadCard(c->arg[0],c->d.asBytes); break; case CMD_MIFARE_READSC: MifareReadSector(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); @@ -871,28 +858,6 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFARE_SNIFFER: 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; - #endif #ifdef WITH_ICLASS @@ -907,7 +872,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; #endif @@ -1036,7 +1001,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; @@ -1066,12 +1031,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 diff --git a/armsrc/apps.h b/armsrc/apps.h index 81124a1a..eafee559 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -14,40 +14,28 @@ #include #include -#include -#include -#include -#include - -#include "../include/common.h" -#include "../include/hitag2.h" -#include "../include/mifare.h" - -//#include -//#include -//#include "des.h" -//#include "aes.h" -#include "../common/desfire.h" -#include "../common/crc32.h" +#include "common.h" +#include "hitag2.h" +#include "mifare.h" // The large multi-purpose buffer, typically used to hold A/D samples, // maybe processed in some way. -#define BIGBUF_SIZE 40000 +#define BIGBUF_SIZE 40000 uint32_t BigBuf[BIGBUF_SIZE / sizeof(uint32_t)]; -#define TRACE_OFFSET 0 -#define TRACE_SIZE 3000 -#define RECV_CMD_OFFSET (TRACE_OFFSET + TRACE_SIZE) -#define MAX_FRAME_SIZE 256 -#define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 1)/ 8) -#define RECV_CMD_PAR_OFFSET (RECV_CMD_OFFSET + MAX_FRAME_SIZE) -#define RECV_RESP_OFFSET (RECV_CMD_PAR_OFFSET + MAX_PARITY_SIZE) -#define RECV_RESP_PAR_OFFSET (RECV_RESP_OFFSET + MAX_FRAME_SIZE) -#define CARD_MEMORY_OFFSET (RECV_RESP_PAR_OFFSET + MAX_PARITY_SIZE) -#define CARD_MEMORY_SIZE 4096 -#define DMA_BUFFER_OFFSET CARD_MEMORY_OFFSET -#define DMA_BUFFER_SIZE CARD_MEMORY_SIZE -#define FREE_BUFFER_OFFSET (CARD_MEMORY_OFFSET + CARD_MEMORY_SIZE) -#define FREE_BUFFER_SIZE (BIGBUF_SIZE - FREE_BUFFER_OFFSET - 1) +#define TRACE_OFFSET 0 +#define TRACE_SIZE 3000 +#define RECV_CMD_OFFSET (TRACE_OFFSET + TRACE_SIZE) +#define MAX_FRAME_SIZE 256 +#define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 1)/ 8) +#define RECV_CMD_PAR_OFFSET (RECV_CMD_OFFSET + MAX_FRAME_SIZE) +#define RECV_RESP_OFFSET (RECV_CMD_PAR_OFFSET + MAX_PARITY_SIZE) +#define RECV_RESP_PAR_OFFSET (RECV_RESP_OFFSET + MAX_FRAME_SIZE) +#define CARD_MEMORY_OFFSET (RECV_RESP_PAR_OFFSET + MAX_PARITY_SIZE) +#define CARD_MEMORY_SIZE 4096 +#define DMA_BUFFER_OFFSET CARD_MEMORY_OFFSET +#define DMA_BUFFER_SIZE CARD_MEMORY_SIZE +#define FREE_BUFFER_OFFSET (CARD_MEMORY_OFFSET + CARD_MEMORY_SIZE) +#define FREE_BUFFER_SIZE (BIGBUF_SIZE - FREE_BUFFER_OFFSET - 1) extern const uint8_t OddByteParity[256]; extern uint8_t *trace; // = (uint8_t *) BigBuf; @@ -76,10 +64,7 @@ void ToSendReset(void); void ListenReaderField(int limit); void AcquireRawAdcSamples125k(int at134khz); void SnoopLFRawAdcSamples(int divisor, int trigger_threshold); -void DoAcquisition125k_internal(int trigger_threshold, bool silent); -void DoAcquisition125k_threshold(int trigger_threshold); -void DoAcquisition125k(); - +void DoAcquisition125k(int trigger_threshold); extern int ToSendMax; extern uint8_t ToSend[]; extern uint32_t BigBuf[]; @@ -144,10 +129,8 @@ void ReadTItag(void); void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc); void AcquireTiType(void); void AcquireRawBitsTI(void); -void SimulateTagLowFrequency( uint16_t period, uint32_t gap, uint8_t ledcontrol); -void SimulateTagLowFrequencyA(int period, int gap); - -void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol); +void SimulateTagLowFrequency(int period, int gap, int ledcontrol); +void CmdHIDsimTAG(int hi, int lo, int ledcontrol); void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol); void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol); void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol); @@ -160,7 +143,6 @@ 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); @@ -181,7 +163,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data); void ReaderIso14443a(UsbCommand * c); // Also used in iclass.c bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t len, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); -void GetParity(const uint8_t * pbtCmd, uint16_t len, uint8_t *parity); +void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *parity); void iso14a_set_trigger(bool enable); void iso14a_clear_trace(); void iso14a_set_tracing(bool enable); @@ -195,9 +177,7 @@ void ReaderMifare(bool first_try); int32_t dist_nt(uint32_t nt1, uint32_t nt2); void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); void MifareUReadBlock(uint8_t arg0,uint8_t *datain); -void MifareUC_Auth1(uint8_t arg0, uint8_t *datain); -void MifareUC_Auth2(uint32_t arg0, uint8_t *datain); -void MifareUReadCard(uint8_t arg0, int Pages, uint8_t *datain); +void MifareUReadCard(uint8_t arg0,uint8_t *datain); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0,uint8_t *datain); @@ -214,36 +194,6 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareCIdent(); // is "magic chinese" card? -//desfire -void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain); -void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); - -// mifaredesfire.h -bool InitDesfireCard(); -void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); -void MifareDesfireGetInformation(); -void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); -void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); -int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); -size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); -void OnSuccess(); -void OnError(); - - - -// 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 void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); diff --git a/armsrc/crapto1.c b/armsrc/crapto1.c index c0a7fc32..9d491d12 100644 --- a/armsrc/crapto1.c +++ b/armsrc/crapto1.c @@ -44,12 +44,12 @@ static void quicksort(uint32_t* const start, uint32_t* const stop) else if(*rit > *start) --rit; else - *it ^= ( (*it ^= *rit ), *rit ^= *it); + *it ^= (*it ^= *rit, *rit ^= *it); if(*rit >= *start) --rit; if(rit != start) - *rit ^= ( (*rit ^= *start), *start ^= *rit); + *rit ^= (*rit ^= *start, *start ^= *rit); quicksort(start, rit - 1); quicksort(rit + 1, stop); @@ -454,7 +454,7 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) odd = lfsr_prefix_ks(ks, 1); even = lfsr_prefix_ks(ks, 0); - + s = statelist = malloc((sizeof *statelist) << 20); if(!s || !odd || !even) { free(statelist); diff --git a/armsrc/des.c b/armsrc/des.c deleted file mode 100644 index 0a27503e..00000000 --- a/armsrc/des.c +++ /dev/null @@ -1,383 +0,0 @@ -/* des.c */ -/* - This file is part of the ARM-Crypto-Lib. - Copyright (C) 2006-2010 Daniel Otte (daniel.otte@rub.de) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** - * \file des.c - * \author Daniel Otte - * \email daniel.otte@rub.de - * \date 2007-06-16 - * \brief DES and EDE-DES implementation - * \license GPLv3 or later - * - */ -#include -#include - -const uint8_t sbox[256] = { - /* S-box 1 */ - 0xE4, 0xD1, 0x2F, 0xB8, 0x3A, 0x6C, 0x59, 0x07, - 0x0F, 0x74, 0xE2, 0xD1, 0xA6, 0xCB, 0x95, 0x38, - 0x41, 0xE8, 0xD6, 0x2B, 0xFC, 0x97, 0x3A, 0x50, - 0xFC, 0x82, 0x49, 0x17, 0x5B, 0x3E, 0xA0, 0x6D, - /* S-box 2 */ - 0xF1, 0x8E, 0x6B, 0x34, 0x97, 0x2D, 0xC0, 0x5A, - 0x3D, 0x47, 0xF2, 0x8E, 0xC0, 0x1A, 0x69, 0xB5, - 0x0E, 0x7B, 0xA4, 0xD1, 0x58, 0xC6, 0x93, 0x2F, - 0xD8, 0xA1, 0x3F, 0x42, 0xB6, 0x7C, 0x05, 0xE9, - /* S-box 3 */ - 0xA0, 0x9E, 0x63, 0xF5, 0x1D, 0xC7, 0xB4, 0x28, - 0xD7, 0x09, 0x34, 0x6A, 0x28, 0x5E, 0xCB, 0xF1, - 0xD6, 0x49, 0x8F, 0x30, 0xB1, 0x2C, 0x5A, 0xE7, - 0x1A, 0xD0, 0x69, 0x87, 0x4F, 0xE3, 0xB5, 0x2C, - /* S-box 4 */ - 0x7D, 0xE3, 0x06, 0x9A, 0x12, 0x85, 0xBC, 0x4F, - 0xD8, 0xB5, 0x6F, 0x03, 0x47, 0x2C, 0x1A, 0xE9, - 0xA6, 0x90, 0xCB, 0x7D, 0xF1, 0x3E, 0x52, 0x84, - 0x3F, 0x06, 0xA1, 0xD8, 0x94, 0x5B, 0xC7, 0x2E, - /* S-box 5 */ - 0x2C, 0x41, 0x7A, 0xB6, 0x85, 0x3F, 0xD0, 0xE9, - 0xEB, 0x2C, 0x47, 0xD1, 0x50, 0xFA, 0x39, 0x86, - 0x42, 0x1B, 0xAD, 0x78, 0xF9, 0xC5, 0x63, 0x0E, - 0xB8, 0xC7, 0x1E, 0x2D, 0x6F, 0x09, 0xA4, 0x53, - /* S-box 6 */ - 0xC1, 0xAF, 0x92, 0x68, 0x0D, 0x34, 0xE7, 0x5B, - 0xAF, 0x42, 0x7C, 0x95, 0x61, 0xDE, 0x0B, 0x38, - 0x9E, 0xF5, 0x28, 0xC3, 0x70, 0x4A, 0x1D, 0xB6, - 0x43, 0x2C, 0x95, 0xFA, 0xBE, 0x17, 0x60, 0x8D, - /* S-box 7 */ - 0x4B, 0x2E, 0xF0, 0x8D, 0x3C, 0x97, 0x5A, 0x61, - 0xD0, 0xB7, 0x49, 0x1A, 0xE3, 0x5C, 0x2F, 0x86, - 0x14, 0xBD, 0xC3, 0x7E, 0xAF, 0x68, 0x05, 0x92, - 0x6B, 0xD8, 0x14, 0xA7, 0x95, 0x0F, 0xE2, 0x3C, - /* S-box 8 */ - 0xD2, 0x84, 0x6F, 0xB1, 0xA9, 0x3E, 0x50, 0xC7, - 0x1F, 0xD8, 0xA3, 0x74, 0xC5, 0x6B, 0x0E, 0x92, - 0x7B, 0x41, 0x9C, 0xE2, 0x06, 0xAD, 0xF3, 0x58, - 0x21, 0xE7, 0x4A, 0x8D, 0xFC, 0x90, 0x35, 0x6B -}; - -const uint8_t e_permtab[] ={ - 4, 6, /* 4 bytes in 6 bytes out*/ - 32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1 -}; - -const uint8_t p_permtab[] ={ - 4, 4, /* 32 bit -> 32 bit */ - 16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25 -}; - -const uint8_t ip_permtab[] ={ - 8, 8, /* 64 bit -> 64 bit */ - 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7 -}; - -const uint8_t inv_ip_permtab[] ={ - 8, 8, /* 64 bit -> 64 bit */ - 40, 8, 48, 16, 56, 24, 64, 32, - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25 -}; - -const uint8_t pc1_permtab[] ={ - 8, 7, /* 64 bit -> 56 bit*/ - 57, 49, 41, 33, 25, 17, 9, - 1, 58, 50, 42, 34, 26, 18, - 10, 2, 59, 51, 43, 35, 27, - 19, 11, 3, 60, 52, 44, 36, - 63, 55, 47, 39, 31, 23, 15, - 7, 62, 54, 46, 38, 30, 22, - 14, 6, 61, 53, 45, 37, 29, - 21, 13, 5, 28, 20, 12, 4 -}; - -const uint8_t pc2_permtab[] ={ - 7, 6, /* 56 bit -> 48 bit */ - 14, 17, 11, 24, 1, 5, - 3, 28, 15, 6, 21, 10, - 23, 19, 12, 4, 26, 8, - 16, 7, 27, 20, 13, 2, - 41, 52, 31, 37, 47, 55, - 30, 40, 51, 45, 33, 48, - 44, 49, 39, 56, 34, 53, - 46, 42, 50, 36, 29, 32 -}; - -const uint8_t splitin6bitword_permtab[] = { - 8, 8, /* 64 bit -> 64 bit */ - 64, 64, 1, 6, 2, 3, 4, 5, - 64, 64, 7, 12, 8, 9, 10, 11, - 64, 64, 13, 18, 14, 15, 16, 17, - 64, 64, 19, 24, 20, 21, 22, 23, - 64, 64, 25, 30, 26, 27, 28, 29, - 64, 64, 31, 36, 32, 33, 34, 35, - 64, 64, 37, 42, 38, 39, 40, 41, - 64, 64, 43, 48, 44, 45, 46, 47 -}; - -const uint8_t shiftkey_permtab[] = { - 7, 7, /* 56 bit -> 56 bit */ - 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 1, - 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 29 -}; - -const uint8_t shiftkeyinv_permtab[] = { - 7, 7, - 28, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, - 56, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55 -}; - -/* -1 0 -1 0 -2 1 -2 1 -2 1 -2 1 -2 1 -2 1 ----- -1 0 -2 1 -2 1 -2 1 -2 1 -2 1 -2 1 -1 0 -*/ -#define ROTTABLE 0x7EFC -#define ROTTABLE_INV 0x3F7E -/******************************************************************************/ - -void permute(const uint8_t *ptable, const uint8_t *in, uint8_t *out){ - uint8_t ob; /* in-bytes and out-bytes */ - uint8_t byte, bit; /* counter for bit and byte */ - ob = ptable[1]; - ptable = &(ptable[2]); - for(byte=0; byte>(x%8)) ){ - t|=0x01; - } - } - out[byte]=t; - } -} - -/******************************************************************************/ - -void changeendian32(uint32_t * a){ - *a = (*a & 0x000000FF) << 24 | - (*a & 0x0000FF00) << 8 | - (*a & 0x00FF0000) >> 8 | - (*a & 0xFF000000) >> 24; -} - -/******************************************************************************/ -static inline -void shiftkey(uint8_t *key){ - uint8_t k[7]; - memcpy(k, key, 7); - permute((uint8_t*)shiftkey_permtab, k, key); -} - -/******************************************************************************/ -static inline -void shiftkey_inv(uint8_t *key){ - uint8_t k[7]; - memcpy(k, key, 7); - permute((uint8_t*)shiftkeyinv_permtab, k, key); - -} - -/******************************************************************************/ -static inline -uint64_t splitin6bitwords(uint64_t a){ - uint64_t ret=0; - a &= 0x0000ffffffffffffLL; - permute((uint8_t*)splitin6bitword_permtab, (uint8_t*)&a, (uint8_t*)&ret); - return ret; -} - -/******************************************************************************/ - -static inline -uint8_t substitute(uint8_t a, uint8_t * sbp){ - uint8_t x; - x = sbp[a>>1]; - x = (a&1)?x&0x0F:x>>4; - return x; - -} - -/******************************************************************************/ - -uint32_t des_f(uint32_t r, uint8_t* kr){ - uint8_t i; - uint32_t t=0,ret; - uint64_t data; - uint8_t *sbp; /* sboxpointer */ - permute((uint8_t*)e_permtab, (uint8_t*)&r, (uint8_t*)&data); - for(i=0; i<7; ++i) - ((uint8_t*)&data)[i] ^= kr[i]; - - /* Sbox substitution */ - data = splitin6bitwords(data); - sbp=(uint8_t*)sbox; - for(i=0; i<8; ++i){ - uint8_t x; - x = substitute(((uint8_t*)&data)[i], sbp); - t<<=4; - t |= x; - sbp += 32; - } - changeendian32(&t); - - permute((uint8_t*)p_permtab,(uint8_t*)&t, (uint8_t*)&ret); - - return ret; -} - -/******************************************************************************/ - -void des_enc(void* out, const void* in, const void* key){ -#define R *((uint32_t*)&(data[4])) -#define L *((uint32_t*)&(data[0])) - - uint8_t data[8],kr[6],k[7]; - uint8_t i; - - permute((uint8_t*)ip_permtab, (uint8_t*)in, data); - permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k); - for(i=0; i<8; ++i){ - shiftkey(k); - if(ROTTABLE&((1<<((i<<1)+0))) ) - shiftkey(k); - permute((uint8_t*)pc2_permtab, k, kr); - L ^= des_f(R, kr); - - shiftkey(k); - if(ROTTABLE&((1<<((i<<1)+1))) ) - shiftkey(k); - permute((uint8_t*)pc2_permtab, k, kr); - R ^= des_f(L, kr); - - } - /* L <-> R*/ - R ^= L; - L ^= R; - R ^= L; - - permute((uint8_t*)inv_ip_permtab, data, (uint8_t*)out); -} - -/******************************************************************************/ - -void des_dec(void* out, const void* in, const uint8_t* key){ -#define R *((uint32_t*)&(data[4])) -#define L *((uint32_t*)&(data[0])) - - uint8_t data[8],kr[6],k[7]; - int8_t i; - permute((uint8_t*)ip_permtab, (uint8_t*)in, data); - permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k); - for(i=7; i>=0; --i){ - - permute((uint8_t*)pc2_permtab, k, kr); - L ^= des_f(R, kr); - shiftkey_inv(k); - if(ROTTABLE&((1<<((i<<1)+1))) ){ - shiftkey_inv(k); - } - - permute((uint8_t*)pc2_permtab, k, kr); - R ^= des_f(L, kr); - shiftkey_inv(k); - if(ROTTABLE&((1<<((i<<1)+0))) ){ - shiftkey_inv(k); - } - - } - /* L <-> R*/ - R ^= L; - L ^= R; - R ^= L; - - permute((uint8_t*)inv_ip_permtab, data, (uint8_t*)out); -} - -/******************************************************************************/ - -void tdes_enc(void* out, void* in, const void* key){ - des_enc(out, in, (uint8_t*)key + 0); - des_dec(out, out, (uint8_t*)key + 8); - des_enc(out, out, (uint8_t*)key +16); -} - -/******************************************************************************/ - -void tdes_dec(void* out, void* in, const uint8_t* key){ - des_dec(out, in, (uint8_t*)key +16); - des_enc(out, out, (uint8_t*)key + 8); - des_dec(out, out, (uint8_t*)key + 0); -} - -/******************************************************************************/ - - diff --git a/armsrc/des.h b/armsrc/des.h deleted file mode 100644 index 652886fd..00000000 --- a/armsrc/des.h +++ /dev/null @@ -1,107 +0,0 @@ -/* des.h */ -/* - This file is part of the ARM-Crypto-Lib. - Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** - * \file des.h - * \author Daniel Otte - * \date 2007-06-16 - * \brief des and tdes declarations - * \license GPLv3 or later - * - */ -#ifndef DES_H_ -#define DES_H_ - -/* the FIPS 46-3 (1999-10-25) name for triple DES is triple data encryption algorithm so TDEA. - * Also we only implement the three key mode */ - -/** \def tdea_enc - * \brief defining an alias for void tdes_enc(void* out, const void* in, const void* key) - */ - -/** \def tdea_dec - * \brief defining an alias for void tdes_dec(void* out, const void* in, const void* key) - */ - -#define tdea_enc tdes_enc -#define tdea_dec tdes_dec - -/** \fn void des_enc(void* out, const void* in, const void* key) - * \brief encrypt a block with DES - * - * This function encrypts a block of 64 bits (8 bytes) with the DES algorithm. - * Key expansion is done automatically. The key is 64 bits long, but note that - * only 56 bits are used (the LSB of each byte is dropped). The input and output - * blocks may overlap. - * - * \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to - * \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from - * \param key pointer to the key (64 bit = 8 byte) - */ -void des_enc(void* out, const void* in, const void* key); - -/** \fn void des_dec(void* out, const void* in, const void* key) - * \brief decrypt a block with DES - * - * This function decrypts a block of 64 bits (8 bytes) with the DES algorithm. - * Key expansion is done automatically. The key is 64 bits long, but note that - * only 56 bits are used (the LSB of each byte is dropped). The input and output - * blocks may overlap. - * - * \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to - * \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from - * \param key pointer to the key (64 bit = 8 byte) - */ -void des_dec(void* out, const void* in, const void* key); - -/** \fn void tdes_enc(void* out, const void* in, const void* key) - * \brief encrypt a block with Tripple-DES - * - * This function encrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE) - * algorithm. Key expansion is done automatically. The key is 192 bits long, but - * note that only 178 bits are used (the LSB of each byte is dropped). The input - * and output blocks may overlap. - * - * \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to - * \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from - * \param key pointer to the key (192 bit = 24 byte) - */ -void tdes_enc(void* out, const void* in, const void* key); - -/** \fn void tdes_dec(void* out, const void* in, const void* key) - * \brief decrypt a block with Tripple-DES - * - * This function decrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE) - * algorithm. Key expansion is done automatically. The key is 192 bits long, but - * note that only 178 bits are used (the LSB of each byte is dropped). The input - * and output blocks may overlap. - * - * \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to - * \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from - * \param key pointer to the key (192 bit = 24 byte) - */ - void tdes_dec(void* out, const void* in, const void* key); - -#endif /*DES_H_*/ - -// Copied from des.h in desfire imp. -typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */ -typedef unsigned long DES3_KS[48][2]; /* Triple-DES key schedule */ - - -extern int Asmversion; /* 1 if we're linked with an asm version, 0 if C */ diff --git a/armsrc/desfire_crypto.c b/armsrc/desfire_crypto.c deleted file mode 100644 index 9ea07371..00000000 --- a/armsrc/desfire_crypto.c +++ /dev/null @@ -1,642 +0,0 @@ -/*- - * 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 - * - * $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 deleted file mode 100644 index 698f11e3..00000000 --- a/armsrc/desfire_crypto.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __DESFIRE_CRYPTO_H -#define __DESFIRE_CRYPTO_H - -#include -#include -#include -#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 deleted file mode 100644 index b3aa14e9..00000000 --- a/armsrc/desfire_key.c +++ /dev/null @@ -1,155 +0,0 @@ -/*- - * 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 - * - * $Id$ - */ -#include -#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 deleted file mode 100644 index 0d99903e..00000000 --- a/armsrc/desfire_key.h +++ /dev/null @@ -1,17 +0,0 @@ -#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 diff --git a/armsrc/epa.c b/armsrc/epa.c index 0bbd2dd7..bec79e61 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -13,7 +13,7 @@ #include "iso14443a.h" #include "epa.h" -#include "../common/cmd.h" +#include "cmd.h" // Protocol and Parameter Selection Request // use regular (1x) speed in both directions @@ -224,7 +224,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,15 +252,13 @@ 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; } // increase the timeout (at least some cards really do need this!) iso14a_set_timeout(0x0002FFFF); - Dbprintf("epa: Epic!"); // read the CardAccess file // this array will hold the CardAccess file @@ -268,13 +266,10 @@ 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 @@ -286,8 +281,6 @@ 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); @@ -309,7 +302,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); } //----------------------------------------------------------------------------- @@ -432,7 +425,7 @@ int EPA_Setup() // power up the field iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - + iso14a_set_timeout(10500); // select the card diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 32e0500e..077b378a 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -9,8 +9,7 @@ // Routines to load the FPGA image, and then to configure the FPGA's major // mode once it is configured. //----------------------------------------------------------------------------- - -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index dc4c4232..27a5d508 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -16,10 +16,10 @@ // (c) 2012 Roel Verdult //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" -#include "../include/hitag2.h" +#include "hitag2.h" #include "string.h" static bool bQuiet; @@ -744,7 +744,7 @@ void SnoopHitag(uint32_t type) { // Set up eavesdropping mode, frequency divisor which will drive the FPGA // and analog mux selection. FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); @@ -968,7 +968,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { // Set up simulator mode, frequency divisor which will drive the FPGA // and analog mux selection. FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); @@ -987,7 +987,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, @@ -1140,7 +1140,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { case RHT2F_PASSWORD: { Dbprintf("List identifier in password mode"); memcpy(password,htd->pwd.password,4); - blocknr = 0; + blocknr = 0; bQuitTraceFull = false; bQuiet = false; bPwd = false; @@ -1158,7 +1158,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { case RHT2F_CRYPTO: { DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); // 4 or 6 ?? + memcpy(key,htd->crypto.key,4); //HACK; 4 or 6?? I read both in the code. Dbhexdump(6,key,false); blocknr = 0; bQuiet = false; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index cf1931fd..625cf39b 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -36,7 +36,7 @@ // //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" @@ -45,11 +45,9 @@ // Needed for CRC in emulation mode; // same construction as in ISO 14443; // different initial value (CRC_ICLASS) -#include "../common/iso14443crc.h" -#include "../common/iso15693tools.h" +#include "iso14443crc.h" #include "iso15693tools.h" - static int timeout = 4096; @@ -353,7 +351,7 @@ static struct { SUB_SECOND_HALF, SUB_BOTH } sub; - uint8_t *output; + uint8_t *output; } Demod; static RAMFUNC int ManchesterDecoding(int v) @@ -435,7 +433,7 @@ static RAMFUNC int ManchesterDecoding(int v) else { modulation = bit & Demod.syncBit; modulation |= ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; - + Demod.samples += 4; if(Demod.posCount==0) { @@ -645,7 +643,7 @@ void RAMFUNC SnoopIClass(void) uint8_t *readerToTagCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); // The response (tag -> reader) that we're receiving. uint8_t *tagToReaderResponse = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); - + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // reset traceLen to 0 @@ -744,7 +742,7 @@ void RAMFUNC SnoopIClass(void) //if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,TRUE)) break; //if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break; - if(tracing) { + if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Uart.output, Uart.byteCnt, parity); LogTrace(Uart.output,Uart.byteCnt, (GetCountSspClk()-time_0) << 4, (GetCountSspClk()-time_0) << 4, parity, TRUE); @@ -768,7 +766,7 @@ void RAMFUNC SnoopIClass(void) rsamples = samples - Demod.samples; LED_B_ON(); - if(tracing) { + if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); LogTrace(Demod.output, Demod.len, (GetCountSspClk()-time_0) << 4, (GetCountSspClk()-time_0) << 4, parity, FALSE); @@ -1267,18 +1265,18 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int if (wait) { 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(); + } } @@ -1361,19 +1359,19 @@ 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 - if (tracing) { + // Store reader command in buffer + if (tracing) { uint8_t par[MAX_PARITY_SIZE]; GetParity(frame, len, par); LogTrace(frame, len, rsamples, rsamples, par, TRUE); @@ -1408,7 +1406,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!! @@ -1433,10 +1431,10 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer) int samples = 0; if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return FALSE; rsamples += samples; - if (tracing){ - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(receivedAnswer, Demod.len, parity); - LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,FALSE); + if (tracing) { + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(receivedAnswer, Demod.len, parity); + LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,FALSE); } if(samples == 0) return FALSE; return Demod.len; @@ -1539,7 +1537,7 @@ void ReaderIClass(uint8_t arg0) { uint8_t card_data[24]={0}; uint8_t last_csn[8]={0}; - + int read_status= 0; bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; bool get_cc = arg0 & FLAG_ICLASS_READER_GET_CC; @@ -1554,7 +1552,7 @@ void ReaderIClass(uint8_t arg0) { DbpString("Trace full"); break; } - WDT_HIT(); + WDT_HIT(); read_status = handshakeIclassTag(card_data); @@ -1562,24 +1560,24 @@ void ReaderIClass(uint8_t arg0) { if(read_status == 1) datasize = 8; if(read_status == 2) datasize = 16; - 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(!get_cc || (get_cc && read_status == 2)) { - cmd_send(CMD_ACK,read_status,0,0,card_data,datasize); + cmd_send(CMD_ACK,read_status,0,0,card_data,datasize); if(abort_after_read) { 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); } //If 'get_cc' was specified and we didn't get a CC, we'll just keep trying... } - LED_B_OFF(); + LED_B_OFF(); } cmd_send(CMD_ACK,0,0,0,card_data, 0); LED_A_OFF(); @@ -1614,14 +1612,14 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { } memory; uint8_t* resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); - + setupIclassReader(); while(!BUTTON_PRESS()) { WDT_HIT(); - + if(traceLen > TRACE_SIZE) { DbpString("Trace full"); break; @@ -1630,20 +1628,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)) { @@ -1651,30 +1649,30 @@ 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(); - //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]); }else{ Dbprintf("Failed to dump block %d", block); @@ -1702,10 +1700,10 @@ void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, uint8_ uint16_t crc = 0; - uint8_t* resp = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); + 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 index 775c583a..e9483189 100644 --- a/armsrc/iso14443.c +++ b/armsrc/iso14443.c @@ -10,12 +10,12 @@ // supported. //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "../common/iso14443crc.h" +#include "iso14443crc.h" //static void GetSamplesFor14443(int weTx, int n); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 8399c6f8..c2f809fe 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -10,12 +10,13 @@ // Routines to support ISO 14443 type A. //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "../common/cmd.h" -#include "../common/iso14443crc.h" +#include "cmd.h" + +#include "iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" @@ -169,7 +170,7 @@ byte_t oddparity (const byte_t bt) return OddByteParity[bt]; } -void GetParity(const uint8_t * pbtCmd, uint16_t iLen, uint8_t *par) +void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) { uint16_t paritybit_cnt = 0; uint16_t paritybyte_cnt = 0; @@ -179,15 +180,15 @@ void GetParity(const uint8_t * pbtCmd, uint16_t iLen, uint8_t *par) // Generate the parity bits parityBits |= ((OddByteParity[pbtCmd[i]]) << (7-paritybit_cnt)); if (paritybit_cnt == 7) { - par[paritybyte_cnt] = parityBits; // save 8 Bits parity - parityBits = 0; // and advance to next Parity Byte + par[paritybyte_cnt] = parityBits; // save 8 Bits parity + parityBits = 0; // and advance to next Parity Byte paritybyte_cnt++; paritybit_cnt = 0; } else { - paritybit_cnt++; + paritybit_cnt++; } } - + // save remaining parity bits par[paritybyte_cnt] = parityBits; @@ -203,7 +204,7 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ { if (!tracing) return FALSE; - uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity + uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity uint16_t duration = timestamp_end - timestamp_start; // Return when trace is full @@ -218,7 +219,7 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ // 16 bits data length (little endian, Highest Bit used as readerToTag flag) // y Bytes data // x Bytes parity (one byte per 8 bytes data) - + // timestamp (start) trace[traceLen++] = ((timestamp_start >> 0) & 0xff); trace[traceLen++] = ((timestamp_start >> 8) & 0xff); @@ -228,28 +229,28 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ // duration trace[traceLen++] = ((duration >> 0) & 0xff); trace[traceLen++] = ((duration >> 8) & 0xff); - + // data length trace[traceLen++] = ((iLen >> 0) & 0xff); trace[traceLen++] = ((iLen >> 8) & 0xff); - + // readerToTag flag if (!readerToTag) { trace[traceLen - 1] |= 0x80; - } + } // data bytes if (btBytes != NULL && iLen != 0) { memcpy(trace + traceLen, btBytes, iLen); } - traceLen += iLen; - + traceLen += iLen; + // parity bytes if (parity != NULL && iLen != 0) { memcpy(trace + traceLen, parity, num_paritybytes); } traceLen += num_paritybytes; - + return TRUE; } @@ -307,7 +308,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.twoBits = (Uart.twoBits << 8) | bit; - if (Uart.state == STATE_UNSYNCD) { // not yet synced + if (Uart.state == STATE_UNSYNCD) { // not yet synced if (Uart.highCnt < 7) { // wait for a stable unmodulated signal if (Uart.twoBits == 0xffff) { @@ -315,7 +316,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) } else { Uart.highCnt = 0; } - } else { + } else { Uart.syncBit = 0xFFFF; // not set // look for 00xx1111 (the start bit) if ((Uart.twoBits & 0x6780) == 0x0780) Uart.syncBit = 7; @@ -355,9 +356,9 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if((Uart.len & 0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits - Uart.parityBits = 0; + if((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + Uart.parityBits = 0; } } } @@ -374,32 +375,32 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if ((Uart.len & 0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + if ((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits Uart.parityBits = 0; } } } else { // no modulation in both halves - Sequence Y if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication Uart.state = STATE_UNSYNCD; - Uart.bitCount--; // last "0" was part of EOC sequence - Uart.shiftReg <<= 1; // drop it - if(Uart.bitCount > 0) { // if we decoded some bits - Uart.shiftReg >>= (9 - Uart.bitCount); // right align them - Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); // add last byte to the output - Uart.parityBits <<= 1; // add a (void) parity bit - Uart.parityBits <<= (8 - (Uart.len & 0x0007)); // left align parity bits - Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store it - return TRUE; - } else if (Uart.len & 0x0007) { // there are some parity bits to store - Uart.parityBits <<= (8 - (Uart.len & 0x0007)); // left align remaining parity bits - Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them + Uart.bitCount--; // last "0" was part of EOC sequence + Uart.shiftReg <<= 1; // drop it + if(Uart.bitCount > 0) { // if we decoded some bits + Uart.shiftReg >>= (9 - Uart.bitCount); // right align them + Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); // add last byte to the output + Uart.parityBits <<= 1; // add a (void) parity bit + Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align parity bits + Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store it + return TRUE; + } else if (Uart.len & 0x0007) { // there are some parity bits to store + Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align remaining parity bits + Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them } - if ( Uart.len) { - return TRUE; // we are finished with decoding the raw data sequence + if (Uart.len) { + return TRUE; // we are finished with decoding the raw data sequence } else { UartReset(); // Nothing receiver - start over - } + } } if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC UartReset(); @@ -414,8 +415,8 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if ((Uart.len & 0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + if ((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits Uart.parityBits = 0; } } @@ -423,7 +424,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) } } - } + } return FALSE; // not finished yet, need more data } @@ -527,8 +528,8 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; - if((Demod.len & 0x0007) == 0) { // every 8 data bytes - Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits + if((Demod.len&0x0007) == 0) { // every 8 data bytes + Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits Demod.parityBits = 0; } } @@ -543,26 +544,26 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; - if ((Demod.len & 0x0007) == 0) { // every 8 data bytes - Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits1 + if ((Demod.len&0x0007) == 0) { // every 8 data bytes + Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits1 Demod.parityBits = 0; } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1); } else { // no modulation in both halves - End of communication - if(Demod.bitCount > 0) { // there are some remaining data bits - Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits - Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output - Demod.parityBits <<= 1; // add a (void) parity bit - Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them - return TRUE; - } else if (Demod.len & 0x0007) { // there are some parity bits to store - Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them - } - if (Demod.len) { - return TRUE; // we are finished with decoding the raw data sequence + if(Demod.bitCount > 0) { // there are some remaining data bits + Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits + Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output + Demod.parityBits <<= 1; // add a (void) parity bit + Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits + Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + return TRUE; + } else if (Demod.len & 0x0007) { // there are some parity bits to store + Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits + Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + } + if (Demod.len) { + return TRUE; // we are finished with decoding the raw data sequence } else { // nothing received. Start over DemodReset(); } @@ -627,10 +628,10 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // Set up the demodulator for tag -> reader responses. DemodInit(receivedResponse, receivedResponsePar); - + // Set up the demodulator for the reader -> tag commands UartInit(receivedCmd, receivedCmdPar); - + // Setup and start DMA. FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); @@ -687,12 +688,12 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) triggered = TRUE; if(triggered) { - if (!LogTrace(receivedCmd, - Uart.len, - Uart.startTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, - Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, - Uart.parity, - TRUE)) break; + if (!LogTrace(receivedCmd, + Uart.len, + Uart.startTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, + Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, + Uart.parity, + TRUE)) break; } /* And ready to receive another command. */ UartReset(); @@ -709,12 +710,12 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { if(ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { LED_B_ON(); - if (!LogTrace(receivedResponse, - Demod.len, - Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, - Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, - Demod.parity, - FALSE)) break; + if (!LogTrace(receivedResponse, + Demod.len, + Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, + Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, + Demod.parity, + FALSE)) break; if ((!triggered) && (param & 0x01)) triggered = TRUE; @@ -745,7 +746,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { //----------------------------------------------------------------------------- // Prepare tag messages //----------------------------------------------------------------------------- -static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity) +static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity) { ToSendReset(); @@ -763,7 +764,7 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *pa ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; - for( uint16_t i = 0; i < len; i++) { + for(uint16_t i = 0; i < len; i++) { uint8_t b = cmd[i]; // Data bits @@ -1034,8 +1035,8 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // 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, + 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 // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) // TC(1) = 0x02: CID supported, NAD not supported @@ -1091,7 +1092,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) // buffers used on software Uart: uint8_t *receivedCmd = ((uint8_t *)BigBuf) + RECV_CMD_OFFSET; uint8_t *receivedCmdPar = ((uint8_t *)BigBuf) + RECV_CMD_PAR_OFFSET; - + cmdsRecvd = 0; tag_response_info_t* p_response; @@ -1101,7 +1102,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) if(!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { DbpString("Button press"); - break; + break; } p_response = NULL; @@ -1323,14 +1324,14 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing } } - NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); + NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); } //----------------------------------------------------------------------------- // Prepare reader command (in bits, support short frames) to send to FPGA //----------------------------------------------------------------------------- -void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, uint16_t bits, const uint8_t *parity) +void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8_t *parity) { int i, j; int last; @@ -1411,7 +1412,7 @@ void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, uint16_t bits, const uint //----------------------------------------------------------------------------- // Prepare reader command to send to FPGA //----------------------------------------------------------------------------- -void CodeIso14443aAsReaderPar(const uint8_t * cmd, uint16_t len, const uint8_t *parity) +void CodeIso14443aAsReaderPar(const uint8_t *cmd, uint16_t len, const uint8_t *parity) { CodeIso14443aBitsAsReaderPar(cmd, len*8, parity); } @@ -1595,7 +1596,7 @@ int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool correctionNeeded){ GetParity(resp, respLen, par); return EmSendCmdExPar(resp, respLen, correctionNeeded, par); } - + int EmSendCmd(uint8_t *resp, uint16_t respLen){ uint8_t par[MAX_PARITY_SIZE]; GetParity(resp, respLen, par); @@ -1610,16 +1611,16 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity) { if (tracing) { - // we cannot exactly measure the end and start of a received command from reader. However we know that the delay from - // end of the received command to start of the tag's (simulated by us) answer is n*128+20 or n*128+84 resp. - // with n >= 9. The start of the tags answer can be measured and therefore the end of the received command be calculated: - uint16_t reader_modlen = reader_EndTime - reader_StartTime; - uint16_t approx_fdt = tag_StartTime - reader_EndTime; - uint16_t exact_fdt = (approx_fdt - 20 + 32)/64 * 64 + 20; - reader_EndTime = tag_StartTime - exact_fdt; - reader_StartTime = reader_EndTime - reader_modlen; - if (!LogTrace(reader_data, reader_len, reader_StartTime, reader_EndTime, reader_Parity, TRUE)) { - return FALSE; + // we cannot exactly measure the end and start of a received command from reader. However we know that the delay from + // end of the received command to start of the tag's (simulated by us) answer is n*128+20 or n*128+84 resp. + // with n >= 9. The start of the tags answer can be measured and therefore the end of the received command be calculated: + uint16_t reader_modlen = reader_EndTime - reader_StartTime; + uint16_t approx_fdt = tag_StartTime - reader_EndTime; + uint16_t exact_fdt = (approx_fdt - 20 + 32)/64 * 64 + 20; + reader_EndTime = tag_StartTime - exact_fdt; + reader_StartTime = reader_EndTime - reader_modlen; + if (!LogTrace(reader_data, reader_len, reader_StartTime, reader_EndTime, reader_Parity, TRUE)) { + return FALSE; } else return(!LogTrace(tag_data, tag_len, tag_StartTime, tag_EndTime, tag_Parity, FALSE)); } else { return TRUE; @@ -1643,7 +1644,7 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive // Now get the answer from the card DemodInit(receivedResponse, receivedResponsePar); - + // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -1685,23 +1686,23 @@ void ReaderTransmitPar(uint8_t* frame, uint16_t len, uint8_t *par, uint32_t *tim void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing) { - // Generate parity and redirect - uint8_t par[MAX_PARITY_SIZE]; - GetParity(frame, len/8, par); - ReaderTransmitBitsPar(frame, len, par, timing); + // Generate parity and redirect + uint8_t par[MAX_PARITY_SIZE]; + GetParity(frame, len/8, par); + ReaderTransmitBitsPar(frame, len, par, timing); } void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing) { - // Generate parity and redirect - uint8_t par[MAX_PARITY_SIZE]; - GetParity(frame, len, par); - ReaderTransmitBitsPar(frame, len*8, par, timing); + // Generate parity and redirect + uint8_t par[MAX_PARITY_SIZE]; + GetParity(frame, len, par); + ReaderTransmitBitsPar(frame, len*8, par, timing); } int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t *parity) { - if (!GetIso14443aAnswerFromTag(receivedAnswer,parity,offset)) return FALSE; + if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, offset)) return FALSE; if (tracing) { LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, FALSE); } @@ -1720,34 +1721,26 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) /* performs iso14443a anticollision procedure * fills the uid pointer unless NULL * fills resp_data unless NULL */ -int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { - - //uint8_t deselect[] = {0xc2}; //DESELECT - //uint8_t halt[] = { 0x50, 0x00, 0x57, 0xCD }; // HALT - uint8_t wupa[] = { 0x52 }; // WAKE-UP - //uint8_t reqa[] = { 0x26 }; // REQUEST A +int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr) { + uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP uint8_t sel_all[] = { 0x93,0x20 }; uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 uint8_t *resp = ((uint8_t *)BigBuf) + RECV_RESP_OFFSET; uint8_t *resp_par = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; - byte_t uid_resp[4]; size_t uid_resp_len; + uint8_t sak = 0x04; // cascade uid int cascade_level = 0; - int len =0; - - // test for the SKYLANDERS TOY. - // ReaderTransmit(deselect,sizeof(deselect), NULL); - // len = ReaderReceive(resp, resp_par); - + int len; + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitBitsPar(wupa,7,0, NULL); + ReaderTransmitBitsPar(wupa,7,0, NULL); // Receive the ATQA if(!ReaderReceive(resp, resp_par)) return 0; - + if(p_hi14a_card) { memcpy(p_hi14a_card->atqa, resp, 2); p_hi14a_card->uidlen = 0; @@ -1759,103 +1752,99 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u memset(uid_ptr,0,10); } - // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in - // which case we need to make a cascade 2 request and select - this is a long UID - // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. - for(; sak & 0x04; cascade_level++) { - // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) - sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; + // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in + // which case we need to make a cascade 2 request and select - this is a long UID + // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. + for(; sak & 0x04; cascade_level++) { + // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) + sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; - // SELECT_ALL - ReaderTransmit(sel_all,sizeof(sel_all), NULL); - if (!ReaderReceive(resp, resp_par)) return 0; + // SELECT_ALL + ReaderTransmit(sel_all, sizeof(sel_all), NULL); + if (!ReaderReceive(resp, resp_par)) return 0; - if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit - memset(uid_resp, 0, 4); - uint16_t uid_resp_bits = 0; - uint16_t collision_answer_offset = 0; - // anti-collision-loop: - while (Demod.collisionPos) { - Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos); - for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point - uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01; - uid_resp[uid_resp_bits & 0xf8] |= UIDbit << (uid_resp_bits % 8); + if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit + memset(uid_resp, 0, 4); + uint16_t uid_resp_bits = 0; + uint16_t collision_answer_offset = 0; + // anti-collision-loop: + while (Demod.collisionPos) { + Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos); + for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point + uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01; + uid_resp[uid_resp_bits & 0xf8] |= UIDbit << (uid_resp_bits % 8); + } + uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position + uid_resp_bits++; + // construct anticollosion command: + sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits + for (uint16_t i = 0; i <= uid_resp_bits/8; i++) { + sel_uid[2+i] = uid_resp[i]; + } + collision_answer_offset = uid_resp_bits%8; + ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL); + if (!ReaderReceiveOffset(resp, collision_answer_offset, resp_par)) return 0; } - uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position - uid_resp_bits++; - // construct anticollosion command: - sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits - for (uint16_t i = 0; i <= uid_resp_bits/8; i++) { - sel_uid[2+i] = uid_resp[i]; + // finally, add the last bits and BCC of the UID + for (uint16_t i = collision_answer_offset; i < (Demod.len-1)*8; i++, uid_resp_bits++) { + uint16_t UIDbit = (resp[i/8] >> (i%8)) & 0x01; + uid_resp[uid_resp_bits/8] |= UIDbit << (uid_resp_bits % 8); } - collision_answer_offset = uid_resp_bits%8; - ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL); - if (!ReaderReceiveOffset(resp, collision_answer_offset,resp_par)) return 0; + + } else { // no collision, use the response to SELECT_ALL as current uid + memcpy(uid_resp, resp, 4); } - // finally, add the last bits and BCC of the UID - for (uint16_t i = collision_answer_offset; i < (Demod.len-1)*8; i++, uid_resp_bits++) { - uint16_t UIDbit = (resp[i/8] >> (i%8)) & 0x01; - uid_resp[uid_resp_bits/8] |= UIDbit << (uid_resp_bits % 8); + uid_resp_len = 4; + + // calculate crypto UID. Always use last 4 Bytes. + if(cuid_ptr) { + *cuid_ptr = bytes_to_num(uid_resp, 4); } - } else { // no collision, use the response to SELECT_ALL as current uid - memcpy(uid_resp,resp,4); + // Construct SELECT UID command + sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) + memcpy(sel_uid+2, uid_resp, 4); // the UID + sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC + AppendCrc14443a(sel_uid, 7); // calculate and add CRC + ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); + + // Receive the SAK + if (!ReaderReceive(resp, resp_par)) return 0; + sak = resp[0]; + + // Test if more parts of the uid are comming + if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { + // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: + // http://www.nxp.com/documents/application_note/AN10927.pdf + uid_resp[0] = uid_resp[1]; + uid_resp[1] = uid_resp[2]; + uid_resp[2] = uid_resp[3]; + + uid_resp_len = 3; + } + + if(uid_ptr) { + memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len); + } + + if(p_hi14a_card) { + memcpy(p_hi14a_card->uid + (cascade_level*3), uid_resp, uid_resp_len); + p_hi14a_card->uidlen += uid_resp_len; + } } - uid_resp_len = 4; - // calculate crypto UID. Always use last 4 Bytes. - if(cuid_ptr) { - *cuid_ptr = bytes_to_num(uid_resp, 4); - } - - // Construct SELECT UID command - sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) - memcpy(sel_uid+2,uid_resp,4); // the UID - sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC - AppendCrc14443a(sel_uid,7); // calculate and add CRC - ReaderTransmit(sel_uid,sizeof(sel_uid), NULL); - - // Receive the SAK - if (!ReaderReceive(resp, resp_par)){ - return 0; + if(p_hi14a_card) { + p_hi14a_card->sak = sak; + p_hi14a_card->ats_len = 0; } - - - sak = resp[0]; - - // Test if more parts of the uid are coming - if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { - // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: - // http://www.nxp.com/documents/application_note/AN10927.pdf - uid_resp[0] = uid_resp[1]; - uid_resp[1] = uid_resp[2]; - uid_resp[2] = uid_resp[3]; - - uid_resp_len = 3; - } - - if(uid_ptr) { - memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len); - } - - if(p_hi14a_card) { - memcpy(p_hi14a_card->uid + (cascade_level*3), uid_resp, uid_resp_len); - p_hi14a_card->uidlen += uid_resp_len; - } - } - - if(p_hi14a_card) { - p_hi14a_card->sak = sak; - p_hi14a_card->ats_len = 0; - } // non iso14443a compliant tag if( (sak & 0x20) == 0) return 2; - + // Request for answer to select AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); - + if (!(len = ReaderReceive(resp, resp_par))) return 0; @@ -1866,7 +1855,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u // reset the PCB block number iso14_pcb_blocknum = 0; - return 1; + return 1; } void iso14443a_setup(uint8_t fpga_minor_mode) { @@ -1877,7 +1866,8 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Signal field is on with the appropriate LED - if (fpga_minor_mode == FPGA_HF_ISO14443A_READER_MOD || fpga_minor_mode == FPGA_HF_ISO14443A_READER_LISTEN) { + if (fpga_minor_mode == FPGA_HF_ISO14443A_READER_MOD + || fpga_minor_mode == FPGA_HF_ISO14443A_READER_LISTEN) { LED_D_ON(); } else { LED_D_OFF(); @@ -1890,7 +1880,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { DemodReset(); UartReset(); NextTransferTime = 2*DELAY_ARM2AIR_AS_READER; - iso14a_set_timeout(1050); // 10ms default 10*105 = + iso14a_set_timeout(1050); // 10ms default } int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) { @@ -1905,7 +1895,7 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) { ReaderTransmit(real_cmd, cmd_len+4, NULL); size_t len = ReaderReceive(data, parity); - uint8_t * data_bytes = (uint8_t *) data; + uint8_t *data_bytes = (uint8_t *) data; if (!len) return 0; //DATA LINK ERROR // if we received an I- or R(ACK)-Block with a block number equal to the @@ -1969,8 +1959,8 @@ void ReaderIso14443a(UsbCommand *c) len += 2; if (lenbits) lenbits += 16; } - if(lenbits>0) { - GetParity(cmd, lenbits/8, par); + if(lenbits>0) { + GetParity(cmd, lenbits/8, par); ReaderTransmitBitsPar(cmd, lenbits, par, NULL); } else { ReaderTransmit(cmd,len, NULL); @@ -2168,7 +2158,7 @@ void ReaderMifare(bool first_try) led_on = !led_on; if(led_on) LED_B_ON(); else LED_B_OFF(); - par_list[nt_diff] = SwapBits(par[0], 8); + par_list[nt_diff] = SwapBits(par[0], 8); ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; // Test if the information is complete @@ -2736,7 +2726,7 @@ void RAMFUNC SniffMifare(uint8_t param) { // The response (tag -> reader) that we're receiving. uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); uint8_t *receivedResponsePar = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; - + // 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; diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 15e2a2f0..c595d5e1 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -12,7 +12,7 @@ #ifndef __ISO14443A_H #define __ISO14443A_H -#include "../include/common.h" +#include "common.h" #include "mifaresniff.h" typedef struct { @@ -28,8 +28,8 @@ typedef struct { uint16_t bitCount; uint16_t collisionPos; uint16_t syncBit; - uint8_t parityBits; - uint8_t parityLen; + uint8_t parityBits; + uint8_t parityLen; uint16_t shiftReg; uint16_t samples; uint16_t len; @@ -61,8 +61,8 @@ typedef struct { uint16_t byteCntMax; uint16_t posCnt; uint16_t syncBit; - uint8_t parityBits; - uint8_t parityLen; + uint8_t parityBits; + uint8_t parityLen; uint16_t highCnt; uint16_t twoBits; uint32_t startTime, endTime; diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index c4f5f612..ec8120b9 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -58,14 +58,12 @@ // *) document all the functions -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "util.h" #include "apps.h" #include "string.h" -#include "../common/iso15693tools.h" -#include "../common/cmd.h" -#include "crapto1.h" -#include "mifareutil.h" +#include "iso15693tools.h" +#include "cmd.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) @@ -453,7 +451,7 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int int8_t prev = 0; - // NOW READ RESPONSE +// NOW READ RESPONSE FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads c = 0; @@ -469,9 +467,21 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int // tone that the tag AM-modulates, so every other sample is I, // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. - if (getNext) { + if(getNext) { + int8_t r; - dest[c++] = abs(b) + abs(prev); + if(b < 0) { + r = -b; + } else { + r = b; + } + if(prev < 0) { + r -= prev; + } else { + r += prev; + } + + dest[c++] = (uint8_t)r; if(c >= 20000) { break; @@ -679,8 +689,8 @@ void RecordRawAdcSamplesIso15693(void) FpgaSetupSsc(); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -982,7 +992,7 @@ void SetDebugIso15693(uint32_t debug) { // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector // all demodulation performed in arm rather than host. - greg //----------------------------------------------------------------------------- -void ReaderIso15693(uint32_t parameter ) +void ReaderIso15693(uint32_t parameter) { LED_A_ON(); LED_B_ON(); @@ -1003,7 +1013,7 @@ void ReaderIso15693(uint32_t parameter ) int elapsed = 0; uint8_t TagUID[8] = {0x00}; - + // Blank arrays memset(BigBuf + 3660, 0x00, 300); @@ -1014,9 +1024,9 @@ void ReaderIso15693(uint32_t parameter ) FpgaSetupSsc(); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + // Give the tags time to energize FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(200); @@ -1055,7 +1065,7 @@ void ReaderIso15693(uint32_t parameter ) Dbhexdump(answerLen1,answer1,true); // UID is reverse - if (answerLen1 >= 12) + if (answerLen1>=12) Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX", TagUID[7],TagUID[6],TagUID[5],TagUID[4], TagUID[3],TagUID[2],TagUID[1],TagUID[0]); @@ -1069,14 +1079,14 @@ void ReaderIso15693(uint32_t parameter ) DbdecodeIso15693Answer(answerLen3,answer3); Dbhexdump(answerLen3,answer3,true); - // read all pages - if (answerLen1 >= 12 && DEBUG) { + // read all pages + if (answerLen1>=12 && DEBUG) { i=0; - while (i < 32) { // sanity check, assume max 32 pages + while (i<32) { // sanity check, assume max 32 pages BuildReadBlockRequest(TagUID,i); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); - answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); - if (answerLen2 > 0) { + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); + if (answerLen2>0) { Dbprintf("READ SINGLE BLOCK %d returned %d octets:",i,answerLen2); DbdecodeIso15693Answer(answerLen2,answer2); Dbhexdump(answerLen2,answer2,true); @@ -1108,9 +1118,9 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) int tsamples = 0; int wait = 0; int elapsed = 0; - + memset(buf, 0x00, 100); - + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -1118,8 +1128,8 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) FpgaSetupSsc(); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); LED_A_OFF(); LED_B_OFF(); @@ -1136,7 +1146,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) BuildInventoryResponse(uid); - TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait); + TransmitTo15693Reader(ToSend,ToSendMax, &tsamples, &wait); } Dbprintf("%d octets read from reader command: %x %x %x %x %x %x %x %x %x", answerLen1, diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 0e63ef5e..3fbdf5cb 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -8,14 +8,14 @@ // LEGIC RF simulation code //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" #include "legicrf.h" -#include "../include/legic_prng.h" -#include "../common/crc.h" +#include "legic_prng.h" +#include "crc.h" static struct legic_frame { int bits; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 08bae44d..edddb1c6 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -8,136 +8,154 @@ // Also routines for raw mode reading/simulating of LF waveform //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" -#include "../common/crc16.h" -#include "../common/lfdemod.h" +#include "hitag2.h" +#include "crc16.h" #include "string.h" -#include "crapto1.h" -#include "mifareutil.h" -#include "../include/hitag2.h" +#include "lfdemod.h" -// 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 -#define T0 192 -#define SHORT_COIL() LOW(GPIO_SSC_DOUT) -#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) +/** +* Does the sample acquisition. If threshold is specified, the actual sampling +* is not commenced until the threshold has been reached. +* @param trigger_threshold - the threshold +* @param silent - is true, now outputs are made. If false, dbprints the status +*/ +void DoAcquisition125k_internal(int trigger_threshold,bool silent) +{ + uint8_t *dest = (uint8_t *)BigBuf; + int n = sizeof(BigBuf); + int i; + memset(dest, 0, n); + i = 0; + for(;;) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); + } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + LED_D_OFF(); + if (trigger_threshold != -1 && dest[i] < trigger_threshold) + continue; + else + trigger_threshold = -1; + if (++i >= n) break; + } + } + if(!silent) + { + Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + } +} +/** +* Perform sample aquisition. +*/ +void DoAcquisition125k(int trigger_threshold) +{ + DoAcquisition125k_internal(trigger_threshold, false); +} + +/** +* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream +* if not already loaded, sets divisor and starts up the antenna. +* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz +* 0 or 95 ==> 125 KHz +* +**/ void LFSetupFPGAForADC(int divisor, bool lf_field) { - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else if (divisor == 0) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else if (divisor == 0) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0)); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0)); - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(150); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); } - +/** +* Initializes the FPGA, and acquires the samples. +**/ void AcquireRawAdcSamples125k(int divisor) { - LFSetupFPGAForADC(divisor, true); - DoAcquisition125k(); + LFSetupFPGAForADC(divisor, true); + // Now call the acquisition routine + DoAcquisition125k_internal(-1,false); } +/** +* Initializes the FPGA for snoop-mode, and acquires the samples. +**/ void SnoopLFRawAdcSamples(int divisor, int trigger_threshold) { - LFSetupFPGAForADC(divisor, false); - DoAcquisition125k_threshold(trigger_threshold); + LFSetupFPGAForADC(divisor, false); + DoAcquisition125k(trigger_threshold); } -// split into two routines so we can avoid timing issues after sending commands // -void DoAcquisition125k_internal(int trigger_threshold, bool silent) -{ - uint8_t *dest = (uint8_t *)BigBuf; - uint16_t i = 0; - memset(dest, 0x00, BIGBUF_SIZE); - - for(;;) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - LED_D_OFF(); - if (trigger_threshold != -1 && dest[i] < trigger_threshold) - continue; - else - trigger_threshold = -1; - if (++i >= BIGBUF_SIZE) break; - } - } - if (!silent){ - Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", - dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); - } -} -void DoAcquisition125k_threshold(int trigger_threshold) { - DoAcquisition125k_internal(trigger_threshold, true); -} -void DoAcquisition125k() { - DoAcquisition125k_internal(-1, true); -} - void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) { - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - /* Make sure the tag is reset */ - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(2500); - int divisor = 95; // 125 KHz - // see if 'h' was specified - if (command[strlen((char *) command) - 1] == 'h') - divisor = 88; // 134.8 KHz + /* Make sure the tag is reset */ + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(2500); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(2000); - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); + int divisor_used = 95; // 125 KHz + // see if 'h' was specified - // now modulate the reader field - while(*command != '\0' && *command != ' ') { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); + if (command[strlen((char *) command) - 1] == 'h') + divisor_used = 88; // 134.8 KHz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - LED_D_ON(); - if(*(command++) == '0') - SpinDelayUs(period_0); - else - SpinDelayUs(period_1); - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelayUs(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // now do the read - DoAcquisition125k(-1); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + + // And a little more time for the tag to fully power up + SpinDelay(2000); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + // now modulate the reader field + while(*command != '\0' && *command != ' ') { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelayUs(delay_off); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + LED_D_ON(); + if(*(command++) == '0') + SpinDelayUs(period_0); + else + SpinDelayUs(period_1); + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelayUs(delay_off); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor_used); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // now do the read + DoAcquisition125k(-1); } /* blank r/w tag data stream @@ -151,228 +169,228 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, */ void ReadTItag(void) { - // some hardcoded initial params - // when we read a TI tag we sample the zerocross line at 2Mhz - // TI tags modulate a 1 as 16 cycles of 123.2Khz - // TI tags modulate a 0 as 16 cycles of 134.2Khz - #define FSAMPLE 2000000 - #define FREQLO 123200 - #define FREQHI 134200 + // some hardcoded initial params + // when we read a TI tag we sample the zerocross line at 2Mhz + // TI tags modulate a 1 as 16 cycles of 123.2Khz + // TI tags modulate a 0 as 16 cycles of 134.2Khz +#define FSAMPLE 2000000 +#define FREQLO 123200 +#define FREQHI 134200 - signed char *dest = (signed char *)BigBuf; - int n = sizeof(BigBuf); + signed char *dest = (signed char *)BigBuf; + int n = sizeof(BigBuf); - // 128 bit shift register [shift3:shift2:shift1:shift0] - uint32_t shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0; + // 128 bit shift register [shift3:shift2:shift1:shift0] + uint32_t shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0; - int i, cycles=0, samples=0; - // how many sample points fit in 16 cycles of each frequency - uint32_t sampleslo = (FSAMPLE<<4)/FREQLO, sampleshi = (FSAMPLE<<4)/FREQHI; - // when to tell if we're close enough to one freq or another - uint32_t threshold = (sampleslo - sampleshi + 1)>>1; + int i, cycles=0, samples=0; + // how many sample points fit in 16 cycles of each frequency + uint32_t sampleslo = (FSAMPLE<<4)/FREQLO, sampleshi = (FSAMPLE<<4)/FREQHI; + // when to tell if we're close enough to one freq or another + uint32_t threshold = (sampleslo - sampleshi + 1)>>1; - // TI tags charge at 134.2Khz - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + // TI tags charge at 134.2Khz + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - // Place FPGA in passthrough mode, in this mode the CROSS_LO line - // connects to SSP_DIN and the SSP_DOUT logic level controls - // whether we're modulating the antenna (high) - // or listening to the antenna (low) - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + // Place FPGA in passthrough mode, in this mode the CROSS_LO line + // connects to SSP_DIN and the SSP_DOUT logic level controls + // whether we're modulating the antenna (high) + // or listening to the antenna (low) + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); - // get TI tag data into the buffer - AcquireTiType(); + // get TI tag data into the buffer + AcquireTiType(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - for (i=0; i0) ) { - cycles++; - // after 16 cycles, measure the frequency - if (cycles>15) { - cycles=0; - samples=i-samples; // number of samples in these 16 cycles + for (i=0; i0) ) { + cycles++; + // after 16 cycles, measure the frequency + if (cycles>15) { + cycles=0; + samples=i-samples; // number of samples in these 16 cycles - // TI bits are coming to us lsb first so shift them - // right through our 128 bit right shift register - shift0 = (shift0>>1) | (shift1 << 31); - shift1 = (shift1>>1) | (shift2 << 31); - shift2 = (shift2>>1) | (shift3 << 31); - shift3 >>= 1; + // TI bits are coming to us lsb first so shift them + // right through our 128 bit right shift register + shift0 = (shift0>>1) | (shift1 << 31); + shift1 = (shift1>>1) | (shift2 << 31); + shift2 = (shift2>>1) | (shift3 << 31); + shift3 >>= 1; - // check if the cycles fall close to the number - // expected for either the low or high frequency - if ( (samples>(sampleslo-threshold)) && (samples<(sampleslo+threshold)) ) { - // low frequency represents a 1 - shift3 |= (1<<31); - } else if ( (samples>(sampleshi-threshold)) && (samples<(sampleshi+threshold)) ) { - // high frequency represents a 0 - } else { - // probably detected a gay waveform or noise - // use this as gaydar or discard shift register and start again - shift3 = shift2 = shift1 = shift0 = 0; - } - samples = i; + // check if the cycles fall close to the number + // expected for either the low or high frequency + if ( (samples>(sampleslo-threshold)) && (samples<(sampleslo+threshold)) ) { + // low frequency represents a 1 + shift3 |= (1<<31); + } else if ( (samples>(sampleshi-threshold)) && (samples<(sampleshi+threshold)) ) { + // high frequency represents a 0 + } else { + // probably detected a gay waveform or noise + // use this as gaydar or discard shift register and start again + shift3 = shift2 = shift1 = shift0 = 0; + } + samples = i; - // for each bit we receive, test if we've detected a valid tag + // for each bit we receive, test if we've detected a valid tag - // if we see 17 zeroes followed by 6 ones, we might have a tag - // remember the bits are backwards - if ( ((shift0 & 0x7fffff) == 0x7e0000) ) { - // if start and end bytes match, we have a tag so break out of the loop - if ( ((shift0>>16)&0xff) == ((shift3>>8)&0xff) ) { - cycles = 0xF0B; //use this as a flag (ugly but whatever) - break; - } - } - } - } - } + // if we see 17 zeroes followed by 6 ones, we might have a tag + // remember the bits are backwards + if ( ((shift0 & 0x7fffff) == 0x7e0000) ) { + // if start and end bytes match, we have a tag so break out of the loop + if ( ((shift0>>16)&0xff) == ((shift3>>8)&0xff) ) { + cycles = 0xF0B; //use this as a flag (ugly but whatever) + break; + } + } + } + } + } - // if flag is set we have a tag - if (cycles!=0xF0B) { - DbpString("Info: No valid tag detected."); - } else { - // put 64 bit data into shift1 and shift0 - shift0 = (shift0>>24) | (shift1 << 8); - shift1 = (shift1>>24) | (shift2 << 8); + // if flag is set we have a tag + if (cycles!=0xF0B) { + DbpString("Info: No valid tag detected."); + } else { + // put 64 bit data into shift1 and shift0 + shift0 = (shift0>>24) | (shift1 << 8); + shift1 = (shift1>>24) | (shift2 << 8); - // align 16 bit crc into lower half of shift2 - shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff; + // align 16 bit crc into lower half of shift2 + shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff; - // if r/w tag, check ident match - if ( shift3&(1<<15) ) { - DbpString("Info: TI tag is rewriteable"); - // only 15 bits compare, last bit of ident is not valid - if ( ((shift3>>16)^shift0)&0x7fff ) { - DbpString("Error: Ident mismatch!"); - } else { - DbpString("Info: TI tag ident is valid"); - } - } else { - DbpString("Info: TI tag is readonly"); - } + // if r/w tag, check ident match + if ( shift3&(1<<15) ) { + DbpString("Info: TI tag is rewriteable"); + // only 15 bits compare, last bit of ident is not valid + if ( ((shift3>>16)^shift0)&0x7fff ) { + DbpString("Error: Ident mismatch!"); + } else { + DbpString("Info: TI tag ident is valid"); + } + } else { + DbpString("Info: TI tag is readonly"); + } - // WARNING the order of the bytes in which we calc crc below needs checking - // i'm 99% sure the crc algorithm is correct, but it may need to eat the - // bytes in reverse or something - // calculate CRC - uint32_t crc=0; + // WARNING the order of the bytes in which we calc crc below needs checking + // i'm 99% sure the crc algorithm is correct, but it may need to eat the + // bytes in reverse or something + // calculate CRC + uint32_t crc=0; - crc = update_crc16(crc, (shift0)&0xff); - crc = update_crc16(crc, (shift0>>8)&0xff); - crc = update_crc16(crc, (shift0>>16)&0xff); - crc = update_crc16(crc, (shift0>>24)&0xff); - crc = update_crc16(crc, (shift1)&0xff); - crc = update_crc16(crc, (shift1>>8)&0xff); - crc = update_crc16(crc, (shift1>>16)&0xff); - crc = update_crc16(crc, (shift1>>24)&0xff); + crc = update_crc16(crc, (shift0)&0xff); + crc = update_crc16(crc, (shift0>>8)&0xff); + crc = update_crc16(crc, (shift0>>16)&0xff); + crc = update_crc16(crc, (shift0>>24)&0xff); + crc = update_crc16(crc, (shift1)&0xff); + crc = update_crc16(crc, (shift1>>8)&0xff); + crc = update_crc16(crc, (shift1>>16)&0xff); + crc = update_crc16(crc, (shift1>>24)&0xff); - Dbprintf("Info: Tag data: %x%08x, crc=%x", - (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF); - if (crc != (shift2&0xffff)) { - Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc); - } else { - DbpString("Info: CRC is good"); - } - } + Dbprintf("Info: Tag data: %x%08x, crc=%x", + (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF); + if (crc != (shift2&0xffff)) { + Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc); + } else { + DbpString("Info: CRC is good"); + } + } } void WriteTIbyte(uint8_t b) { - int i = 0; + int i = 0; - // modulate 8 bits out to the antenna - for (i=0; i<8; i++) - { - if (b&(1<PIO_PDR = GPIO_SSC_DIN; - AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN; + // Set up the synchronous serial port + AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN; + AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN; - // steal this pin from the SSP and use it to control the modulation - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + // steal this pin from the SSP and use it to control the modulation + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; - AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; - // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long - // 48/2 = 24 MHz clock must be divided by 12 - AT91C_BASE_SSC->SSC_CMR = 12; + // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long + // 48/2 = 24 MHz clock must be divided by 12 + AT91C_BASE_SSC->SSC_CMR = 12; - AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0); - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF; - AT91C_BASE_SSC->SSC_TCMR = 0; - AT91C_BASE_SSC->SSC_TFMR = 0; + AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0); + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF; + AT91C_BASE_SSC->SSC_TCMR = 0; + AT91C_BASE_SSC->SSC_TFMR = 0; - LED_D_ON(); + LED_D_ON(); - // modulate antenna - HIGH(GPIO_SSC_DOUT); + // modulate antenna + HIGH(GPIO_SSC_DOUT); - // Charge TI tag for 50ms. - SpinDelay(50); + // Charge TI tag for 50ms. + SpinDelay(50); - // stop modulating antenna and listen - LOW(GPIO_SSC_DOUT); + // stop modulating antenna and listen + LOW(GPIO_SSC_DOUT); - LED_D_OFF(); + LED_D_OFF(); - i = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - BigBuf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer - i++; if(i >= TIBUFLEN) break; - } - WDT_HIT(); - } + i = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + BigBuf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer + i++; if(i >= TIBUFLEN) break; + } + WDT_HIT(); + } - // return stolen pin to SSP - AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; + // return stolen pin to SSP + AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; - char *dest = (char *)BigBuf; - n = TIBUFLEN*32; - // unpack buffer - for (i=TIBUFLEN-1; i>=0; i--) { - for (j=0; j<32; j++) { - if(BigBuf[i] & (1 << j)) { - dest[--n] = 1; - } else { - dest[--n] = -1; - } - } - } + char *dest = (char *)BigBuf; + n = TIBUFLEN*32; + // unpack buffer + for (i=TIBUFLEN-1; i>=0; i--) { + for (j=0; j<32; j++) { + if(BigBuf[i] & (1 << j)) { + dest[--n] = 1; + } else { + dest[--n] = -1; + } + } + } } // arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc @@ -380,233 +398,127 @@ void AcquireTiType(void) // if not provided a valid crc will be computed from the data and written. void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) { - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - if(crc == 0) { - crc = update_crc16(crc, (idlo)&0xff); - crc = update_crc16(crc, (idlo>>8)&0xff); - crc = update_crc16(crc, (idlo>>16)&0xff); - crc = update_crc16(crc, (idlo>>24)&0xff); - crc = update_crc16(crc, (idhi)&0xff); - crc = update_crc16(crc, (idhi>>8)&0xff); - crc = update_crc16(crc, (idhi>>16)&0xff); - crc = update_crc16(crc, (idhi>>24)&0xff); - } - Dbprintf("Writing to tag: %x%08x, crc=%x", - (unsigned int) idhi, (unsigned int) idlo, crc); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + if(crc == 0) { + crc = update_crc16(crc, (idlo)&0xff); + crc = update_crc16(crc, (idlo>>8)&0xff); + crc = update_crc16(crc, (idlo>>16)&0xff); + crc = update_crc16(crc, (idlo>>24)&0xff); + crc = update_crc16(crc, (idhi)&0xff); + crc = update_crc16(crc, (idhi>>8)&0xff); + crc = update_crc16(crc, (idhi>>16)&0xff); + crc = update_crc16(crc, (idhi>>24)&0xff); + } + Dbprintf("Writing to tag: %x%08x, crc=%x", + (unsigned int) idhi, (unsigned int) idlo, crc); - // TI tags charge at 134.2Khz - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - // Place FPGA in passthrough mode, in this mode the CROSS_LO line - // connects to SSP_DIN and the SSP_DOUT logic level controls - // whether we're modulating the antenna (high) - // or listening to the antenna (low) - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); - LED_A_ON(); + // TI tags charge at 134.2Khz + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + // Place FPGA in passthrough mode, in this mode the CROSS_LO line + // connects to SSP_DIN and the SSP_DOUT logic level controls + // whether we're modulating the antenna (high) + // or listening to the antenna (low) + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + LED_A_ON(); - // steal this pin from the SSP and use it to control the modulation - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + // steal this pin from the SSP and use it to control the modulation + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - // writing algorithm: - // a high bit consists of a field off for 1ms and field on for 1ms - // a low bit consists of a field off for 0.3ms and field on for 1.7ms - // initiate a charge time of 50ms (field on) then immediately start writing bits - // start by writing 0xBB (keyword) and 0xEB (password) - // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer) - // finally end with 0x0300 (write frame) - // all data is sent lsb firts - // finish with 15ms programming time + // writing algorithm: + // a high bit consists of a field off for 1ms and field on for 1ms + // a low bit consists of a field off for 0.3ms and field on for 1.7ms + // initiate a charge time of 50ms (field on) then immediately start writing bits + // start by writing 0xBB (keyword) and 0xEB (password) + // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer) + // finally end with 0x0300 (write frame) + // all data is sent lsb firts + // finish with 15ms programming time - // modulate antenna - HIGH(GPIO_SSC_DOUT); - SpinDelay(50); // charge time + // modulate antenna + HIGH(GPIO_SSC_DOUT); + SpinDelay(50); // charge time - WriteTIbyte(0xbb); // keyword - WriteTIbyte(0xeb); // password - WriteTIbyte( (idlo )&0xff ); - WriteTIbyte( (idlo>>8 )&0xff ); - WriteTIbyte( (idlo>>16)&0xff ); - WriteTIbyte( (idlo>>24)&0xff ); - WriteTIbyte( (idhi )&0xff ); - WriteTIbyte( (idhi>>8 )&0xff ); - WriteTIbyte( (idhi>>16)&0xff ); - WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo - WriteTIbyte( (crc )&0xff ); // crc lo - WriteTIbyte( (crc>>8 )&0xff ); // crc hi - WriteTIbyte(0x00); // write frame lo - WriteTIbyte(0x03); // write frame hi - HIGH(GPIO_SSC_DOUT); - SpinDelay(50); // programming time + WriteTIbyte(0xbb); // keyword + WriteTIbyte(0xeb); // password + WriteTIbyte( (idlo )&0xff ); + WriteTIbyte( (idlo>>8 )&0xff ); + WriteTIbyte( (idlo>>16)&0xff ); + WriteTIbyte( (idlo>>24)&0xff ); + WriteTIbyte( (idhi )&0xff ); + WriteTIbyte( (idhi>>8 )&0xff ); + WriteTIbyte( (idhi>>16)&0xff ); + WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo + WriteTIbyte( (crc )&0xff ); // crc lo + WriteTIbyte( (crc>>8 )&0xff ); // crc hi + WriteTIbyte(0x00); // write frame lo + WriteTIbyte(0x03); // write frame hi + HIGH(GPIO_SSC_DOUT); + SpinDelay(50); // programming time - LED_A_OFF(); + LED_A_OFF(); - // get TI tag data into the buffer - AcquireTiType(); + // get TI tag data into the buffer + AcquireTiType(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Now use tiread to check"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Now use tiread to check"); } - +void SimulateTagLowFrequency(int period, int gap, int ledcontrol) +{ + int i; + uint8_t *tab = (uint8_t *)BigBuf; + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; + + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; + +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) + + i = 0; + for(;;) { + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + if(BUTTON_PRESS()) { + DbpString("Stopped"); + return; + } + WDT_HIT(); + } -// PIO_CODR = Clear Output Data Register -// PIO_SODR = Set Output Data Register -//#define LOW(x) AT91C_BASE_PIOA->PIO_CODR = (x) -//#define HIGH(x) AT91C_BASE_PIOA->PIO_SODR = (x) -void SimulateTagLowFrequency( uint16_t period, uint32_t gap, uint8_t ledcontrol) -{ - LED_D_ON(); - - uint16_t i = 0; - uint8_t send = 0; - - //int overflow = 0; - uint8_t *buf = (uint8_t *)BigBuf; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); - - // Configure output pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - - SHORT_COIL(); - - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - - // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // 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, - // external trigger rising edge, load RA on rising edge of TIOA. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; - - // Enable and reset counter - //AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - while(!BUTTON_PRESS()) { - WDT_HIT(); - - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * 55) { - - // Check if rising edge in modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - //int ra = (AT91C_BASE_TC1->TC_RA/T0) + overflow; - //Dbprintf("Timing value - %d %d", ra, overflow); - //overflow = 0; - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - send = 1; - - LED_B_ON(); - } - } - - if ( send ) { - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, - // not that since the clock counts since the rising edge, but T_Wait1 is - // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) - // periods. The gap time T_Low varies (4..10). All timer values are in - // terms of T0 units - while(AT91C_BASE_TC0->TC_CV < T0 * 16 ); - - // datat kommer in som 1 bit för varje position i arrayn - for(i = 0; i < period; ++i) { - - // Reset clock for the next bit - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - if ( buf[i] > 0 ) - HIGH(GPIO_SSC_DOUT); - else - LOW(GPIO_SSC_DOUT); - - while(AT91C_BASE_TC0->TC_CV < T0 * 1 ); - } - // Drop modulation - LOW(GPIO_SSC_DOUT); - - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - LED_B_OFF(); - } - - send = 0; - - // Save the timer overflow, will be 0 when frame was received - //overflow += (AT91C_BASE_TC1->TC_CV/T0); - - // Reset the timer to restart while-loop that receives frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - } - - LED_B_OFF(); - LED_D_OFF(); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - DbpString("Sim Stopped"); -} - - -void SimulateTagLowFrequencyA(int len, int gap) -{ - uint8_t *buf = (uint8_t *)BigBuf; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); // new izsh toggle mode! - - // 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. - FpgaSetupSsc(); - SpinDelay(5); - - AT91C_BASE_SSC->SSC_THR = 0x00; - - int i = 0; - while(!BUTTON_PRESS()) { - WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - - if ( buf[i] > 0 ) - AT91C_BASE_SSC->SSC_THR = 0x43; - else - AT91C_BASE_SSC->SSC_THR = 0x00; - - ++i; - LED_A_ON(); - if (i >= len){ - i = 0; - } - } - - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - LED_A_OFF(); - } - } - DbpString("lf simulate stopped"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + if (ledcontrol) + LED_D_ON(); + + if(tab[i]) + OPEN_COIL(); + else + SHORT_COIL(); + + if (ledcontrol) + LED_D_OFF(); + + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + if(BUTTON_PRESS()) { + DbpString("Stopped"); + return; + } + WDT_HIT(); + } + + i++; + if(i == period) { + i = 0; + if (gap) { + SHORT_COIL(); + SpinDelayUs(gap); + } + } + } } #define DEBUG_FRAME_CONTENTS 1 @@ -615,319 +527,315 @@ void SimulateTagLowFrequencyBidir(int divisor, int t0) } // compose fc/8 fc/10 waveform -static void fc(int c, uint16_t *n) { - uint8_t *dest = (uint8_t *)BigBuf; - int idx; +static void fc(int c, int *n) { + uint8_t *dest = (uint8_t *)BigBuf; + int idx; - // for when we want an fc8 pattern every 4 logical bits - if(c == 0) { - dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - } - // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples - if(c == 8) { - for (idx=0; idx<6; idx++) { - dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - } - } + // for when we want an fc8 pattern every 4 logical bits + if(c==0) { + dest[((*n)++)]=1; + dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + } + // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples + if(c==8) { + for (idx=0; idx<6; idx++) { + dest[((*n)++)]=1; + dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + } + } - // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples - if(c == 10) { - for (idx = 0; idx < 5; idx++) { - dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - dest[((*n)++)]=0; - } - } + // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples + if(c==10) { + for (idx=0; idx<5; idx++) { + dest[((*n)++)]=1; + dest[((*n)++)]=1; + dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + dest[((*n)++)]=0; + } + } } // prepare a waveform pattern in the buffer based on the ID given then // simulate a HID tag until the button is pressed -void CmdHIDsimTAG(int hi, int lo, uint8_t ledcontrol) +void CmdHIDsimTAG(int hi, int lo, int ledcontrol) { - uint16_t n = 0, i = 0; - /* - HID tag bitstream format - The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits - A 1 bit is represented as 6 fc8 and 5 fc10 patterns - A 0 bit is represented as 5 fc10 and 6 fc8 patterns - A fc8 is inserted before every 4 bits - A special start of frame pattern is used consisting a0b0 where a and b are neither 0 - nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) - */ + int n=0, i=0; + /* + HID tag bitstream format + The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits + A 1 bit is represented as 6 fc8 and 5 fc10 patterns + A 0 bit is represented as 5 fc10 and 6 fc8 patterns + A fc8 is inserted before every 4 bits + A special start of frame pattern is used consisting a0b0 where a and b are neither 0 + nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) + */ - if (hi > 0xFFF) { - DbpString("Tags can only have 44 bits."); - return; - } - fc(0, &n); - // special start of frame marker containing invalid bit sequences - fc(8, &n); fc(8, &n); // invalid - fc(8, &n); fc(10, &n); // logical 0 - fc(10, &n); fc(10, &n); // invalid - fc(8, &n); fc(10, &n); // logical 0 + if (hi>0xFFF) { + DbpString("Tags can only have 44 bits."); + return; + } + fc(0,&n); + // special start of frame marker containing invalid bit sequences + fc(8, &n); fc(8, &n); // invalid + fc(8, &n); fc(10, &n); // logical 0 + fc(10, &n); fc(10, &n); // invalid + fc(8, &n); fc(10, &n); // logical 0 - WDT_HIT(); - // manchester encode bits 43 to 32 - for (i = 11; i >= 0; i--) { - if ((i % 4) == 3) fc(0, &n); - if ((hi >> i) & 1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } + WDT_HIT(); + // manchester encode bits 43 to 32 + for (i=11; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((hi>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } + } - WDT_HIT(); - // manchester encode bits 31 to 0 - for (i = 31; i >= 0; i--) { - if ((i % 4 ) == 3) fc(0, &n); - if ((lo >> i ) & 1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } + WDT_HIT(); + // manchester encode bits 31 to 0 + for (i=31; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((lo>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition + } + } - if (ledcontrol) - LED_A_ON(); + if (ledcontrol) + LED_A_ON(); - SimulateTagLowFrequency(n, 0, ledcontrol); + SimulateTagLowFrequency(n, 0, ledcontrol); - if (ledcontrol) - LED_A_OFF(); + if (ledcontrol) + LED_A_OFF(); } // loop to get raw HID waveform then FSK demodulate the TAG ID from it void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = (uint8_t *)BigBuf; - uint32_t hi2 = 0, hi = 0, lo = 0; + uint8_t *dest = (uint8_t *)BigBuf; - // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(0, true); + size_t size=0; //, found=0; + uint32_t hi2=0, hi=0, lo=0; - while(!BUTTON_PRESS()) { + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(95, true); - WDT_HIT(); - if (ledcontrol) LED_A_ON(); + while(!BUTTON_PRESS()) { - DoAcquisition125k_internal(-1,true); + WDT_HIT(); + if (ledcontrol) LED_A_ON(); - // FSK demodulator - int bitLen = HIDdemodFSK(dest,BIGBUF_SIZE,&hi2,&hi,&lo); + DoAcquisition125k_internal(-1,true); + size = sizeof(BigBuf); + if (size < 2000) continue; + // FSK demodulator - WDT_HIT(); + int bitLen = HIDdemodFSK(dest,size,&hi2,&hi,&lo); - if (bitLen > 0 && lo > 0){ + WDT_HIT(); - // final loop, go over previously decoded manchester data and decode into usable tag ID - // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 - - if (hi2 != 0){ - //extra large HID tags - Dbprintf("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, - (unsigned int) hi, - (unsigned int) lo, - (unsigned int) (lo >> 1) & 0xFFFF); - - } else { - //standard HID tags <38 bits - uint8_t bitlen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - - if ((( hi >> 5 ) & 1) ==1){//if bit 38 is set then < 37 bit format is used - uint32_t lo2 = 0; - lo2 = (((hi & 31) << 12) | (lo >> 20)); //get bits 21-37 to check for format len bit - uint8_t idx3 = 1; - while(lo2 > 1){ //find last bit set to 1 (format len bit) - lo2 = lo2 >> 1; - idx3++; - } - bitlen =idx3 + 19; - fc = 0; - cardnum = 0; - if(bitlen == 26){ - cardnum = (lo >> 1) & 0xFFFF; - fc = (lo >> 17) & 0xFF; - } - if(bitlen == 37){ - cardnum = (lo >> 1) & 0x7FFFF; - fc = ((hi & 0xF) << 12)|( lo >> 20); - } - if(bitlen == 34){ - cardnum = (lo >> 1) & 0xFFFF; - fc = ((hi & 1) << 15) | (lo >> 17); - } - if(bitlen == 35){ - cardnum = (lo >> 1 ) & 0xFFFFF; - fc = ((hi & 1) << 11 ) | ( lo >> 21); - } - } - else { //if bit 38 is not set then 37 bit format is used - bitlen = 37; - fc = 0; - cardnum = 0; - if(bitlen == 37){ - cardnum = ( lo >> 1) & 0x7FFFF; - fc = ((hi & 0xF) << 12 ) |(lo >> 20); - } - } - Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", - (unsigned int) hi, - (unsigned int) lo, - (unsigned int) (lo >> 1) & 0xFFFF, - (unsigned int) bitlen, - (unsigned int) fc, - (unsigned int) cardnum); - } - if (findone){ - if (ledcontrol) LED_A_OFF(); - return; - } - // reset - hi2 = hi = lo = 0; - } - WDT_HIT(); - } - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); + if (bitLen>0 && lo>0){ + // final loop, go over previously decoded manchester data and decode into usable tag ID + // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 + if (hi2 != 0){ //extra large HID tags + Dbprintf("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + }else { //standard HID tags <38 bits + //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd + uint8_t bitlen = 0; + uint32_t fc = 0; + uint32_t cardnum = 0; + if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used + uint32_t lo2=0; + lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit + uint8_t idx3 = 1; + while(lo2>1){ //find last bit set to 1 (format len bit) + lo2=lo2>>1; + idx3++; + } + bitlen =idx3+19; + fc =0; + cardnum=0; + if(bitlen==26){ + cardnum = (lo>>1)&0xFFFF; + fc = (lo>>17)&0xFF; + } + if(bitlen==37){ + cardnum = (lo>>1)&0x7FFFF; + fc = ((hi&0xF)<<12)|(lo>>20); + } + if(bitlen==34){ + cardnum = (lo>>1)&0xFFFF; + fc= ((hi&1)<<15)|(lo>>17); + } + if(bitlen==35){ + cardnum = (lo>>1)&0xFFFFF; + fc = ((hi&1)<<11)|(lo>>21); + } + } + else { //if bit 38 is not set then 37 bit format is used + bitlen= 37; + fc =0; + cardnum=0; + if(bitlen==37){ + cardnum = (lo>>1)&0x7FFFF; + fc = ((hi&0xF)<<12)|(lo>>20); + } + } + //Dbprintf("TAG ID: %x%08x (%d)", + // (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, + (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); + } + if (findone){ + if (ledcontrol) LED_A_OFF(); + return; + } + // reset + hi2 = hi = lo = 0; + } + WDT_HIT(); + } + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); } void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = (uint8_t *)BigBuf; - uint32_t bitLen = 0; - int clk = 0, invert = 0, errCnt = 0; - uint64_t lo = 0; - - // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(0, true); + uint8_t *dest = (uint8_t *)BigBuf; - while(!BUTTON_PRESS()) { + size_t size=0; //, found=0; + uint32_t bitLen=0; + int clk=0, invert=0, errCnt=0; + uint64_t lo=0; + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(95, true); - WDT_HIT(); - if (ledcontrol) LED_A_ON(); + while(!BUTTON_PRESS()) { - DoAcquisition125k_internal(-1,true); - - // FSK demodulator - bitLen = BIGBUF_SIZE; - errCnt = askmandemod(dest,&bitLen,&clk,&invert); - if ( errCnt < 0 ) continue; + WDT_HIT(); + if (ledcontrol) LED_A_ON(); - WDT_HIT(); - - lo = Em410xDecode(dest,bitLen); - - if ( lo <= 0) continue; - - 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) - ); + DoAcquisition125k_internal(-1,true); + size = sizeof(BigBuf); + if (size < 2000) continue; + // FSK demodulator + //int askmandemod(uint8_t *BinStream,uint32_t *BitLen,int *clk, int *invert); + bitLen=size; + //Dbprintf("DEBUG: Buffer got"); + errCnt = askmandemod(dest,&bitLen,&clk,&invert); //HIDdemodFSK(dest,size,&hi2,&hi,&lo); + //Dbprintf("DEBUG: ASK Got"); + WDT_HIT(); - if (findone){ - if (ledcontrol) LED_A_OFF(); - return; - } - - WDT_HIT(); - lo = clk = invert = errCnt = 0; - } - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); + if (errCnt>=0){ + lo = Em410xDecode(dest,bitLen); + //Dbprintf("DEBUG: EM GOT"); + //printEM410x(lo); + if (lo>0){ + 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(); + return; + } + } else{ + //Dbprintf("DEBUG: No Tag"); + } + WDT_HIT(); + lo = 0; + clk=0; + invert=0; + errCnt=0; + size=0; + //SpinDelay(50); + } + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); } void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = (uint8_t *)BigBuf; - int idx = 0; - uint32_t code = 0, code2 = 0; - uint8_t version = 0; - uint8_t facilitycode = 0; - uint16_t number = 0; + uint8_t *dest = (uint8_t *)BigBuf; + int idx=0; + uint32_t code=0, code2=0; + uint8_t version=0; + uint8_t facilitycode=0; + uint16_t number=0; + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(95, true); - LFSetupFPGAForADC(0, true); + while(!BUTTON_PRESS()) { + WDT_HIT(); + if (ledcontrol) LED_A_ON(); + DoAcquisition125k_internal(-1,true); + //fskdemod and get start index + WDT_HIT(); + idx = IOdemodFSK(dest,sizeof(BigBuf)); + if (idx>0){ + //valid tag found - while(!BUTTON_PRESS()) { + //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 + 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 - WDT_HIT(); - if (ledcontrol) LED_A_ON(); - - DoAcquisition125k_internal(-1, true); - - idx = IOdemodFSK(dest, BIGBUF_SIZE); - - if ( idx < 0 ) - continue; - - WDT_HIT(); - - //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 - 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 (findone){ - if (ledcontrol) LED_A_OFF(); - return; - } - code = code2 = 0; - version = facilitycode = 0; - number = 0; - idx = 0; - } - - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); + 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(); + return; + } + code=code2=0; + version=facilitycode=0; + number=0; + idx=0; + } + WDT_HIT(); + } + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); } /*------------------------------ @@ -936,14 +844,14 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) */ /* T55x7 configuration register definitions */ -#define T55x7_POR_DELAY 0x00000001 -#define T55x7_ST_TERMINATOR 0x00000008 -#define T55x7_PWD 0x00000010 +#define T55x7_POR_DELAY 0x00000001 +#define T55x7_ST_TERMINATOR 0x00000008 +#define T55x7_PWD 0x00000010 #define T55x7_MAXBLOCK_SHIFT 5 -#define T55x7_AOR 0x00000200 -#define T55x7_PSKCF_RF_2 0 -#define T55x7_PSKCF_RF_4 0x00000400 -#define T55x7_PSKCF_RF_8 0x00000800 +#define T55x7_AOR 0x00000200 +#define T55x7_PSKCF_RF_2 0 +#define T55x7_PSKCF_RF_4 0x00000400 +#define T55x7_PSKCF_RF_8 0x00000800 #define T55x7_MODULATION_DIRECT 0 #define T55x7_MODULATION_PSK1 0x00001000 #define T55x7_MODULATION_PSK2 0x00002000 @@ -954,17 +862,17 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define T55x7_MODULATION_FSK2a 0x00007000 #define T55x7_MODULATION_MANCHESTER 0x00008000 #define T55x7_MODULATION_BIPHASE 0x00010000 -#define T55x7_BITRATE_RF_8 0 -#define T55x7_BITRATE_RF_16 0x00040000 -#define T55x7_BITRATE_RF_32 0x00080000 -#define T55x7_BITRATE_RF_40 0x000C0000 -#define T55x7_BITRATE_RF_50 0x00100000 -#define T55x7_BITRATE_RF_64 0x00140000 +#define T55x7_BITRATE_RF_8 0 +#define T55x7_BITRATE_RF_16 0x00040000 +#define T55x7_BITRATE_RF_32 0x00080000 +#define T55x7_BITRATE_RF_40 0x000C0000 +#define T55x7_BITRATE_RF_50 0x00100000 +#define T55x7_BITRATE_RF_64 0x00140000 #define T55x7_BITRATE_RF_100 0x00180000 #define T55x7_BITRATE_RF_128 0x001C0000 /* T5555 (Q5) configuration register definitions */ -#define T5555_ST_TERMINATOR 0x00000001 +#define T5555_ST_TERMINATOR 0x00000001 #define T5555_MAXBLOCK_SHIFT 0x00000001 #define T5555_MODULATION_MANCHESTER 0 #define T5555_MODULATION_PSK1 0x00000010 @@ -974,321 +882,330 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define T5555_MODULATION_FSK2 0x00000050 #define T5555_MODULATION_BIPHASE 0x00000060 #define T5555_MODULATION_DIRECT 0x00000070 -#define T5555_INVERT_OUTPUT 0x00000080 -#define T5555_PSK_RF_2 0 -#define T5555_PSK_RF_4 0x00000100 -#define T5555_PSK_RF_8 0x00000200 -#define T5555_USE_PWD 0x00000400 -#define T5555_USE_AOR 0x00000800 -#define T5555_BITRATE_SHIFT 12 -#define T5555_FAST_WRITE 0x00004000 -#define T5555_PAGE_SELECT 0x00008000 +#define T5555_INVERT_OUTPUT 0x00000080 +#define T5555_PSK_RF_2 0 +#define T5555_PSK_RF_4 0x00000100 +#define T5555_PSK_RF_8 0x00000200 +#define T5555_USE_PWD 0x00000400 +#define T5555_USE_AOR 0x00000800 +#define T5555_BITRATE_SHIFT 12 +#define T5555_FAST_WRITE 0x00004000 +#define T5555_PAGE_SELECT 0x00008000 /* * Relevant times in microsecond * To compensate antenna falling times shorten the write times * and enlarge the gap ones. */ -#define START_GAP 30*8 // 10 - 50fc 250 -#define WRITE_GAP 20*8 // 8 - 30fc -#define WRITE_0 24*8 // 16 - 31fc 24fc 192 -#define WRITE_1 54*8 // 48 - 63fc 54fc 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); - -#define T55xx_SAMPLES_SIZE 12000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) +#define START_GAP 250 +#define WRITE_GAP 160 +#define WRITE_0 144 // 192 +#define WRITE_1 400 // 432 for T55x7; 448 for E5550 // Write one bit to card 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) - SpinDelayUs(WRITE_0); - else - SpinDelayUs(WRITE_1); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelayUs(WRITE_GAP); + 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) + SpinDelayUs(WRITE_0); + else + SpinDelayUs(WRITE_1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelayUs(WRITE_GAP); } // Write one card block in page 0, no lock void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMode) { - uint32_t i = 0; + //unsigned int i; //enio adjustment 12/10/14 + uint32_t i; - // Set up FPGA, 125kHz - // Wait for config.. (192+8190xPOW)x8 == 67ms - LFSetupFPGAForADC(0, true); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Now start writting - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelayUs(START_GAP); + // Give it a bit of time for the resonant antenna to settle. + // And for the tag to fully power up + SpinDelay(150); - // Opcode - T55xxWriteBit(1); - T55xxWriteBit(0); //Page 0 - if (PwdMode == 1){ - // Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Lock bit - T55xxWriteBit(0); + // Now start writting + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelayUs(START_GAP); - // Data - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Data & i); + // Opcode + T55xxWriteBit(1); + T55xxWriteBit(0); //Page 0 + if (PwdMode == 1){ + // Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(Pwd & i); + } + // Lock bit + T55xxWriteBit(0); - // Block - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); + // Data + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(Data & i); - // Now perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, - // so wait a little more) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - SpinDelay(20); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // Block + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit(Block & i); + + // Now perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + SpinDelay(20); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); } // Read one card block in page 0 void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) { - uint8_t *dest = get_bigbufptr_recvrespbuf(); - uint16_t bufferlength = T55xx_SAMPLES_SIZE; - uint32_t i = 0; + uint8_t *dest = (uint8_t *)BigBuf; + //int m=0, i=0; //enio adjustment 12/10/14 + uint32_t m=0, i=0; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + m = sizeof(BigBuf); + // 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. + FpgaSetupSsc(); - // Clear destination buffer before sending the command 0x80 = average. - memset(dest, 0x80, bufferlength); + LED_D_ON(); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Set up FPGA, 125kHz - // Wait for config.. (192+8190xPOW)x8 == 67ms - LFSetupFPGAForADC(0, true); + // Give it a bit of time for the resonant antenna to settle. + // And for the tag to fully power up + SpinDelay(150); + + // Now start writting + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelayUs(START_GAP); + + // Opcode + T55xxWriteBit(1); + T55xxWriteBit(0); //Page 0 + if (PwdMode == 1){ + // Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(Pwd & i); + } + // Lock bit + T55xxWriteBit(0); + // Block + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit(Block & i); + + // Turn field on to read the response + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // Now do the acquisition + i = 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) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + // we don't care about actual value, only if it's more or less than a + // threshold essentially we capture zero crossings for later analysis + // if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; + i++; + if (i >= m) break; + } + } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelayUs(START_GAP); - - // Opcode - T55xxWriteBit(1); - T55xxWriteBit(0); //Page 0 - if (PwdMode == 1){ - // Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Lock bit - T55xxWriteBit(0); - // Block - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); - - // Turn field on to read the response - TurnReadLFOn(); - - // Now do the acquisition - i = 0; - for(;;) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - //AT91C_BASE_SSC->SSC_THR = 0xff; - LED_D_ON(); - } - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - ++i; - LED_D_OFF(); - if (i >= bufferlength) break; - } - } - - cmd_send(CMD_ACK,0,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); + LED_D_OFF(); + DbpString("DONE!"); } // Read card traceability data (page 1) void T55xxReadTrace(void){ - uint8_t *dest = get_bigbufptr_recvrespbuf(); - uint16_t bufferlength = T55xx_SAMPLES_SIZE; - uint32_t i = 0; - - // Clear destination buffer before sending the command 0x80 = average - memset(dest, 0x80, bufferlength); - - LFSetupFPGAForADC(0, true); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelayUs(START_GAP); - - // Opcode - T55xxWriteBit(1); - T55xxWriteBit(1); //Page 1 - - // Turn field on to read the response - TurnReadLFOn(); - - // Now do the acquisition - for(;;) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - ++i; - LED_D_OFF(); - - if (i >= bufferlength) break; - } - } - - cmd_send(CMD_ACK,0,0,0,0,0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); -} + uint8_t *dest = (uint8_t *)BigBuf; + int m=0, i=0; -void TurnReadLFOn(){ - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Give it a bit of time for the resonant antenna to settle. - //SpinDelay(30); - SpinDelayUs(8*150); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + m = sizeof(BigBuf); + // 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. + FpgaSetupSsc(); + + LED_D_ON(); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // Give it a bit of time for the resonant antenna to settle. + // And for the tag to fully power up + SpinDelay(150); + + // Now start writting + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelayUs(START_GAP); + + // Opcode + T55xxWriteBit(1); + T55xxWriteBit(1); //Page 1 + + // Turn field on to read the response + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // Now do the acquisition + i = 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) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + i++; + if (i >= m) break; + } + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_D_OFF(); + DbpString("DONE!"); } /*-------------- Cloning routines -----------*/ // Copy HID id to card and setup block 0 config void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) { - int data1=0, data2=0, data3=0, data4=0, data5=0, data6=0; //up to six blocks for long format - int last_block = 0; - - if (longFMT){ - // Ensure no more than 84 bits supplied - if (hi2>0xFFFFF) { - DbpString("Tags can only have 84 bits."); - return; - } - // Build the 6 data blocks for supplied 84bit ID - last_block = 6; - data1 = 0x1D96A900; // load preamble (1D) & long format identifier (9E manchester encoded) - for (int i=0;i<4;i++) { - if (hi2 & (1<<(19-i))) - data1 |= (1<<(((3-i)*2)+1)); // 1 -> 10 - else - data1 |= (1<<((3-i)*2)); // 0 -> 01 - } - - data2 = 0; - for (int i=0;i<16;i++) { - if (hi2 & (1<<(15-i))) - data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data2 |= (1<<((15-i)*2)); // 0 -> 01 + int data1=0, data2=0, data3=0, data4=0, data5=0, data6=0; //up to six blocks for long format + int last_block = 0; + + if (longFMT){ + // Ensure no more than 84 bits supplied + if (hi2>0xFFFFF) { + DbpString("Tags can only have 84 bits."); + return; + } + // Build the 6 data blocks for supplied 84bit ID + last_block = 6; + data1 = 0x1D96A900; // load preamble (1D) & long format identifier (9E manchester encoded) + for (int i=0;i<4;i++) { + if (hi2 & (1<<(19-i))) + data1 |= (1<<(((3-i)*2)+1)); // 1 -> 10 + else + data1 |= (1<<((3-i)*2)); // 0 -> 01 + } + + data2 = 0; + for (int i=0;i<16;i++) { + if (hi2 & (1<<(15-i))) + data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data2 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data3 = 0; + for (int i=0;i<16;i++) { + if (hi & (1<<(31-i))) + data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data3 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data4 = 0; + for (int i=0;i<16;i++) { + if (hi & (1<<(15-i))) + data4 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data4 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data5 = 0; + for (int i=0;i<16;i++) { + if (lo & (1<<(31-i))) + data5 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data5 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data6 = 0; + for (int i=0;i<16;i++) { + if (lo & (1<<(15-i))) + data6 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data6 |= (1<<((15-i)*2)); // 0 -> 01 + } } - - data3 = 0; - for (int i=0;i<16;i++) { - if (hi & (1<<(31-i))) - data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data3 |= (1<<((15-i)*2)); // 0 -> 01 - } - - data4 = 0; - for (int i=0;i<16;i++) { - if (hi & (1<<(15-i))) - data4 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data4 |= (1<<((15-i)*2)); // 0 -> 01 + else { + // Ensure no more than 44 bits supplied + if (hi>0xFFF) { + DbpString("Tags can only have 44 bits."); + return; + } + + // Build the 3 data blocks for supplied 44bit ID + last_block = 3; + + data1 = 0x1D000000; // load preamble + + for (int i=0;i<12;i++) { + if (hi & (1<<(11-i))) + data1 |= (1<<(((11-i)*2)+1)); // 1 -> 10 + else + data1 |= (1<<((11-i)*2)); // 0 -> 01 + } + + data2 = 0; + for (int i=0;i<16;i++) { + if (lo & (1<<(31-i))) + data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data2 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data3 = 0; + for (int i=0;i<16;i++) { + if (lo & (1<<(15-i))) + data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data3 |= (1<<((15-i)*2)); // 0 -> 01 + } } - - data5 = 0; - for (int i=0;i<16;i++) { - if (lo & (1<<(31-i))) - data5 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data5 |= (1<<((15-i)*2)); // 0 -> 01 - } - - data6 = 0; - for (int i=0;i<16;i++) { - if (lo & (1<<(15-i))) - data6 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data6 |= (1<<((15-i)*2)); // 0 -> 01 + + LED_D_ON(); + // Program the data blocks for supplied ID + // and the block 0 for HID format + T55xxWriteBlock(data1,1,0,0); + T55xxWriteBlock(data2,2,0,0); + T55xxWriteBlock(data3,3,0,0); + + if (longFMT) { // if long format there are 6 blocks + T55xxWriteBlock(data4,4,0,0); + T55xxWriteBlock(data5,5,0,0); + T55xxWriteBlock(data6,6,0,0); } - } - else { - // Ensure no more than 44 bits supplied - if (hi>0xFFF) { - DbpString("Tags can only have 44 bits."); - return; - } - - // Build the 3 data blocks for supplied 44bit ID - last_block = 3; - - data1 = 0x1D000000; // load preamble - - for (int i=0;i<12;i++) { - if (hi & (1<<(11-i))) - data1 |= (1<<(((11-i)*2)+1)); // 1 -> 10 - else - data1 |= (1<<((11-i)*2)); // 0 -> 01 - } - - data2 = 0; - for (int i=0;i<16;i++) { - if (lo & (1<<(31-i))) - data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data2 |= (1<<((15-i)*2)); // 0 -> 01 - } - - data3 = 0; - for (int i=0;i<16;i++) { - if (lo & (1<<(15-i))) - data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10 - else - data3 |= (1<<((15-i)*2)); // 0 -> 01 - } - } - - LED_D_ON(); - // Program the data blocks for supplied ID - // and the block 0 for HID format - T55xxWriteBlock(data1,1,0,0); - T55xxWriteBlock(data2,2,0,0); - T55xxWriteBlock(data3,3,0,0); - - if (longFMT) { // if long format there are 6 blocks - T55xxWriteBlock(data4,4,0,0); - T55xxWriteBlock(data5,5,0,0); - T55xxWriteBlock(data6,6,0,0); - } - - // Config for HID (RF/50, FSK2a, Maxblock=3 for short/6 for long) - T55xxWriteBlock(T55x7_BITRATE_RF_50 | - T55x7_MODULATION_FSK2a | - last_block << T55x7_MAXBLOCK_SHIFT, - 0,0,0); - - LED_D_OFF(); - - DbpString("DONE!"); + + // Config for HID (RF/50, FSK2a, Maxblock=3 for short/6 for long) + T55xxWriteBlock(T55x7_BITRATE_RF_50 | + T55x7_MODULATION_FSK2a | + last_block << T55x7_MAXBLOCK_SHIFT, + 0,0,0); + + LED_D_OFF(); + + DbpString("DONE!"); } void CopyIOtoT55x7(uint32_t hi, uint32_t lo, uint8_t longFMT) { - int data1=0, data2=0; //up to six blocks for long format - + int data1=0, data2=0; //up to six blocks for long format + data1 = hi; // load preamble data2 = lo; @@ -1297,11 +1214,11 @@ void CopyIOtoT55x7(uint32_t hi, uint32_t lo, uint8_t longFMT) // and the block 0 for HID format T55xxWriteBlock(data1,1,0,0); T55xxWriteBlock(data2,2,0,0); - + //Config Block T55xxWriteBlock(0x00147040,0,0,0); LED_D_OFF(); - + DbpString("DONE!"); } @@ -1311,148 +1228,148 @@ void CopyIOtoT55x7(uint32_t hi, uint32_t lo, uint8_t longFMT) void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo) { - int i, id_bit; - uint64_t id = EM410X_HEADER; - uint64_t rev_id = 0; // reversed ID - int c_parity[4]; // column parity - int r_parity = 0; // row parity - uint32_t clock = 0; + int i, id_bit; + uint64_t id = EM410X_HEADER; + uint64_t rev_id = 0; // reversed ID + int c_parity[4]; // column parity + int r_parity = 0; // row parity + uint32_t clock = 0; - // Reverse ID bits given as parameter (for simpler operations) - for (i = 0; i < EM410X_ID_LENGTH; ++i) { - if (i < 32) { - rev_id = (rev_id << 1) | (id_lo & 1); - id_lo >>= 1; - } else { - rev_id = (rev_id << 1) | (id_hi & 1); - id_hi >>= 1; - } - } + // Reverse ID bits given as parameter (for simpler operations) + for (i = 0; i < EM410X_ID_LENGTH; ++i) { + if (i < 32) { + rev_id = (rev_id << 1) | (id_lo & 1); + id_lo >>= 1; + } else { + rev_id = (rev_id << 1) | (id_hi & 1); + id_hi >>= 1; + } + } - for (i = 0; i < EM410X_ID_LENGTH; ++i) { - id_bit = rev_id & 1; + for (i = 0; i < EM410X_ID_LENGTH; ++i) { + id_bit = rev_id & 1; - if (i % 4 == 0) { - // Don't write row parity bit at start of parsing - if (i) - id = (id << 1) | r_parity; - // Start counting parity for new row - r_parity = id_bit; - } else { - // Count row parity - r_parity ^= id_bit; - } + if (i % 4 == 0) { + // Don't write row parity bit at start of parsing + if (i) + id = (id << 1) | r_parity; + // Start counting parity for new row + r_parity = id_bit; + } else { + // Count row parity + r_parity ^= id_bit; + } - // First elements in column? - if (i < 4) - // Fill out first elements - c_parity[i] = id_bit; - else - // Count column parity - c_parity[i % 4] ^= id_bit; + // First elements in column? + if (i < 4) + // Fill out first elements + c_parity[i] = id_bit; + else + // Count column parity + c_parity[i % 4] ^= id_bit; - // Insert ID bit - id = (id << 1) | id_bit; - rev_id >>= 1; - } + // Insert ID bit + id = (id << 1) | id_bit; + rev_id >>= 1; + } - // Insert parity bit of last row - id = (id << 1) | r_parity; + // Insert parity bit of last row + id = (id << 1) | r_parity; - // Fill out column parity at the end of tag - for (i = 0; i < 4; ++i) - id = (id << 1) | c_parity[i]; + // Fill out column parity at the end of tag + for (i = 0; i < 4; ++i) + id = (id << 1) | c_parity[i]; - // Add stop bit - id <<= 1; + // Add stop bit + id <<= 1; - Dbprintf("Started writing %s tag ...", card ? "T55x7":"T5555"); - LED_D_ON(); + Dbprintf("Started writing %s tag ...", card ? "T55x7":"T5555"); + LED_D_ON(); - // Write EM410x ID - T55xxWriteBlock((uint32_t)(id >> 32), 1, 0, 0); - T55xxWriteBlock((uint32_t)id, 2, 0, 0); + // Write EM410x ID + T55xxWriteBlock((uint32_t)(id >> 32), 1, 0, 0); + T55xxWriteBlock((uint32_t)id, 2, 0, 0); - // Config for EM410x (RF/64, Manchester, Maxblock=2) - if (card) { - // Clock rate is stored in bits 8-15 of the card value - clock = (card & 0xFF00) >> 8; - Dbprintf("Clock rate: %d", clock); - switch (clock) - { - case 32: - clock = T55x7_BITRATE_RF_32; - break; - case 16: - clock = T55x7_BITRATE_RF_16; - break; - case 0: - // A value of 0 is assumed to be 64 for backwards-compatibility - // Fall through... - case 64: - clock = T55x7_BITRATE_RF_64; - break; - default: - Dbprintf("Invalid clock rate: %d", clock); - return; - } + // Config for EM410x (RF/64, Manchester, Maxblock=2) + if (card) { + // Clock rate is stored in bits 8-15 of the card value + clock = (card & 0xFF00) >> 8; + Dbprintf("Clock rate: %d", clock); + switch (clock) + { + case 32: + clock = T55x7_BITRATE_RF_32; + break; + case 16: + clock = T55x7_BITRATE_RF_16; + break; + case 0: + // A value of 0 is assumed to be 64 for backwards-compatibility + // Fall through... + case 64: + clock = T55x7_BITRATE_RF_64; + break; + default: + Dbprintf("Invalid clock rate: %d", clock); + return; + } - // Writing configuration for T55x7 tag - T55xxWriteBlock(clock | - T55x7_MODULATION_MANCHESTER | - 2 << T55x7_MAXBLOCK_SHIFT, - 0, 0, 0); - } - else - // Writing configuration for T5555(Q5) tag - T55xxWriteBlock(0x1F << T5555_BITRATE_SHIFT | - T5555_MODULATION_MANCHESTER | - 2 << T5555_MAXBLOCK_SHIFT, - 0, 0, 0); + // Writing configuration for T55x7 tag + T55xxWriteBlock(clock | + T55x7_MODULATION_MANCHESTER | + 2 << T55x7_MAXBLOCK_SHIFT, + 0, 0, 0); + } + else + // Writing configuration for T5555(Q5) tag + T55xxWriteBlock(0x1F << T5555_BITRATE_SHIFT | + T5555_MODULATION_MANCHESTER | + 2 << T5555_MAXBLOCK_SHIFT, + 0, 0, 0); - LED_D_OFF(); - Dbprintf("Tag %s written with 0x%08x%08x\n", card ? "T55x7":"T5555", - (uint32_t)(id >> 32), (uint32_t)id); + LED_D_OFF(); + Dbprintf("Tag %s written with 0x%08x%08x\n", card ? "T55x7":"T5555", + (uint32_t)(id >> 32), (uint32_t)id); } // Clone Indala 64-bit tag by UID to T55x7 void CopyIndala64toT55x7(int hi, int lo) { - //Program the 2 data blocks for supplied 64bit UID - // and the block 0 for Indala64 format - T55xxWriteBlock(hi,1,0,0); - T55xxWriteBlock(lo,2,0,0); - //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=2) - T55xxWriteBlock(T55x7_BITRATE_RF_32 | - T55x7_MODULATION_PSK1 | - 2 << T55x7_MAXBLOCK_SHIFT, - 0, 0, 0); - //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data) - // T5567WriteBlock(0x603E1042,0); + //Program the 2 data blocks for supplied 64bit UID + // and the block 0 for Indala64 format + T55xxWriteBlock(hi,1,0,0); + T55xxWriteBlock(lo,2,0,0); + //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=2) + T55xxWriteBlock(T55x7_BITRATE_RF_32 | + T55x7_MODULATION_PSK1 | + 2 << T55x7_MAXBLOCK_SHIFT, + 0, 0, 0); + //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data) + // T5567WriteBlock(0x603E1042,0); - DbpString("DONE!"); + DbpString("DONE!"); } void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int uid6, int uid7) { - //Program the 7 data blocks for supplied 224bit UID - // and the block 0 for Indala224 format - T55xxWriteBlock(uid1,1,0,0); - T55xxWriteBlock(uid2,2,0,0); - T55xxWriteBlock(uid3,3,0,0); - T55xxWriteBlock(uid4,4,0,0); - T55xxWriteBlock(uid5,5,0,0); - T55xxWriteBlock(uid6,6,0,0); - T55xxWriteBlock(uid7,7,0,0); - //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=7) - T55xxWriteBlock(T55x7_BITRATE_RF_32 | - T55x7_MODULATION_PSK1 | - 7 << T55x7_MAXBLOCK_SHIFT, - 0,0,0); - //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data) - // T5567WriteBlock(0x603E10E2,0); + //Program the 7 data blocks for supplied 224bit UID + // and the block 0 for Indala224 format + T55xxWriteBlock(uid1,1,0,0); + T55xxWriteBlock(uid2,2,0,0); + T55xxWriteBlock(uid3,3,0,0); + T55xxWriteBlock(uid4,4,0,0); + T55xxWriteBlock(uid5,5,0,0); + T55xxWriteBlock(uid6,6,0,0); + T55xxWriteBlock(uid7,7,0,0); + //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=7) + T55xxWriteBlock(T55x7_BITRATE_RF_32 | + T55x7_MODULATION_PSK1 | + 7 << T55x7_MAXBLOCK_SHIFT, + 0,0,0); + //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data) + // T5567WriteBlock(0x603E10E2,0); - DbpString("DONE!"); + DbpString("DONE!"); } @@ -1460,260 +1377,260 @@ void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int #define max(x,y) ( x GraphBuffer[0]) { - while(i < GraphTraceLen) { - if( !(GraphBuffer[i] > GraphBuffer[i-1]) && GraphBuffer[i] > lmax) - break; - i++; + uint8_t BitStream[256]; + uint8_t Blocks[8][16]; + uint8_t *GraphBuffer = (uint8_t *)BigBuf; + int GraphTraceLen = sizeof(BigBuf); + int i, j, lastval, bitidx, half_switch; + int clock = 64; + int tolerance = clock / 8; + int pmc, block_done; + int lc, warnings = 0; + int num_blocks = 0; + int lmin=128, lmax=128; + uint8_t dir; + + AcquireRawAdcSamples125k(0); + + lmin = 64; + lmax = 192; + + i = 2; + + /* Find first local max/min */ + if(GraphBuffer[1] > GraphBuffer[0]) { + while(i < GraphTraceLen) { + if( !(GraphBuffer[i] > GraphBuffer[i-1]) && GraphBuffer[i] > lmax) + break; + i++; + } + dir = 0; } - dir = 0; - } - else { - while(i < GraphTraceLen) { - if( !(GraphBuffer[i] < GraphBuffer[i-1]) && GraphBuffer[i] < lmin) - break; - i++; + else { + while(i < GraphTraceLen) { + if( !(GraphBuffer[i] < GraphBuffer[i-1]) && GraphBuffer[i] < lmin) + break; + i++; + } + dir = 1; } - dir = 1; - } - - lastval = i++; - half_switch = 0; - pmc = 0; - block_done = 0; - - 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)) + + lastval = i++; + half_switch = 0; + pmc = 0; + block_done = 0; + + for (bitidx = 0; i < GraphTraceLen; i++) { - lc = i - lastval; - lastval = i; - - // Switch depending on lc length: - // Tolerance is 1/8 of clock rate (arbitrary) - if (abs(lc-clock/4) < tolerance) { - // 16T0 - if((i - pmc) == lc) { /* 16T0 was previous one */ - /* It's a PMC ! */ - i += (128+127+16+32+33+16)-1; - lastval = i; - pmc = 0; - block_done = 1; - } - else { - pmc = i; - } - } else if (abs(lc-clock/2) < tolerance) { - // 32TO - if((i - pmc) == lc) { /* 16T0 was previous one */ - /* It's a PMC ! */ - i += (128+127+16+32+33)-1; - lastval = i; - pmc = 0; - block_done = 1; - } - else if(half_switch == 1) { - BitStream[bitidx++] = 0; - half_switch = 0; - } - else - half_switch++; - } else if (abs(lc-clock) < tolerance) { - // 64TO - BitStream[bitidx++] = 1; - } else { - // Error - warnings++; - if (warnings > 10) + if ( (GraphBuffer[i-1] > GraphBuffer[i] && dir == 1 && GraphBuffer[i] > lmax) || (GraphBuffer[i-1] < GraphBuffer[i] && dir == 0 && GraphBuffer[i] < lmin)) { - Dbprintf("Error: too many detection errors, aborting."); - return 0; + lc = i - lastval; + lastval = i; + + // Switch depending on lc length: + // Tolerance is 1/8 of clock rate (arbitrary) + if (abs(lc-clock/4) < tolerance) { + // 16T0 + if((i - pmc) == lc) { /* 16T0 was previous one */ + /* It's a PMC ! */ + i += (128+127+16+32+33+16)-1; + lastval = i; + pmc = 0; + block_done = 1; + } + else { + pmc = i; + } + } else if (abs(lc-clock/2) < tolerance) { + // 32TO + if((i - pmc) == lc) { /* 16T0 was previous one */ + /* It's a PMC ! */ + i += (128+127+16+32+33)-1; + lastval = i; + pmc = 0; + block_done = 1; + } + else if(half_switch == 1) { + BitStream[bitidx++] = 0; + half_switch = 0; + } + else + half_switch++; + } else if (abs(lc-clock) < tolerance) { + // 64TO + BitStream[bitidx++] = 1; + } else { + // Error + warnings++; + if (warnings > 10) + { + Dbprintf("Error: too many detection errors, aborting."); + return 0; + } + } + + 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]; + } + num_blocks++; + } + bitidx = 0; + block_done = 0; + half_switch = 0; + } + if(i < GraphTraceLen) + { + if (GraphBuffer[i-1] > GraphBuffer[i]) dir=0; + else dir = 1; + } } - } - - 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]; - } - num_blocks++; - } - bitidx = 0; - block_done = 0; - half_switch = 0; - } - if(i < GraphTraceLen) - { - if (GraphBuffer[i-1] > GraphBuffer[i]) dir=0; - else dir = 1; + if(bitidx==255) + bitidx=0; + warnings = 0; + if(num_blocks == 4) break; } - } - if(bitidx==255) - bitidx=0; - warnings = 0; - if(num_blocks == 4) break; - } - memcpy(outBlocks, Blocks, 16*num_blocks); - return num_blocks; + memcpy(outBlocks, Blocks, 16*num_blocks); + return num_blocks; } int IsBlock0PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled - return 1; - if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? - return 1; - return 0; + // Assume RFU means 0 :) + if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled + return 1; + if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? + return 1; + return 0; } int IsBlock1PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if(Block[10] == 0 && Block[11] == 0 && Block[12] == 0 && Block[13] == 0) - if((Block[14] & 0x7f) <= 9 && Block[15] <= 9) - return 1; - - return 0; + // Assume RFU means 0 :) + if(Block[10] == 0 && Block[11] == 0 && Block[12] == 0 && Block[13] == 0) + if((Block[14] & 0x7f) <= 9 && Block[15] <= 9) + return 1; + + return 0; } #define ALLOC 16 void ReadPCF7931() { - uint8_t Blocks[8][17]; - uint8_t tmpBlocks[4][16]; - int i, j, ind, ind2, n; - int num_blocks = 0; - int max_blocks = 8; - int ident = 0; - int error = 0; - int tries = 0; - - memset(Blocks, 0, 8*17*sizeof(uint8_t)); - - do { - memset(tmpBlocks, 0, 4*16*sizeof(uint8_t)); - n = DemodPCF7931((uint8_t**)tmpBlocks); - if(!n) - error++; - if(error==10 && num_blocks == 0) { - Dbprintf("Error, no tag or bad tag"); - return; - } - else if (tries==20 || error==10) { - Dbprintf("Error reading the tag"); - Dbprintf("Here is the partial content"); - goto end; - } - - for(i=0; i= 0; ind--,ind2--) { - if(ind2 < 0) - ind2 = max_blocks; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } - for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { - if(ind2 > max_blocks) - ind2 = 0; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } - } - } + else if (tries==20 || error==10) { + Dbprintf("Error reading the tag"); + Dbprintf("Here is the partial content"); + goto end; } - } - } - tries++; - if (BUTTON_PRESS()) return; - } while (num_blocks != max_blocks); + + for(i=0; i= 0; ind--,ind2--) { + if(ind2 < 0) + ind2 = max_blocks; + if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found + // Dbprintf("Tmp %d -> Block %d", ind, ind2); + memcpy(Blocks[ind2], tmpBlocks[ind], 16); + Blocks[ind2][ALLOC] = 1; + num_blocks++; + if(num_blocks == max_blocks) goto end; + } + } + for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { + if(ind2 > max_blocks) + ind2 = 0; + if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found + // Dbprintf("Tmp %d -> Block %d", ind, ind2); + memcpy(Blocks[ind2], tmpBlocks[ind], 16); + Blocks[ind2][ALLOC] = 1; + num_blocks++; + if(num_blocks == max_blocks) goto end; + } + } + } + } + } + } + } + tries++; + if (BUTTON_PRESS()) return; + } while (num_blocks != max_blocks); end: - Dbprintf("-----------------------------------------"); - Dbprintf("Memory content:"); - Dbprintf("-----------------------------------------"); - for(i=0; i", i); - } - Dbprintf("-----------------------------------------"); - - return ; + Dbprintf("-----------------------------------------"); + Dbprintf("Memory content:"); + Dbprintf("-----------------------------------------"); + for(i=0; i", i); + } + Dbprintf("-----------------------------------------"); + + return ; } @@ -1737,20 +1654,20 @@ uint8_t * fwd_write_ptr; //forwardlink bit pointer //==================================================================== //-------------------------------------------------------------------- uint8_t Prepare_Cmd( uint8_t cmd ) { - //-------------------------------------------------------------------- - - *forward_ptr++ = 0; //start bit - *forward_ptr++ = 0; //second pause for 4050 code - - *forward_ptr++ = cmd; - cmd >>= 1; - *forward_ptr++ = cmd; - cmd >>= 1; - *forward_ptr++ = cmd; - cmd >>= 1; - *forward_ptr++ = cmd; - - return 6; //return number of emited bits + //-------------------------------------------------------------------- + + *forward_ptr++ = 0; //start bit + *forward_ptr++ = 0; //second pause for 4050 code + + *forward_ptr++ = cmd; + cmd >>= 1; + *forward_ptr++ = cmd; + cmd >>= 1; + *forward_ptr++ = cmd; + cmd >>= 1; + *forward_ptr++ = cmd; + + return 6; //return number of emited bits } //==================================================================== @@ -1760,21 +1677,21 @@ uint8_t Prepare_Cmd( uint8_t cmd ) { //-------------------------------------------------------------------- uint8_t Prepare_Addr( uint8_t addr ) { - //-------------------------------------------------------------------- - - register uint8_t line_parity; - - uint8_t i; - line_parity = 0; - for(i=0;i<6;i++) { - *forward_ptr++ = addr; - line_parity ^= addr; - addr >>= 1; - } - - *forward_ptr++ = (line_parity & 1); - - return 7; //return number of emited bits + //-------------------------------------------------------------------- + + register uint8_t line_parity; + + uint8_t i; + line_parity = 0; + for(i=0;i<6;i++) { + *forward_ptr++ = addr; + line_parity ^= addr; + addr >>= 1; + } + + *forward_ptr++ = (line_parity & 1); + + return 7; //return number of emited bits } //==================================================================== @@ -1784,36 +1701,36 @@ uint8_t Prepare_Addr( uint8_t addr ) { //-------------------------------------------------------------------- uint8_t Prepare_Data( uint16_t data_low, uint16_t data_hi) { - //-------------------------------------------------------------------- - - register uint8_t line_parity; - register uint8_t column_parity; - register uint8_t i, j; - register uint16_t data; - - data = data_low; - column_parity = 0; - - for(i=0; i<4; i++) { - line_parity = 0; - for(j=0; j<8; j++) { - line_parity ^= data; - column_parity ^= (data & 1) << j; - *forward_ptr++ = data; - data >>= 1; + //-------------------------------------------------------------------- + + register uint8_t line_parity; + register uint8_t column_parity; + register uint8_t i, j; + register uint16_t data; + + data = data_low; + column_parity = 0; + + for(i=0; i<4; i++) { + line_parity = 0; + for(j=0; j<8; j++) { + line_parity ^= data; + column_parity ^= (data & 1) << j; + *forward_ptr++ = data; + data >>= 1; + } + *forward_ptr++ = line_parity; + if(i == 1) + data = data_hi; } - *forward_ptr++ = line_parity; - if(i == 1) - data = data_hi; - } - - for(j=0; j<8; j++) { - *forward_ptr++ = column_parity; - column_parity >>= 1; - } - *forward_ptr = 0; - - return 45; //return number of emited bits + + for(j=0; j<8; j++) { + *forward_ptr++ = column_parity; + column_parity >>= 1; + } + *forward_ptr = 0; + + return 45; //return number of emited bits } //==================================================================== @@ -1822,123 +1739,116 @@ uint8_t Prepare_Data( uint16_t data_low, uint16_t data_hi) { // fwd_bit_count set with number of bits to be sent //==================================================================== void SendForward(uint8_t fwd_bit_count) { - - fwd_write_ptr = forwardLink_data; - fwd_bit_sz = fwd_bit_count; - - LED_D_ON(); - - //Field on - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - - // Give it a bit of time for the resonant antenna to settle. - // And for the tag to fully power up - SpinDelay(150); - - // force 1st mod pulse (start gap must be longer for 4305) - fwd_bit_sz--; //prepare next bit modulation - fwd_write_ptr++; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - SpinDelayUs(55*8); //55 cycles off (8us each)for 4305 - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on - SpinDelayUs(16*8); //16 cycles on (8us each) - - // now start writting - while(fwd_bit_sz-- > 0) { //prepare next bit modulation - if(((*fwd_write_ptr++) & 1) == 1) - SpinDelayUs(32*8); //32 cycles at 125Khz (8us each) - else { - //These timings work for 4469/4269/4305 (with the 55*8 above) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - SpinDelayUs(23*8); //16-4 cycles off (8us each) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on - SpinDelayUs(9*8); //16 cycles on (8us each) + + fwd_write_ptr = forwardLink_data; + fwd_bit_sz = fwd_bit_count; + + LED_D_ON(); + + //Field on + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // Give it a bit of time for the resonant antenna to settle. + // And for the tag to fully power up + SpinDelay(150); + + // force 1st mod pulse (start gap must be longer for 4305) + fwd_bit_sz--; //prepare next bit modulation + fwd_write_ptr++; + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + SpinDelayUs(55*8); //55 cycles off (8us each)for 4305 + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on + SpinDelayUs(16*8); //16 cycles on (8us each) + + // now start writting + while(fwd_bit_sz-- > 0) { //prepare next bit modulation + if(((*fwd_write_ptr++) & 1) == 1) + SpinDelayUs(32*8); //32 cycles at 125Khz (8us each) + else { + //These timings work for 4469/4269/4305 (with the 55*8 above) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + SpinDelayUs(23*8); //16-4 cycles off (8us each) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on + SpinDelayUs(9*8); //16 cycles on (8us each) + } } - } } void EM4xLogin(uint32_t Password) { - - uint8_t fwd_bit_count; - - forward_ptr = forwardLink_data; - fwd_bit_count = Prepare_Cmd( FWD_CMD_LOGIN ); - fwd_bit_count += Prepare_Data( Password&0xFFFF, Password>>16 ); - - SendForward(fwd_bit_count); - - //Wait for command to complete - SpinDelay(20); - + + uint8_t fwd_bit_count; + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_LOGIN ); + fwd_bit_count += Prepare_Data( Password&0xFFFF, Password>>16 ); + + SendForward(fwd_bit_count); + + //Wait for command to complete + SpinDelay(20); + } void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { - - uint8_t *dest = (uint8_t *)BigBuf; - uint16_t bufferlength = 12000; - 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); - - forward_ptr = forwardLink_data; - fwd_bit_count = Prepare_Cmd( FWD_CMD_READ ); - fwd_bit_count += Prepare_Addr( Address ); - - // 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. - FpgaSetupSsc(); - - SendForward(fwd_bit_count); - - // // Turn field on to read the response - // TurnReadLFOn(); - - // Now do the acquisition - i = 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) { - dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - ++i; - if (i >= bufferlength) break; - } - } - - cmd_send(CMD_ACK,0,0,0,0,0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); + uint8_t fwd_bit_count; + uint8_t *dest = (uint8_t *)BigBuf; + int m=0, i=0; + + //If password mode do login + if (PwdMode == 1) EM4xLogin(Pwd); + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_READ ); + fwd_bit_count += Prepare_Addr( Address ); + + m = sizeof(BigBuf); + // 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. + FpgaSetupSsc(); + + SendForward(fwd_bit_count); + + // Now do the acquisition + i = 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) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + i++; + if (i >= m) break; + } + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_D_OFF(); } void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { - - uint8_t fwd_bit_count; - - //If password mode do login - if (PwdMode == 1) EM4xLogin(Pwd); - - forward_ptr = forwardLink_data; - fwd_bit_count = Prepare_Cmd( FWD_CMD_WRITE ); - fwd_bit_count += Prepare_Addr( Address ); - fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 ); - - SendForward(fwd_bit_count); - - //Wait for write to complete - SpinDelay(20); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_D_OFF(); + + uint8_t fwd_bit_count; + + //If password mode do login + if (PwdMode == 1) EM4xLogin(Pwd); + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_WRITE ); + fwd_bit_count += Prepare_Addr( Address ); + fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 ); + + SendForward(fwd_bit_count); + + //Wait for write to complete + SpinDelay(20); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_D_OFF(); } diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index fc480a38..8541553b 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -15,9 +15,6 @@ #include "mifarecmd.h" #include "apps.h" -#include "util.h" -#include "desfire.h" -#include "../common/crc.h" //----------------------------------------------------------------------------- // Select, Authenticate, Read a MIFARE tag. @@ -76,75 +73,13 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); LED_B_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - - -void MifareUC_Auth1(uint8_t arg0, uint8_t *datain){ - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16]; - uint8_t uid[10]; - uint32_t cuid; - - // clear trace - iso14a_clear_trace(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card, something went wrong before auth"); - }; - - if(mifare_ultra_auth1(cuid, dataoutbuf)){ - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part1: Fail."); - } - - isOK=1; - if (MF_DBGLEVEL >= 2) DbpString("AUTH 1 FINISHED"); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,cuid,0,dataoutbuf,11); - LED_B_OFF(); - // Thats it... - LEDsoff(); -} -void MifareUC_Auth2(uint32_t arg0, uint8_t *datain){ - // params - uint32_t cuid = arg0; - uint8_t key[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16]; - - memcpy(key, datain, 16); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - if(mifare_ultra_auth2(cuid, key, dataoutbuf)){ - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail..."); - } - isOK=1; - if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED"); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,11); - LED_B_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -265,38 +200,37 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LEDsoff(); } -void MifareUReadCard(uint8_t arg0, int arg1, uint8_t *datain) + +void MifareUReadCard(uint8_t arg0, uint8_t *datain) { - // params - uint8_t sectorNo = arg0; - int Pages=arg1; - int count_Pages=0; - // variables - byte_t isOK = 0; - byte_t dataoutbuf[176]; - uint8_t uid[10]; - uint32_t cuid; + // params + uint8_t sectorNo = arg0; + + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16 * 4]; + uint8_t uid[10]; + uint32_t cuid; - // clear trace - iso14a_clear_trace(); + // clear trace + iso14a_clear_trace(); +// iso14a_set_tracing(false); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - Dbprintf("Pages %d",Pages); while (true) { if(!iso14443a_select_card(uid, NULL, &cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; - for(int sec=0;sec= 1) Dbprintf("Read block %d error",sec); break; - }else{ - count_Pages++; }; } if(mifare_ultra_halt(cuid)) { @@ -307,18 +241,16 @@ void MifareUReadCard(uint8_t arg0, int arg1, uint8_t *datain) isOK = 1; break; } - Dbprintf("Pages read %d",count_Pages); - if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); + + if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); LED_B_ON(); - if (Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); - if (Pages==44 && count_Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); - if (Pages==44 && count_Pages>16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,176); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); LED_B_OFF(); - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } @@ -505,7 +437,7 @@ void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) } // Return 1 if the nonce is invalid else return 0 -int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t * parity) { +int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) { return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; @@ -541,7 +473,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint32_t auth1_time, auth2_time; static uint16_t delta_time; @@ -562,7 +494,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat WDT_HIT(); davg = dmax = 0; - dmin = 2000; + dmin = 2000; delta_time = 0; for (rtr = 0; rtr < 17; rtr++) { @@ -599,7 +531,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat }; nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 - for (i = 141; i < 1200; i++) { + for (i = 101; i < 1200; i++) { nttmp = prng_successor(nttmp, 1); if (nttmp == nt2) break; } @@ -617,7 +549,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat } } - if (rtr <= 1) return; + if (rtr <= 1) return; davg = (davg + (rtr - 1)/2) / (rtr - 1); @@ -636,18 +568,9 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // get crypted nonces for target sector for(i=0; i < 2; i++) { // look for exactly two different nonces - WDT_HIT(); - if(BUTTON_PRESS()) { - DbpString("Nested: cancelled"); - crypto1_destroy(pcs); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - return; - } - target_nt[i] = 0; while(target_nt[i] == 0) { // continue until we have an unambiguous nonce - + // prepare next select. No need to power down the card. if(mifare_classic_halt(pcs, cuid)) { if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); @@ -707,7 +630,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat if (target_nt[i] == 0 && j == dmax+1 && MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (all invalid)", i+1); } } - + LED_C_OFF(); // ----------------------------- crypto1 destroy @@ -941,15 +864,15 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai uint8_t d_block[18] = {0x00}; uint32_t cuid; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - + // reset FPGA and LED if (workFlags & 0x08) { LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - + iso14a_clear_trace(); iso14a_set_tracing(TRUE); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -1067,7 +990,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - + iso14a_clear_trace(); iso14a_set_tracing(TRUE); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -1148,75 +1071,3 @@ void MifareCIdent(){ // // DESFIRE // - -void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16]; - uint8_t uid[10]; - uint32_t cuid; - - // clear trace - iso14a_clear_trace(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card, something went wrong before auth"); - }; - - if(mifare_desfire_des_auth1(cuid, dataoutbuf)){ - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part1: Fail."); - } - - isOK=1; - if (MF_DBGLEVEL >= 2) DbpString("AUTH 1 FINISHED"); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,cuid,0,dataoutbuf,11); - LED_B_OFF(); - - // Thats it... - //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - -void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ - // params - uint32_t cuid = arg0; - uint8_t key[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16]; - - memcpy(key, datain, 16); - // clear trace - //iso14a_clear_trace(); - //iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - -// Dbprintf("Sending %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", -// key[0],key[1],key[2],key[3],key[4],key[5],key[6],key[7],key[8], -// key[9],key[10],key[11],key[12],key[13],key[14],key[15]); - - if(mifare_desfire_des_auth2(cuid, key, dataoutbuf)){ - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail..."); - } - isOK=1; - if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED"); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,12); - LED_B_OFF(); - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} \ No newline at end of file diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 2c5a7e3f..3c00a343 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -13,15 +13,16 @@ #ifndef __MIFARECMD_H #define __MIFARECMD_H -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "../common/iso14443crc.h" +#include "iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" -#include "../include/common.h" +#include "common.h" + #endif \ No newline at end of file diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c deleted file mode 100644 index 155538cb..00000000 --- a/armsrc/mifaredesfire.c +++ /dev/null @@ -1,521 +0,0 @@ -#include "mifaredesfire.h" -#include "des.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(){ - - // Make sure it is off. -// FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); -// SpinDelay(300); - - byte_t cardbuf[USB_CMD_DATA_SIZE]; - memset(cardbuf,0,sizeof(cardbuf)); - iso14a_card_select_t *card = (iso14a_card_select_t*)cardbuf; - - iso14a_set_tracing(TRUE); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - int len = iso14443a_select_card(NULL,card,NULL); - - if (!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - OnError(); - 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 ){ - iso14a_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(); - 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]; - uint8_t dataout[USB_CMD_DATA_SIZE]; - byte_t cardbuf[USB_CMD_DATA_SIZE]; - - memset(resp,0,sizeof(resp)); - memset(dataout,0, sizeof(dataout)); - memset(cardbuf,0,sizeof(cardbuf)); - - /* - 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? - */ - iso14a_clear_trace(); - iso14a_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 >= 1) { - Dbprintf("Can't select card"); - } - OnError(); - 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(); - 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(); - 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(); - 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* bigbuffer = get_bigbufptr_recvrespbuf(); - 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(); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - // 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]; - 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 >= 1) { - DbpString("Authentication failed. Card timeout."); - } - OnError(); - return; - } - - if ( resp[2] == 0xaf ){ - } else { - DbpString("Authetication failed. Invalid key number."); - OnError(); - 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 >= 1) { - DbpString("Authentication failed. Card timeout."); - } - OnError(); - 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(); - 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(); - return; - } - - } - } - break; - case 2: - //SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp); - break; - case 3:{ - - //defaultkey - uint8_t keybytes[16]; - if (datain[1] == 0xff){ - memcpy(keybytes,PICC_MASTER_KEY16,16); - } else{ - memcpy(keybytes, datain+1, datalen); - } - - struct desfire_key defaultkey = {0}; - 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(); - return; - } - - cmd[0] = AUTHENTICATE_AES; - cmd[1] = 0x00; //keynumber - len = DesfireAPDU(cmd, 2, resp); - if ( !len ) { - if (MF_DBGLEVEL >= 1) { - DbpString("Authentication failed. Card timeout."); - } - OnError(); - 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 >= 1) { - DbpString("Authentication failed. Card timeout."); - } - OnError(); - 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(); - 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] = {0}; - - uint8_t *resp = ((uint8_t *)BigBuf) + RECV_RESP_OFFSET; - uint8_t *resp_par = ((uint8_t *)BigBuf) + RECV_RESP_PAR_OFFSET; - - wrappedLen = CreateAPDU( cmd, cmd_len, wCmd); - - if (MF_DBGLEVEL >= 4) { - print_result("WCMD <--: ", wCmd, wrappedLen); - } - ReaderTransmit( wCmd, wrappedLen, NULL); - - len = ReaderReceive(resp, 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(){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK,0,0,0,0,0); - LEDsoff(); -} diff --git a/armsrc/mifaredesfire.h b/armsrc/mifaredesfire.h deleted file mode 100644 index 659e0057..00000000 --- a/armsrc/mifaredesfire.h +++ /dev/null @@ -1,15 +0,0 @@ -#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 diff --git a/armsrc/mifaresniff.h b/armsrc/mifaresniff.h index aa2a860f..22daffee 100644 --- a/armsrc/mifaresniff.h +++ b/armsrc/mifaresniff.h @@ -11,16 +11,16 @@ #ifndef __MIFARESNIFF_H #define __MIFARESNIFF_H -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "../common/iso14443crc.h" +#include "iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" -#include "../include/common.h" +#include "common.h" #define SNF_INIT 0 #define SNF_NO_FIELD 1 diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 84f77a35..7c856557 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -9,12 +9,12 @@ // Work with mifare cards. //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "../common/iso14443crc.h" +#include "iso14443crc.h" #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" @@ -23,7 +23,7 @@ int MF_DBGLEVEL = MF_DBG_ALL; // memory management uint8_t* get_bigbufptr_recvrespbuf(void) { - return (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); + return (((uint8_t *)BigBuf) + RECV_RESP_OFFSET); } uint8_t* get_bigbufptr_recvcmdbuf(void) { return (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); @@ -76,7 +76,7 @@ uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { } // send commands -int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) +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) { return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, answer_parity, timing); } @@ -84,39 +84,19 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) { uint8_t dcmd[8]; - dcmd[0] = cmd; - dcmd[1] = data[0]; + dcmd[0] = cmd; + dcmd[1] = data[0]; dcmd[2] = data[1]; - dcmd[3] = data[2]; - dcmd[4] = data[3]; - dcmd[5] = data[4]; + dcmd[3] = data[2]; + dcmd[4] = data[3]; + dcmd[5] = data[4]; AppendCrc14443a(dcmd, 6); ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer, answer_parity); - if(!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); - return 2; - } - return len; -} - -int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) -{ - uint8_t dcmd[19]; - int len; - dcmd[0] = cmd; - memcpy(dcmd+1,data,16); - AppendCrc14443a(dcmd, 17); - - ReaderTransmit(dcmd, sizeof(dcmd), timing); - len = ReaderReceive(answer, answer_parity); - if(!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); - len = ReaderReceive(answer,answer_parity); - } - if(len==1) { - if (MF_DBGLEVEL >= 1) Dbprintf("NAK - Authentication failed."); - return 1; + if(!len) + { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + return 2; } return len; } @@ -149,7 +129,7 @@ int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cm int len = ReaderReceive(answer, par); if (answer_parity) *answer_parity = par[0]; - + if (crypted == CRYPT_ALL) { if (len == 1) { res = 0; @@ -175,7 +155,7 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL); } -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_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) { // variables int len; @@ -186,9 +166,9 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN uint32_t nt, ntpp; // Supplied tag nonce uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - + // Transmit MIFARE_CLASSIC_AUTH len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing); if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); @@ -296,56 +276,6 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo memcpy(blockData, receivedAnswer, 16); return 0; -} - -int mifare_ultra_auth1(uint32_t uid, uint8_t *blockData){ - // variables - uint16_t len; - - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); - uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - - // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, receivedAnswer,receivedAnswerPar ,NULL); - if (len == 1) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; - } - if (len == 11) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], - receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], - receivedAnswer[10]); - memcpy(blockData, receivedAnswer, 11); - return 0; - } - //else something went wrong??? - return 1; -} - -int mifare_ultra_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ - // variables - uint16_t len; - - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); - uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - - // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, key, receivedAnswer, receivedAnswerPar, NULL); - if (len == 1) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; - } - if (len == 11){ - if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], - receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], - receivedAnswer[10]); - memcpy(blockData, receivedAnswer, 11); - return 0; - } - //something went wrong? - return 1; } int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) @@ -354,10 +284,10 @@ int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) uint16_t len; uint8_t bt[2]; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); - uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; + // command MIFARE_CLASSIC_READBLOCK len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { @@ -430,34 +360,34 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) { - // variables - uint16_t len; - uint8_t par[3] = {0}; // enough for 18 parity bits - uint8_t d_block[18]; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + // variables + uint16_t len; + uint8_t par[3] = {0}; // enough for 18 parity bits + uint8_t d_block[18]; + uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t* receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - - // command MIFARE_CLASSIC_WRITEBLOCK - len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); + + // command MIFARE_CLASSIC_WRITEBLOCK + len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); - if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]); - return 1; - } + if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]); + return 1; + } memset(d_block,'\0',18); memcpy(d_block, blockData, 16); AppendCrc14443a(d_block, 16); ReaderTransmitPar(d_block, sizeof(d_block), par, NULL); - - // Receive the response + + // Receive the response len = ReaderReceive(receivedAnswer, receivedAnswerPar); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len); - return 2; - } + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len); + return 2; + } return 0; } @@ -465,8 +395,8 @@ int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) { uint16_t len; - uint8_t d_block[8]; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t d_block[8]; + uint8_t *receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; // command MIFARE_CLASSIC_WRITEBLOCK @@ -478,17 +408,17 @@ int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *bloc //i know the data send here is correct len = mifare_sendcmd_short_special(NULL, 1, 0xA2, d_block, receivedAnswer, receivedAnswerPar, NULL); - if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0],len); - return 1; - } - return 0; + if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0],len); + return 1; + } + return 0; } int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) { uint16_t len; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswer = get_bigbufptr_recvrespbuf(); uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); @@ -502,9 +432,9 @@ int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) int mifare_ultra_halt(uint32_t uid) { - uint16_t len; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); - uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; + uint16_t len; + uint8_t *receivedAnswer = get_bigbufptr_recvrespbuf(); + uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; len = mifare_sendcmd_short(NULL, true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { @@ -538,7 +468,7 @@ uint8_t FirstBlockOfSector(uint8_t sectorNo) // work with emulator memory void emlSetMem(uint8_t *data, int blockNum, int blocksCount) { - uint8_t* emCARD = get_bigbufptr_emlcardmem(); + uint8_t* emCARD = get_bigbufptr_emlcardmem(); memcpy(emCARD + blockNum * 16, data, blocksCount * 16); } @@ -576,7 +506,7 @@ int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) { } memcpy(blReg, data, 4); - *blBlock = data[12]; + *blBlock = data[12]; return 0; } @@ -623,91 +553,3 @@ void emlClearMem(void) { emlSetMem((uint8_t *)uid, 0, 1); return; } - -// -//DESFIRE -// -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) -{ - uint8_t dcmd[5] = {0x00}; - dcmd[0] = cmd; - memcpy(dcmd+1,data,2); - AppendCrc14443a(dcmd, 3); - - ReaderTransmit(dcmd, sizeof(dcmd), NULL); - int len = ReaderReceive(answer, answer_parity); - if(!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); - return 2; - } - return len; -} - -int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing) -{ - uint8_t dcmd[20] = {0x00}; - dcmd[0] = cmd; - memcpy(dcmd+1,data,17); - AppendCrc14443a(dcmd, 18); - - ReaderTransmit(dcmd, sizeof(dcmd), NULL); - int len = ReaderReceive(answer, answer_parity); - if(!len){ - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); - return 2; - } - return len; -} - -int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData){ - // variables - int len; - // load key, keynumber - uint8_t data[2]={0x0a, 0x00}; - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); - uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - - // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer,receivedAnswerPar,NULL); - if (len == 1) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; - } - - if (len == 12) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], - receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], - receivedAnswer[10],receivedAnswer[11]); - memcpy(blockData, receivedAnswer, 12); - return 0; - } - return 1; -} - -int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ - // variables - int len; - uint8_t data[17]={0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - memcpy(data+1,key,16); - - uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf(); - uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE; - - // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar ,NULL); - - if ((receivedAnswer[0] == 0x03)&&(receivedAnswer[1] == 0xae)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]); - return 1; - } - if (len == 12){ - if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], - receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], - receivedAnswer[10],receivedAnswer[11]); - memcpy(blockData, receivedAnswer, 12); - return 0; - } - return 1; -} \ No newline at end of file diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 6ef5e0a5..c8f3dadf 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -16,7 +16,7 @@ #define CRYPT_NONE 0 #define CRYPT_ALL 1 #define CRYPT_REQUEST 2 -#define AUTH_FIRST 0 +#define AUTH_FIRST 0 #define AUTH_NESTED 2 // mifare 4bit card answers @@ -55,28 +55,18 @@ extern int MF_DBGLEVEL; //functions uint8_t* mifare_get_bigbufptr(void); int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); -int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing); - -int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing); +int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested); int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing); int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); -int mifare_ultra_auth1(uint32_t cuid, uint8_t *blockData); -int mifare_ultra_auth2(uint32_t cuid, uint8_t *key, uint8_t *blockData); int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); int mifare_ultra_halt(uint32_t uid); - -// desfire -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); -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); -int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData); -int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); // crypto functions void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len); diff --git a/armsrc/start.c b/armsrc/start.c index 3f5dc676..d7332bda 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -9,7 +9,7 @@ // with the linker script. //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "apps.h" extern char __data_start__, __data_src_start__, __data_end__, __bss_start__, __bss_end__; diff --git a/armsrc/string.c b/armsrc/string.c index 945a4cf6..cc71276c 100644 --- a/armsrc/string.c +++ b/armsrc/string.c @@ -48,11 +48,6 @@ int memcmp(const void *av, const void *bv, int len) return 0; } -void memxor(uint8_t * dest, uint8_t * src, size_t len) { - for( ; len > 0; len--,dest++,src++) - *dest ^= *src; -} - int strlen(const char *str) { int l = 0; diff --git a/armsrc/string.h b/armsrc/string.h index 6e2c7883..46ee218d 100644 --- a/armsrc/string.h +++ b/armsrc/string.h @@ -12,14 +12,10 @@ #ifndef __STRING_H #define __STRING_H -#include -#include - int strlen(const char *str); -RAMFUNC void *memcpy(void *dest, const void *src, int len); +void *memcpy(void *dest, const void *src, int len); void *memset(void *dest, int c, int len); -RAMFUNC int memcmp(const void *av, const void *bv, int len); -void memxor(uint8_t * dest, uint8_t * src, size_t len); +int memcmp(const void *av, const void *bv, int len); char *strncat(char *dest, const char *src, unsigned int n); char *strcat(char *dest, const char *src); void strreverse(char s[]); diff --git a/armsrc/util.c b/armsrc/util.c index 0558fb94..5b68f513 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -8,31 +8,11 @@ // Utility functions used in many places, not specific to any piece of code. //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include "util.h" #include "string.h" #include "apps.h" - - -void print_result(char *name, uint8_t *buf, size_t len) { - uint8_t *p = buf; - - if ( len % 16 == 0 ) { - for(; p-buf < len; p += 16) - Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - name, - p-buf, - len, - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] - ); - } - else { - for(; p-buf < len; p += 8) - Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - } -} - size_t nbytes(size_t nbits) { return (nbits/8)+((nbits%8)>0); } @@ -65,26 +45,6 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } -// RotateLeft - Ultralight, Desfire -void rol(uint8_t *data, const size_t len){ - uint8_t first = data[0]; - for (size_t i = 0; i < len-1; i++) { - data[i] = data[i+1]; - } - data[len-1] = first; -} -void lsl (uint8_t *data, size_t len) { - for (size_t n = 0; n < len - 1; n++) { - data[n] = (data[n] << 1) | (data[n+1] >> 7); - } - data[len - 1] <<= 1; -} - -int32_t le24toh (uint8_t data[3]) -{ - return (data[2] << 16) | (data[1] << 8) | data[0]; -} - void LEDsoff() { LED_A_OFF(); diff --git a/armsrc/util.h b/armsrc/util.h index c6503395..e8b9cdff 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -13,7 +13,7 @@ #include #include -#include "../include/common.h" +#include #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) @@ -27,14 +27,10 @@ #define BUTTON_DOUBLE_CLICK -2 #define BUTTON_ERROR -99 -void print_result(char *name, uint8_t *buf, size_t len); size_t nbytes(size_t nbits); uint32_t SwapBits(uint32_t value, int nrbits); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); -void rol(uint8_t *data, const size_t len); -void lsl (uint8_t *data, size_t len); -int32_t le24toh (uint8_t data[3]); void SpinDelay(int ms); void SpinDelayUs(int us); diff --git a/client/Makefile b/client/Makefile index 83d00260..b2b215e1 100644 --- a/client/Makefile +++ b/client/Makefile @@ -13,14 +13,14 @@ CXX=g++ VPATH = ../common OBJDIR = obj -LDLIBS = -L/mingw/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lm -lreadline -lpthread -lcrypto -lgdi32 +LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a LDFLAGS = $(COMMON_FLAGS) -CFLAGS = -std=c99 -I. -I../include -I../common -I/mingw/include -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 $(ICE_FLAGS) +CFLAGS = -std=c99 -lcrypto -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 LUAPLATFORM = generic ifneq (,$(findstring MINGW,$(platform))) -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 +CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui +QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 MOC = $(QTDIR)/bin/moc LUAPLATFORM = mingw else ifeq ($(platform),Darwin) @@ -56,14 +56,13 @@ CORESRCS = uart.c \ CMDSRCS = nonce2key/crapto1.c\ nonce2key/crypto1.c\ nonce2key/nonce2key.c\ - loclass/cipher.c \ - loclass/cipherutils.c \ - loclass/des.c \ - loclass/ikeys.c \ - loclass/elite_crack.c \ - loclass/fileutils.c \ - loclass/hash1_brute.c \ - mifarehost.c \ + loclass/cipher.c \ + loclass/cipherutils.c \ + loclass/des.c \ + loclass/ikeys.c \ + loclass/elite_crack.c\ + loclass/fileutils.c\ + mifarehost.c\ crc16.c \ iso14443crc.c \ iso15693tools.c \ @@ -80,12 +79,8 @@ CMDSRCS = nonce2key/crapto1.c\ cmdhflegic.c \ cmdhficlass.c \ cmdhfmf.c \ - cmdhfmfu.c \ - cmdhfmfdes.c \ - cmdhfdes.c \ cmdhw.c \ cmdlf.c \ - cmdlfawid26.c \ cmdlfio.c \ cmdlfhid.c \ cmdlfem4x.c \ diff --git a/client/cmddata.c b/client/cmddata.c index 9a19dca7..38917a33 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -26,33 +26,37 @@ static int CmdHelp(const char *Cmd); int CmdAmp(const char *Cmd) { - int i, rising, falling; - int max = INT_MIN, min = INT_MAX; + int i, rising, falling; + int max = INT_MIN, min = INT_MAX; - DetectHighLowInGraph( &max, &min, FALSE); + for (i = 10; i < GraphTraceLen; ++i) { + if (GraphBuffer[i] > max) + max = GraphBuffer[i]; + if (GraphBuffer[i] < min) + min = GraphBuffer[i]; + } - if (max != min) { - rising = falling = 0; - - for (i = 0; i < GraphTraceLen; ++i) { - if (GraphBuffer[i + 1] < GraphBuffer[i]) { - if (rising) { - GraphBuffer[i] = max; - rising = 0; - } - falling = 1; - } - if (GraphBuffer[i + 1] > GraphBuffer[i]) { - if (falling) { - GraphBuffer[i] = min; - falling = 0; - } - rising= 1; - } - } - } - RepaintGraphWindow(); - return 0; + if (max != min) { + rising = falling= 0; + for (i = 0; i < GraphTraceLen; ++i) { + if (GraphBuffer[i + 1] < GraphBuffer[i]) { + if (rising) { + GraphBuffer[i] = max; + rising = 0; + } + falling = 1; + } + if (GraphBuffer[i + 1] > GraphBuffer[i]) { + if (falling) { + GraphBuffer[i] = min; + falling = 0; + } + rising= 1; + } + } + } + RepaintGraphWindow(); + return 0; } /* @@ -69,167 +73,171 @@ int CmdAmp(const char *Cmd) //this method is dependant on all highs and lows to be the same(or clipped) this creates issues[marshmellow] it also ignores the clock int Cmdaskdemod(const char *Cmd) { - int i; - int c, high = 0, low = 0; + int i; + int c, high = 0, low = 0; - sscanf(Cmd, "%i", &c); + // TODO: complain if we do not give 2 arguments here ! + // (AL - this doesn't make sense! we're only using one argument!!!) + sscanf(Cmd, "%i", &c); - if (c != 0 && c != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - - DetectHighLowInGraph( &high, &low, FALSE); - - high = abs(high * .75); - low = abs(low * .75); - - //prime loop - if (GraphBuffer[0] > 0) { - GraphBuffer[0] = 1-c; - } else { - GraphBuffer[0] = c; - } - - for (i = 1; i < GraphTraceLen; ++i) { - /* Transitions are detected at each peak - * Transitions are either: - * - we're low: transition if we hit a high - * - we're high: transition if we hit a low - * (we need to do it this way because some tags keep high or - * low for long periods, others just reach the peak and go - * down) - */ + /* Detect high and lows and clock */ + // (AL - clock???) + for (i = 0; i < GraphTraceLen; ++i) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + high=abs(high*.75); + low=abs(low*.75); + if (c != 0 && c != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + //prime loop + if (GraphBuffer[0] > 0) { + GraphBuffer[0] = 1-c; + } else { + GraphBuffer[0] = c; + } + for (i = 1; i < GraphTraceLen; ++i) { + /* Transitions are detected at each peak + * Transitions are either: + * - we're low: transition if we hit a high + * - we're high: transition if we hit a low + * (we need to do it this way because some tags keep high or + * low for long periods, others just reach the peak and go + * down) + */ //[marhsmellow] change == to >= for high and <= for low for fuzz - if ((GraphBuffer[i] == high) && (GraphBuffer[i - 1] == c)) { - GraphBuffer[i] = 1 - c; - } else if ((GraphBuffer[i] == low) && (GraphBuffer[i - 1] == (1 - c))){ - GraphBuffer[i] = c; - } else { - /* No transition */ - GraphBuffer[i] = GraphBuffer[i - 1]; - } - } + if ((GraphBuffer[i] == high) && (GraphBuffer[i - 1] == c)) { + GraphBuffer[i] = 1 - c; + } else if ((GraphBuffer[i] == low) && (GraphBuffer[i - 1] == (1 - c))){ + GraphBuffer[i] = c; + } else { + /* No transition */ + GraphBuffer[i] = GraphBuffer[i - 1]; + } + } RepaintGraphWindow(); return 0; } -void printBitStream(uint8_t bits[], uint32_t bitLen){ - - uint32_t i = 0; - if (bitLen < 16) { - PrintAndLog("Too few bits found: %d",bitLen); - return; - } - if (bitLen > 512) - bitLen = 512; - - if ( ( bitLen % 16 ) > 0) { - bitLen = ((bitLen / 16) * 16); - PrintAndLog("ICE: equally divided with 16 = %d",bitLen); - } - - for (i = 0; i <= ( bitLen - 16); i += 16) { - PrintAndLog("%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", - bits[i], - bits[i+1], - bits[i+2], - bits[i+3], - bits[i+4], - bits[i+5], - bits[i+6], - bits[i+7], - bits[i+8], - bits[i+9], - bits[i+10], - bits[i+11], - bits[i+12], - bits[i+13], - bits[i+14], - bits[i+15]); - } +//by marshmellow +void printBitStream(uint8_t BitStream[], uint32_t bitLen) +{ + uint32_t i = 0; + if (bitLen<16) { + PrintAndLog("Too few bits found: %d",bitLen); + return; + } + if (bitLen>512) bitLen=512; + for (i = 0; i <= (bitLen-16); i+=16) { + PrintAndLog("%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", + BitStream[i], + BitStream[i+1], + BitStream[i+2], + BitStream[i+3], + BitStream[i+4], + BitStream[i+5], + BitStream[i+6], + BitStream[i+7], + BitStream[i+8], + BitStream[i+9], + BitStream[i+10], + BitStream[i+11], + BitStream[i+12], + BitStream[i+13], + BitStream[i+14], + BitStream[i+15]); + } return; } - -void printEM410x(uint64_t id) { - - if ( id <= 0 ) return; - - uint64_t id2lo = 0; - uint32_t i,j; - i = j = 0; - - for (j = 5; j > 0; j--){ - for (i = 0; i < 8; i++){ - id2lo = ( id2lo << 1LL)|((id & ( 1 << ( i +( ( j-1 ) * 8 )))) >> ( i + (( j-1) *8 ))); - } - } - //output em id - PrintAndLog("EM TAG ID : %010llx", id); - PrintAndLog("Unique TAG ID: %010llx", id2lo); - PrintAndLog("DEZ 8 : %08lld", id & 0xFFFFFF); - PrintAndLog("DEZ 10 : %010lld", id & 0xFFFFFF); - PrintAndLog("DEZ 5.5 : %05lld.%05lld", (id>>16LL) & 0xFFFF, (id & 0xFFFF)); - PrintAndLog("DEZ 3.5A : %03lld.%05lld", (id>>32ll), (id & 0xFFFF)); - PrintAndLog("DEZ 14/IK2 : %014lld", id); - PrintAndLog("DEZ 15/IK3 : %015lld", id2lo); - PrintAndLog("Other : %05lld_%03lld_%08lld", (id & 0xFFFF), (( id >> 16LL) & 0xFF), (id & 0xFFFFFF)); -} - -int CmdEm410xDecode(const char *Cmd) +//by marshmellow +void printEM410x(uint64_t id) { - uint64_t id = 0; - uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; - uint32_t len = GetFromGraphBuf(bits); - id = Em410xDecode(bits, len); - printEM410x(id); - if ( id > 0 ) - return 1; - return 0; + if (id !=0){ + uint64_t iii=1; + uint64_t id2lo=0; //id2hi=0, + uint32_t ii=0; + uint32_t i=0; + for (ii=5; ii>0;ii--){ + for (i=0;i<8;i++){ + id2lo=(id2lo<<1LL)|((id & (iii<<(i+((ii-1)*8))))>>(i+((ii-1)*8))); + } + } + //output em id + PrintAndLog("EM TAG ID : %010llx", id); + PrintAndLog("Unique TAG ID: %010llx", id2lo); //id2hi, + PrintAndLog("DEZ 8 : %08lld",id & 0xFFFFFF); + PrintAndLog("DEZ 10 : %010lld",id & 0xFFFFFF); + PrintAndLog("DEZ 5.5 : %05lld.%05lld",(id>>16LL) & 0xFFFF,(id & 0xFFFF)); + PrintAndLog("DEZ 3.5A : %03lld.%05lld",(id>>32ll),(id & 0xFFFF)); + PrintAndLog("DEZ 14/IK2 : %014lld",id); + PrintAndLog("DEZ 15/IK3 : %015lld",id2lo); + PrintAndLog("Other : %05lld_%03lld_%08lld",(id&0xFFFF),((id>>16LL) & 0xFF),(id & 0xFFFFFF)); + } + return; } //by marshmellow -//takes 2 arguments - clock and invert both as integers +int CmdEm410xDecode(const char *Cmd) +{ + uint64_t id=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + uint32_t i=0; + i=getFromGraphBuf(BitStream); + id = Em410xDecode(BitStream,i); + printEM410x(id); + if (id>0) return 1; + return 0; +} + + +//by marshmellow +//takes 2 arguments - clock and invert both as integers //attempts to demodulate ask while decoding manchester //prints binary found and saves in graphbuffer for further commands int Cmdaskmandemod(const char *Cmd) { - int invert = 0; - int clk = 0; - - sscanf(Cmd, "%i %i", &clk, &invert); - - if (invert != 0 && invert != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } + int invert=0; + int clk=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + sscanf(Cmd, "%i %i", &clk, &invert); + if (invert != 0 && invert != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + uint32_t BitLen = getFromGraphBuf(BitStream); + // PrintAndLog("DEBUG: Bitlen from grphbuff: %d",BitLen); + int errCnt=0; + errCnt = askmandemod(BitStream, &BitLen,&clk,&invert); + if (errCnt<0){ //if fatal error (or -1) + // PrintAndLog("no data found %d, errors:%d, bitlen:%d, clock:%d",errCnt,invert,BitLen,clk); + return 0; + } + if (BitLen<16) return 0; + PrintAndLog("\nUsing Clock: %d - Invert: %d - Bits Found: %d",clk,invert,BitLen); - uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; - uint32_t len = GetFromGraphBuf(bits); - - int errCnt = askmandemod(bits, &len, &clk, &invert); - - if (errCnt < 0) return 0; - if (len < 16) return 0; - - PrintAndLog("\nUsing Clock: %d - Invert: %d - Bits Found: %d",clk,invert,len); - - if (errCnt > 0){ - PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); - } - - PrintAndLog("ASK/Manchester decoded bitstream:"); - - printBitStream(bits, len); - - uint64_t tagid = Em410xDecode(bits, len); - - if (tagid > 0){ - SetGraphBuf(bits, len); - printEM410x(tagid); - return 1; - } - return 0; + //output + if (errCnt>0){ + PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); + } + PrintAndLog("ASK/Manchester decoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + printBitStream(BitStream,BitLen); + uint64_t lo =0; + lo = Em410xDecode(BitStream,BitLen); + if (lo>0){ + //set GraphBuffer for clone or sim command + setGraphBuf(BitStream,BitLen); + PrintAndLog("EM410x pattern found: "); + printEM410x(lo); + return 1; + } + //if (BitLen>16) return 1; + return 0; } //by marshmellow @@ -237,42 +245,41 @@ int Cmdaskmandemod(const char *Cmd) //stricktly take 10 and 01 and convert to 0 and 1 int Cmdmandecoderaw(const char *Cmd) { - int i = 0; - int errCnt = 0; - int bitnum = 0; - uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; - int high = 0, low = 0; - - for (; i < GraphTraceLen; ++i){ - if (GraphBuffer[i] > high) high = GraphBuffer[i]; - else if (GraphBuffer[i] < low) low = GraphBuffer[i]; - bits[i] = GraphBuffer[i]; - } - - if (high > 1 || low < 0 ){ - PrintAndLog("Error: please raw demod the wave first then mancheseter raw decode"); - return 0; - } - - bitnum = i; - errCnt = manrawdecode(bits, &bitnum); - - if (errCnt>=20){ - PrintAndLog("Too many errors: %d",errCnt); - return 0; - } - - PrintAndLog("Manchester Decoded - # errors:%d - data:",errCnt); - printBitStream(bits,bitnum); - - if (errCnt==0){ - //put back in graphbuffer - SetGraphBuf(bits, bitnum); - - uint64_t id = Em410xDecode(bits,i); - printEM410x(id); - } - return 1; + int i =0; + int errCnt=0; + int bitnum=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + int high=0,low=0; + for (;ihigh) high=GraphBuffer[i]; + else if(GraphBuffer[i]1 || low <0 ){ + PrintAndLog("Error: please raw demod the wave first then mancheseter raw decode"); + return 0; + } + bitnum=i; + errCnt=manrawdecode(BitStream,&bitnum); + if (errCnt>=20){ + PrintAndLog("Too many errors: %d",errCnt); + return 0; + } + PrintAndLog("Manchester Decoded - # errors:%d - data:",errCnt); + printBitStream(BitStream,bitnum); + if (errCnt==0){ + //put back in graphbuffer + ClearGraph(0); + for (i=0; i high) high = GraphBuffer[i]; - else if (GraphBuffer[i] < low) low = GraphBuffer[i]; - bits[i] = GraphBuffer[i]; - } - if (high > 1 || low < 0){ - PrintAndLog("Error: please raw demod the wave first then decode"); - return 0; - } - bitnum = i; - errCnt = BiphaseRawDecode(bits, &bitnum, offset); - if (errCnt >= 20){ - PrintAndLog("Too many errors attempting to decode: %d", errCnt); - return 0; - } - PrintAndLog("Biphase Decoded using offset: %d - # errors:%d - data:", offset, errCnt); - printBitStream(bits, bitnum); - PrintAndLog("\nif bitstream does not look right try offset=1"); - return 1; + int i = 0; + int errCnt=0; + int bitnum=0; + int offset=0; + int high=0, low=0; + sscanf(Cmd, "%i", &offset); + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + //get graphbuffer & high and low + for (;ihigh)high=GraphBuffer[i]; + else if(GraphBuffer[i]1 || low <0){ + PrintAndLog("Error: please raw demod the wave first then decode"); + return 0; + } + bitnum=i; + errCnt=BiphaseRawDecode(BitStream,&bitnum, offset); + if (errCnt>=20){ + PrintAndLog("Too many errors attempting to decode: %d",errCnt); + return 0; + } + PrintAndLog("Biphase Decoded using offset: %d - # errors:%d - data:",offset,errCnt); + printBitStream(BitStream,bitnum); + PrintAndLog("\nif bitstream does not look right try offset=1"); + return 1; } @@ -324,49 +329,38 @@ int CmdBiphaseDecodeRaw(const char *Cmd) //prints binary found and saves in graphbuffer for further commands int Cmdaskrawdemod(const char *Cmd) { - int invert = 0; - int clk = 0; - - sscanf(Cmd, "%i %i", &clk, &invert); - - if (invert != 0 && invert != 1 ) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } + + int invert=0; + int clk=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + sscanf(Cmd, "%i %i", &clk, &invert); + if (invert != 0 && invert != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } + int BitLen = getFromGraphBuf(BitStream); + int errCnt=0; + errCnt = askrawdemod(BitStream, &BitLen, &clk, &invert); + if (errCnt==-1){ //throw away static - allow 1 and -1 (in case of threshold command first) + PrintAndLog("no data found"); + return 0; + } + if (BitLen<16) return 0; + PrintAndLog("Using Clock: %d - invert: %d - Bits Found: %d",clk,invert,BitLen); + //PrintAndLog("Data start pos:%d, lastBit:%d, stop pos:%d, numBits:%d",iii,lastBit,i,bitnum); + //move BitStream back to GraphBuffer + setGraphBuf(BitStream, BitLen); - if ( clock < 0 ) { - PrintAndLog("Wrong clock argument"); - return 0; - } + if (errCnt>0){ + PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); + } - uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; - int len = GetFromGraphBuf(bits); - int errCnt = 0; - - errCnt = askrawdemod(bits, &len, &clk, &invert); + PrintAndLog("ASK demoded bitstream:"); - //throw away static - allow 1 and -1 (in case of threshold command first) - if (errCnt == -1) { - PrintAndLog("no data found"); - return 0; - } - - if (len < 16) return 0; - - PrintAndLog("Using Clock: %d - invert: %d - Bits Found: %d",clk,invert,len); - - //move BitStream back to GraphBuffer - SetGraphBuf(bits, len); - - if (errCnt > 0){ - PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); - } - - PrintAndLog("ASK demoded bitstream:"); - - // Now output the bitstream to the scrollback by line of 16 bits - printBitStream(bits,len); - return 1; + // Now output the bitstream to the scrollback by line of 16 bits + printBitStream(BitStream,BitLen); + + return 1; } int CmdAutoCorr(const char *Cmd) @@ -404,7 +398,7 @@ int CmdAutoCorr(const char *Cmd) int CmdBitsamples(const char *Cmd) { int cnt = 0; - uint8_t got[10000]; + uint8_t got[12288]; GetFromBigBuf(got,sizeof(got),0); WaitForResponse(CMD_ACK,NULL); @@ -437,10 +431,16 @@ int CmdBitstream(const char *Cmd) int hithigh, hitlow, first; /* Detect high and lows and clock */ - DetectHighLowInGraph( &high, &low, FALSE); + for (i = 0; i < GraphTraceLen; ++i) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } /* Get our clock */ - clock = GetClock(Cmd, 0); + clock = GetClock(Cmd, high, 1); gtl = ClearGraph(0); bit = 0; @@ -500,7 +500,7 @@ int CmdDec(const char *Cmd) // uses data from graphbuffer int CmdDetectClockRate(const char *Cmd) { - GetClock("",1); + GetClock("",0,0); return 0; } @@ -510,48 +510,43 @@ int CmdDetectClockRate(const char *Cmd) //defaults: clock = 50, invert=0, rchigh=10, rclow=8 (RF/10 RF/8 (fsk2a)) int CmdFSKrawdemod(const char *Cmd) { - //raw fsk demod no manchester decoding no start bit finding just get binary from wave - int rfLen = 50; - int invert = 0; - int fchigh = 10; - int fclow = 8; - - //set options from parameters entered with the command - sscanf(Cmd, "%i %i %i %i", &rfLen, &invert, &fchigh, &fclow); + //raw fsk demod no manchester decoding no start bit finding just get binary from wave + //set defaults + int rfLen = 50; + int invert=0; + int fchigh=10; + int fclow=8; + //set options from parameters entered with the command + sscanf(Cmd, "%i %i %i %i", &rfLen, &invert, &fchigh, &fclow); - // A lots of checks if chigh, clow is out-of bounds. - - if (strlen(Cmd)>0 && strlen(Cmd)<=2) { - - rfLen = 50; - - //if invert option only is used - if (rfLen == 1){ - invert=1; - } - } - - PrintAndLog("Args invert: %d - Clock:%d - FC high:%d - FC low: %d",invert,rfLen,fchigh, fclow); - - uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; - uint32_t len = GetFromGraphBuf(bits); - - int size = fskdemod(bits, len,(uint8_t)rfLen, (uint8_t)invert, (uint8_t)fchigh, (uint8_t)fclow); - - if (size > 0) { - PrintAndLog("FSK decoded bitstream:"); - - SetGraphBuf(bits, size); - - // Now output the bitstream to the scrollback by line of 16 bits - // only output a max of 8 blocks of 32 bits most tags will have full bit stream inside that sample size - if(size > (8*32)+2) - size = (8*32)+2; - printBitStream(bits,size); - } else { - PrintAndLog("no FSK data found"); - } - return 0; + if (strlen(Cmd)>0 && strlen(Cmd)<=2) { + //rfLen=param_get8(Cmd, 0); //if rfLen option only is used + if (rfLen==1){ + invert=1; //if invert option only is used + rfLen = 50; + } else if(rfLen==0) rfLen=50; + } + PrintAndLog("Args invert: %d - Clock:%d - fchigh:%d - fclow: %d",invert,rfLen,fchigh, fclow); + uint32_t i=0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + uint32_t BitLen = getFromGraphBuf(BitStream); + int size = fskdemod(BitStream,BitLen,(uint8_t)rfLen,(uint8_t)invert,(uint8_t)fchigh,(uint8_t)fclow); + if (size>0){ + PrintAndLog("FSK decoded bitstream:"); + ClearGraph(0); + for (i=0;i (8*32)+2) size = (8*32)+2; //only output a max of 8 blocks of 32 bits most tags will have full bit stream inside that sample size + printBitStream(BitStream,size); + } else{ + PrintAndLog("no FSK data found"); + } + return 0; } //by marshmellow (based on existing demod + holiman's refactor) @@ -559,91 +554,72 @@ int CmdFSKrawdemod(const char *Cmd) //print full HID Prox ID and some bit format details if found int CmdFSKdemodHID(const char *Cmd) { - //raw fsk demod no manchester decoding no start bit finding just get binary from wave - uint32_t hi2=0, hi=0, lo=0; + //raw fsk demod no manchester decoding no start bit finding just get binary from wave + uint32_t hi2=0, hi=0, lo=0; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN] = {0x00}; - uint32_t BitLen = GetFromGraphBuf(BitStream); - - //get binary from fsk wave - size_t size = HIDdemodFSK(BitStream,BitLen,&hi2,&hi,&lo); - - if (size < 0){ - PrintAndLog("Error demoding fsk"); - return 0; - } - - if (hi2==0 && hi==0 && lo==0) return 0; - - //extra large HID tags - if (hi2 != 0){ - PrintAndLog("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, - (unsigned int) hi, - (unsigned int) lo, - (unsigned int) (lo>>1) & 0xFFFF); - SetGraphBuf(BitStream,BitLen); - return 1; - } else { - //standard HID tags <38 bits - uint8_t fmtLen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - - //if bit 38 is set then < 37 bit format is used - if (((hi>>5) & 1)==1){ - uint32_t lo2 = 0; - - //get bits 21-37 to check for format len bit - lo2 = (((hi & 15) << 12) | (lo>>20)); - uint8_t idx3 = 1; - - //find last bit set to 1 (format len bit) - while( lo2 > 1){ - lo2=lo2>>1; - idx3++; - } - fmtLen = idx3 + 19; - fc = 0; - cardnum = 0; - - if(fmtLen==26){ - cardnum = (lo>>1)&0xFFFF; - fc = (lo>>17)&0xFF; - } - if(fmtLen==37){ - cardnum = (lo>>1)&0x7FFFF; - fc = ((hi&0xF)<<12)|(lo>>20); - } - if(fmtLen==34){ - cardnum = (lo>>1)&0xFFFF; - fc= ((hi&1)<<15)|(lo>>17); - } - if(fmtLen==35){ - cardnum = (lo>>1)&0xFFFFF; - fc = ((hi&1)<<11)|(lo>>21); - } - } else { - //if bit 38 is not set then 37 bit format is used - fmtLen= 37; - fc =0; - cardnum=0; - - if (fmtLen==37){ - cardnum = (lo>>1) & 0x7FFFF; - fc = ((hi&0xF) << 12) | (lo >> 20); - } - } - PrintAndLog("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", - (unsigned int) hi, - (unsigned int) lo, - (unsigned int) (lo>>1) & 0xFFFF, - (unsigned int) fmtLen, - (unsigned int) fc, - (unsigned int) cardnum); - SetGraphBuf(BitStream,BitLen); + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + uint32_t BitLen = getFromGraphBuf(BitStream); + //get binary from fsk wave + size_t size = HIDdemodFSK(BitStream,BitLen,&hi2,&hi,&lo); + if (size<0){ + PrintAndLog("Error demoding fsk"); + return 0; + } + if (hi2==0 && hi==0 && lo==0) return 0; + if (hi2 != 0){ //extra large HID tags + PrintAndLog("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + setGraphBuf(BitStream,BitLen); return 1; - } + } + else { //standard HID tags <38 bits + //Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd + uint8_t fmtLen = 0; + uint32_t fc = 0; + uint32_t cardnum = 0; + if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used + uint32_t lo2=0; + lo2=(((hi & 15) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit + uint8_t idx3 = 1; + while(lo2>1){ //find last bit set to 1 (format len bit) + lo2=lo2>>1; + idx3++; + } + fmtLen =idx3+19; + fc =0; + cardnum=0; + if(fmtLen==26){ + cardnum = (lo>>1)&0xFFFF; + fc = (lo>>17)&0xFF; + } + if(fmtLen==37){ + cardnum = (lo>>1)&0x7FFFF; + fc = ((hi&0xF)<<12)|(lo>>20); + } + if(fmtLen==34){ + cardnum = (lo>>1)&0xFFFF; + fc= ((hi&1)<<15)|(lo>>17); + } + if(fmtLen==35){ + cardnum = (lo>>1)&0xFFFFF; + fc = ((hi&1)<<11)|(lo>>21); + } + } + else { //if bit 38 is not set then 37 bit format is used + fmtLen= 37; + fc =0; + cardnum=0; + if(fmtLen==37){ + cardnum = (lo>>1)&0x7FFFF; + fc = ((hi&0xF)<<12)|(lo>>20); + } + } + PrintAndLog("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF, + (unsigned int) fmtLen, (unsigned int) fc, (unsigned int) cardnum); + setGraphBuf(BitStream,BitLen); + return 1; + } return 0; } @@ -652,67 +628,54 @@ int CmdFSKdemodHID(const char *Cmd) //print ioprox ID and some format details int CmdFSKdemodIO(const char *Cmd) { - if (GraphTraceLen < 65) { - PrintAndLog("data samples size is too small"); - return 0; - } + //raw fsk demod no manchester decoding no start bit finding just get binary from wave + //set defaults + int idx=0; + //something in graphbuffer + if (GraphTraceLen < 65) return 0; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; + uint32_t BitLen = getFromGraphBuf(BitStream); + //get binary from fsk wave + // PrintAndLog("DEBUG: got buff"); + idx = IOdemodFSK(BitStream,BitLen); + if (idx<0){ + //PrintAndLog("Error demoding fsk"); + return 0; + } + // PrintAndLog("DEBUG: Got IOdemodFSK"); + if (idx==0){ + //PrintAndLog("IO Prox Data not found - FSK Data:"); + //if (BitLen > 92) printBitStream(BitStream,92); + return 0; + } + //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 (raw) + //Handle the data + if (idx+64>BitLen) return 0; + PrintAndLog("%d%d%d%d%d%d%d%d %d",BitStream[idx], BitStream[idx+1], BitStream[idx+2], BitStream[idx+3], BitStream[idx+4], BitStream[idx+5], BitStream[idx+6], BitStream[idx+7], BitStream[idx+8]); + PrintAndLog("%d%d%d%d%d%d%d%d %d",BitStream[idx+9], BitStream[idx+10], BitStream[idx+11],BitStream[idx+12],BitStream[idx+13],BitStream[idx+14],BitStream[idx+15],BitStream[idx+16],BitStream[idx+17]); + PrintAndLog("%d%d%d%d%d%d%d%d %d facility",BitStream[idx+18], BitStream[idx+19], BitStream[idx+20],BitStream[idx+21],BitStream[idx+22],BitStream[idx+23],BitStream[idx+24],BitStream[idx+25],BitStream[idx+26]); + PrintAndLog("%d%d%d%d%d%d%d%d %d version",BitStream[idx+27], BitStream[idx+28], BitStream[idx+29],BitStream[idx+30],BitStream[idx+31],BitStream[idx+32],BitStream[idx+33],BitStream[idx+34],BitStream[idx+35]); + PrintAndLog("%d%d%d%d%d%d%d%d %d code1",BitStream[idx+36], BitStream[idx+37], BitStream[idx+38],BitStream[idx+39],BitStream[idx+40],BitStream[idx+41],BitStream[idx+42],BitStream[idx+43],BitStream[idx+44]); + PrintAndLog("%d%d%d%d%d%d%d%d %d code2",BitStream[idx+45], BitStream[idx+46], BitStream[idx+47],BitStream[idx+48],BitStream[idx+49],BitStream[idx+50],BitStream[idx+51],BitStream[idx+52],BitStream[idx+53]); + PrintAndLog("%d%d%d%d%d%d%d%d %d%d checksum",BitStream[idx+54],BitStream[idx+55],BitStream[idx+56],BitStream[idx+57],BitStream[idx+58],BitStream[idx+59],BitStream[idx+60],BitStream[idx+61],BitStream[idx+62],BitStream[idx+63]); - //raw fsk demod no manchester decoding no start bit finding just get binary from wave - //set defaults - int idx = 0; - uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0x00}; - uint32_t bitlen = GetFromGraphBuf(bits); - - //get binary from fsk wave - idx = IOdemodFSK(bits, bitlen); + uint32_t code = bytebits_to_byte(BitStream+idx,32); + uint32_t code2 = bytebits_to_byte(BitStream+idx+32,32); + uint8_t version = bytebits_to_byte(BitStream+idx+27,8); //14,4 + uint8_t facilitycode = bytebits_to_byte(BitStream+idx+18,8) ; + uint16_t number = (bytebits_to_byte(BitStream+idx+36,8)<<8)|(bytebits_to_byte(BitStream+idx+45,8)); //36,9 - if (idx == 0) { - return 0; - } - if (idx == -1) { - PrintAndLog("data samples size is too small"); - return 0; - } - if (idx == -2) { - PrintAndLog("Data samples has too much noice"); - return 0; - } - if (idx == -3){ - PrintAndLog("No good demod"); - return 0; - } - - if (idx+64 > bitlen) return 0; - - //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 (raw) - //Handle the data - - PrintAndLog("%d%d%d%d%d%d%d%d %d", bits[idx] , bits[idx+1], bits[idx+2], bits[idx+3], bits[idx+4], bits[idx+5], bits[idx+6], bits[idx+7], bits[idx+8]); - PrintAndLog("%d%d%d%d%d%d%d%d %d", bits[idx+9] , bits[idx+10], bits[idx+11], bits[idx+12], bits[idx+13], bits[idx+14], bits[idx+15], bits[idx+16], bits[idx+17]); - PrintAndLog("%d%d%d%d%d%d%d%d %d facility", bits[idx+18], bits[idx+19], bits[idx+20], bits[idx+21], bits[idx+22], bits[idx+23], bits[idx+24], bits[idx+25], bits[idx+26]); - PrintAndLog("%d%d%d%d%d%d%d%d %d version", bits[idx+27], bits[idx+28], bits[idx+29], bits[idx+30], bits[idx+31], bits[idx+32], bits[idx+33], bits[idx+34], bits[idx+35]); - PrintAndLog("%d%d%d%d%d%d%d%d %d code1", bits[idx+36], bits[idx+37], bits[idx+38], bits[idx+39], bits[idx+40], bits[idx+41], bits[idx+42], bits[idx+43], bits[idx+44]); - PrintAndLog("%d%d%d%d%d%d%d%d %d code2", bits[idx+45], bits[idx+46], bits[idx+47], bits[idx+48], bits[idx+49], bits[idx+50], bits[idx+51], bits[idx+52], bits[idx+53]); - PrintAndLog("%d%d%d%d%d%d%d%d %d%d checksum", bits[idx+54], bits[idx+55], bits[idx+56], bits[idx+57], bits[idx+58], bits[idx+59], bits[idx+60], bits[idx+61], bits[idx+62], bits[idx+63]); - - uint32_t code = bytebits_to_byte(bits+idx,32); - uint32_t code2 = bytebits_to_byte(bits+idx+32,32); - uint8_t version = bytebits_to_byte(bits+idx+27,8); //14,4 - uint8_t facilitycode = bytebits_to_byte(bits+idx+18,8) ; - uint16_t number = (bytebits_to_byte(bits+idx+36,8)<<8)|(bytebits_to_byte(bits+idx+45,8)); //36,9 - - PrintAndLog("XSF(%02d)%02x:%05d (%08x%08x)", version, facilitycode, number, code, code2); - SetGraphBuf(bits, bitlen); - return 1; + PrintAndLog("XSF(%02d)%02x:%05d (%08x%08x)",version,facilitycode,number,code,code2); + setGraphBuf(BitStream,BitLen); + return 1; } - int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating { static const int LowTone[] = { @@ -733,12 +696,12 @@ int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating int lowLen = sizeof (LowTone) / sizeof (int); int highLen = sizeof (HighTone) / sizeof (int); - int convLen = (highLen > lowLen) ? highLen : lowLen; + int convLen = (highLen > lowLen) ? highLen : lowLen; //if highlen > lowLen then highlen else lowlen uint32_t hi = 0, lo = 0; int i, j; int minMark = 0, maxMark = 0; - + for (i = 0; i < GraphTraceLen - convLen; ++i) { int lowSum = 0, highSum = 0; @@ -916,81 +879,43 @@ int CmdSamples(const char *Cmd) n = sizeof(got); PrintAndLog("Reading %d samples from device memory\n", n); - GetFromBigBuf(got,n,0); - WaitForResponse(CMD_ACK,NULL); + GetFromBigBuf(got,n,0); + WaitForResponse(CMD_ACK,NULL); for (int j = 0; j < n; ++j) { GraphBuffer[j] = ((int)got[j]) - 128; - } - GraphTraceLen = n; - RepaintGraphWindow(); - return 0; + } + GraphTraceLen = n; + RepaintGraphWindow(); + return 0; } int CmdTuneSamples(const char *Cmd) { - int timeout = 0; - printf("\nMeasuring antenna characteristics, please wait..."); + int cnt = 0; + int n = 255; + uint8_t got[255]; - UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING}; - SendCommand(&c); - - UsbCommand resp; - while(!WaitForResponseTimeout(CMD_MEASURED_ANTENNA_TUNING,&resp,1000)) { - timeout++; - printf("."); - if (timeout > 7) { - PrintAndLog("\nNo response from Proxmark. Aborting..."); - return 1; - } - } - - int peakv, peakf; - int vLf125, vLf134, vHf; - vLf125 = resp.arg[0] & 0xffff; - vLf134 = resp.arg[0] >> 16; - vHf = resp.arg[1] & 0xffff;; - peakf = resp.arg[2] & 0xffff; - peakv = resp.arg[2] >> 16; - PrintAndLog(""); - PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0); - PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0); - PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1)); - PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0); - if (peakv<2000) - PrintAndLog("# Your LF antenna is unusable."); - else if (peakv<10000) - PrintAndLog("# Your LF antenna is marginal."); - if (vHf<2000) - PrintAndLog("# Your HF antenna is unusable."); - else if (vHf<5000) - PrintAndLog("# Your HF antenna is marginal."); - - for (int i = 0; i < 256; i++) { - GraphBuffer[i] = resp.d.asBytes[i] - 128; - } + PrintAndLog("Reading %d samples\n", n); + GetFromBigBuf(got,n,7256); // armsrc/apps.h: #define FREE_BUFFER_OFFSET 7256 + WaitForResponse(CMD_ACK,NULL); + for (int j = 0; j < n; j++) { + GraphBuffer[cnt++] = ((int)got[j]) - 128; + } - PrintAndLog("Done! Divisor 89 is 134khz, 95 is 125khz.\n"); - PrintAndLog("\n"); - GraphTraceLen = 256; - ShowGraphWindow(); - + PrintAndLog("Done! Divisor 89 is 134khz, 95 is 125khz.\n"); + PrintAndLog("\n"); + GraphTraceLen = n; + RepaintGraphWindow(); return 0; } int CmdLoad(const char *Cmd) { - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; - - len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); - - FILE *f = fopen(filename, "r"); - if (!f) { - PrintAndLog("couldn't open '%s'", filename); - return 0; - } + FILE *f = fopen(Cmd, "r"); + if (!f) { + PrintAndLog("couldn't open '%s'", Cmd); + return 0; + } GraphTraceLen = 0; char line[80]; @@ -1070,13 +995,20 @@ int CmdManchesterDemod(const char *Cmd) /* But it does not work if compiling on WIndows: therefore we just allocate a */ /* large array */ - uint8_t BitStream[MAX_GRAPH_TRACE_LEN] = {0x00}; + uint8_t BitStream[MAX_GRAPH_TRACE_LEN] = {0}; /* Detect high and lows */ - DetectHighLowInGraph( &high, &low, TRUE); - + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + /* Get our clock */ - clock = GetClock(Cmd, 0); + clock = GetClock(Cmd, high, 1); + int tolerance = clock/4; /* Detect first transition */ @@ -1094,14 +1026,14 @@ int CmdManchesterDemod(const char *Cmd) break; } } - + /* If we're not working with 1/0s, demod based off clock */ if (high != 1) { bit = 0; /* We assume the 1st bit is zero, it may not be * the case: this routine (I think) has an init problem. * Ed. - */ + */ for (; i < (int)(GraphTraceLen / clock); i++) { hithigh = 0; @@ -1144,30 +1076,30 @@ int CmdManchesterDemod(const char *Cmd) { if (GraphBuffer[i-1] != GraphBuffer[i]) { - lc = i-lastval; - lastval = i; + lc = i-lastval; + lastval = i; - // Error check: if bitidx becomes too large, we do not - // have a Manchester encoded bitstream or the clock is really - // wrong! - if (bitidx > (GraphTraceLen*2/clock+8) ) { - 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" - BitStream[bitidx++]=GraphBuffer[i-1]; - } else if (abs(lc-clock) < tolerance) { - // Long pulse: either "11" or "00" - BitStream[bitidx++]=GraphBuffer[i-1]; - BitStream[bitidx++]=GraphBuffer[i-1]; - } else { + // Error check: if bitidx becomes too large, we do not + // have a Manchester encoded bitstream or the clock is really + // wrong! + if (bitidx > (GraphTraceLen*2/clock+8) ) { + 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" + BitStream[bitidx++]=GraphBuffer[i-1]; + } else if (abs(lc-clock) < tolerance) { + // Long pulse: either "11" or "00" + BitStream[bitidx++]=GraphBuffer[i-1]; + BitStream[bitidx++]=GraphBuffer[i-1]; + } else { // Error warnings++; - PrintAndLog("Warning: Manchester decode error for pulse width detection."); - PrintAndLog("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)"); + PrintAndLog("Warning: Manchester decode error for pulse width detection."); + PrintAndLog("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)"); if (warnings > 10) { @@ -1181,20 +1113,18 @@ int CmdManchesterDemod(const char *Cmd) // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful // to stop output at the final bitidx2 value, not bitidx - - //http://www.proxmark.org/forum/viewtopic.php?id=403 - for (i = 1; i < bitidx; i += 2) { + for (i = 0; i < bitidx; i += 2) { if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) { BitStream[bit2idx++] = 1 ^ invert; - } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) { - BitStream[bit2idx++] = 0 ^ invert; - } else { - // We cannot end up in this state, this means we are unsynchronized, - // move up 1 bit: - i++; - warnings++; - PrintAndLog("Unsynchronized, resync..."); - PrintAndLog("(too many of those messages mean the stream is not Manchester encoded)"); + } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) { + BitStream[bit2idx++] = 0 ^ invert; + } else { + // We cannot end up in this state, this means we are unsynchronized, + // move up 1 bit: + i++; + warnings++; + PrintAndLog("Unsynchronized, resync..."); + PrintAndLog("(too many of those messages mean the stream is not Manchester encoded)"); if (warnings > 10) { @@ -1226,27 +1156,28 @@ int CmdManchesterDemod(const char *Cmd) BitStream[i+14], BitStream[i+15]); } - return bit2idx; + return 0; } /* Modulate our data into manchester */ int CmdManchesterMod(const char *Cmd) { int i, j; + int clock; int bit, lastbit, wave; - int clock = GetClock(Cmd, 0); - - int half = (int)(clock/2); - + + /* Get our clock */ + clock = GetClock(Cmd, 0, 1); + wave = 0; lastbit = 1; for (i = 0; i < (int)(GraphTraceLen / clock); i++) { bit = GraphBuffer[i * clock] ^ 1; - for (j = 0; j < half; ++j) + for (j = 0; j < (int)(clock/2); j++) GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave; - for (j = half; j < clock; ++j) + for (j = (int)(clock/2); j < clock; j++) GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1; /* Keep track of how we start our wave and if we changed or not this time */ @@ -1288,17 +1219,9 @@ int CmdPlot(const char *Cmd) int CmdSave(const char *Cmd) { - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; - - len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); - - - FILE *f = fopen(filename, "w"); + FILE *f = fopen(Cmd, "w"); if(!f) { - PrintAndLog("couldn't open '%s'", filename); + PrintAndLog("couldn't open '%s'", Cmd); return 0; } int i; @@ -1413,8 +1336,6 @@ static command_t CommandTable[] = {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, {"dec", CmdDec, 1, "Decimate samples"}, {"detectaskclock",CmdDetectClockRate, 1, "Detect ASK clock rate"}, - {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, - {"em4xdecode", CmdEm410xDecode, 1, "decode em4x from graph buffer"}, {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"}, {"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate graph window as a HID FSK using raw"}, {"fskiodemod", CmdFSKdemodIO, 1, "Demodulate graph window as an IO Prox FSK using raw"}, @@ -1432,11 +1353,12 @@ static command_t CommandTable[] = {"norm", CmdNorm, 1, "Normalize max/min to +/-500"}, {"plot", CmdPlot, 1, "Show graph window (hit 'h' in window for keystroke help)"}, {"samples", CmdSamples, 0, "[512 - 40000] -- Get raw samples for graph window"}, + {"tune", CmdTuneSamples, 0, "Get hw tune samples for graph window"}, {"save", CmdSave, 1, " -- Save trace (from graph window)"}, {"scale", CmdScale, 1, " -- Set cursor display scale"}, {"threshold", CmdThreshold, 1, " -- Maximize/minimize every value in the graph window depending on threshold"}, - {"tune", CmdTuneSamples, 0, "Get hw tune samples for graph window"}, {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"}, + {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmddata.h b/client/cmddata.h index 59ac43b9..999e6438 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -43,10 +43,11 @@ int CmdManchesterMod(const char *Cmd); int CmdNorm(const char *Cmd); int CmdPlot(const char *Cmd); int CmdSamples(const char *Cmd); +int CmdTuneSamples(const char *Cmd); int CmdSave(const char *Cmd); int CmdScale(const char *Cmd); int CmdThreshold(const char *Cmd); int CmdDirectionalThreshold(const char *Cmd); int CmdZerocrossings(const char *Cmd); -int CmdTuneSamples(const char *Cmd); + #endif diff --git a/client/cmdhf.c b/client/cmdhf.c index 0ed3f013..550f8e86 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -22,9 +22,6 @@ #include "cmdhflegic.h" #include "cmdhficlass.h" #include "cmdhfmf.h" -#include "cmdhfmfu.h" -#include "cmdhfmfdes.h" -#include "cmdhfdes.h" static int CmdHelp(const char *Cmd); @@ -317,13 +314,10 @@ 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... }"}, - {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, - {"mfdes", CmdHFMFDes, 1, "{ MIFARE Desfire RFIDs... }"}, - {"des", CmdHFDES, 0, "{ MIFARE DESfire}"}, + {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, {"list", CmdHFList, 1, "List protocol data in trace buffer"}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; int CmdHF(const char *Cmd) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 62d95b4b..673737e2 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -14,150 +14,22 @@ #include #include #include "util.h" -#include "../common/iso14443crc.h" +#include "iso14443crc.h" #include "data.h" #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" #include "cmdhf14a.h" -#include "../include/common.h" +#include "common.h" #include "cmdmain.h" -#include "../include/mifare.h" +#include "mifare.h" static int CmdHelp(const char *Cmd); static void waitCmd(uint8_t iLen); int CmdHF14AList(const char *Cmd) { - bool ShowWaitCycles = false; - char param = param_getchar(Cmd, 0); - - if (param == 'h' || (param != 0 && param != 'f')) { - PrintAndLog("List data in trace buffer."); - PrintAndLog("Usage: hf 14a list [f]"); - PrintAndLog("f - show frame delay times as well"); - PrintAndLog("sample: hf 14a list f"); - return 0; - } - - ShowWaitCycles = (param == 'f'); - -// for the time being. Need better Bigbuf handling. -#define TRACE_SIZE 3000 - - uint8_t trace[TRACE_SIZE]; - GetFromBigBuf(trace, TRACE_SIZE, 0); - WaitForResponse(CMD_ACK,NULL); - - PrintAndLog("Recorded Activity"); - PrintAndLog(""); - PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); - PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC "); - PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------"); - - uint16_t tracepos = 0; - uint16_t duration; - uint16_t data_len; - uint16_t parity_len; - bool isResponse; - uint32_t timestamp; - uint32_t first_timestamp; - uint32_t EndOfTransmissionTimestamp; - - for (;;) { - - if(tracepos >= TRACE_SIZE) break; - - timestamp = *((uint32_t *)(trace + tracepos)); - - // Break and stick with current result if buffer was not completely full - if (timestamp == 0x44444444) break; - - if(tracepos == 0) { - first_timestamp = timestamp; - } - - tracepos += 4; - duration = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - data_len = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - - isResponse = false; - if (data_len & 0x8000) { - data_len &= 0x7fff; - isResponse = true; - } - - parity_len = (data_len-1)/8 + 1; - - if (tracepos + data_len + parity_len >= TRACE_SIZE) break; - - uint8_t *frame = trace + tracepos; - tracepos += data_len; - uint8_t *parityBytes = trace + tracepos; - tracepos += parity_len; - - char line[16][110]; - for (int j = 0; j < data_len; j++) { - int oddparity = 0x01; - int k; - - for (k=0;k<8;k++) { - oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); - } - - uint8_t parityBits = parityBytes[j>>3]; - if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]); - } else { - sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]); - } - } - - char crc[5] = {0x00}; - if (data_len > 2) { - uint8_t b1, b2; - ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - sprintf(crc, (isResponse & (data_len < 6)) ? "" : "!crc"); - } - } - - EndOfTransmissionTimestamp = timestamp + duration; - int num_lines = (data_len - 1)/16 + 1; - - for (int j = 0; j < num_lines; j++) { - if (j == 0) { - PrintAndLog(" %9d | %9d | %s | %-64s| %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (isResponse ? "Tag" : "Rdr"), - line[j], - (j == num_lines-1)?crc:"" - ); - } else { - PrintAndLog(" | | | %-64s| %s", - line[j], - (j == num_lines-1)?crc:""); - } - } - - bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; - - if (ShowWaitCycles && !isResponse && next_isResponse) { - uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); - if (next_timestamp != 0x44444444) { - PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", - (EndOfTransmissionTimestamp - first_timestamp), - (next_timestamp - first_timestamp), - " ", - (next_timestamp - EndOfTransmissionTimestamp)); - } - } - } + PrintAndLog("Deprecated command, use 'hf list 14a' instead"); return 0; } @@ -225,6 +97,13 @@ int CmdHF14AReader(const char *Cmd) memcpy(&card.ats, resp.d.asBytes, resp.arg[0]); card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes } + + // disconnect + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); + if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes bool ta1 = 0, tb1 = 0, tc1 = 0; @@ -364,24 +243,6 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog("proprietary non iso14443-4 card found, RATS not supported"); } - - // try to see if card responses to "chinese magic backdoor" commands. - c.cmd = CMD_MIFARE_CIDENT; - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - WaitForResponse(CMD_ACK,&resp); - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog(" Answers to chinese magic backdoor commands: %s", (isOK ? "YES" : "NO") ); - - // disconnect - c.cmd = CMD_READER_ISO_14443a; - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - return select_status; } @@ -536,22 +397,19 @@ int CmdHF14ACmdRaw(const char *cmd) { uint8_t active=0; uint8_t active_select=0; uint16_t numbits=0; - uint16_t timeout=0; - uint8_t bTimeout=0; char buf[5]=""; int i=0; - uint8_t data[USB_CMD_DATA_SIZE]; + uint8_t data[100]; unsigned int datalen=0, temp; if (strlen(cmd)<2) { - PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <0A 0B 0C ... hex>"); + PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] <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"); PrintAndLog(" -a active signal field ON without select"); PrintAndLog(" -s active signal field ON with select"); PrintAndLog(" -b number of bits to send. Useful for send partial byte"); - PrintAndLog(" -t timeout"); return 0; } @@ -584,14 +442,6 @@ int CmdHF14ACmdRaw(const char *cmd) { while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } i-=2; break; - case 't': - bTimeout=1; - sscanf(cmd+i+2,"%d",&temp); - timeout = temp & 0xFFFF; - i+=3; - while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } - i+=2; - break; default: PrintAndLog("Invalid option"); return 0; @@ -609,19 +459,15 @@ int CmdHF14ACmdRaw(const char *cmd) { if (strlen(buf)>=2) { sscanf(buf,"%x",&temp); data[datalen]=(uint8_t)(temp & 0xff); + datalen++; *buf=0; - if (++datalen>sizeof(data)){ - if (crc) - PrintAndLog("Buffer is full, we can't add CRC to your data"); - break; - } } continue; } PrintAndLog("Invalid char on input"); return 0; } - if(crc && datalen>0 && datalen0) { uint8_t first, second; ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second); @@ -635,22 +481,13 @@ int CmdHF14ACmdRaw(const char *cmd) { if(active) c.arg[0] |= ISO14A_NO_SELECT; } - if(bTimeout){ - #define MAX_TIMEOUT 624*105 // max timeout is 624 ms - c.arg[0] |= ISO14A_SET_TIMEOUT; - c.arg[2] = timeout * 105; // each bit is about 9.4 us - if(c.arg[2]>MAX_TIMEOUT) { - c.arg[2] = MAX_TIMEOUT; - PrintAndLog("Set timeout to 624 ms. The max we can wait for response"); - } - } if(power) c.arg[0] |= ISO14A_NO_DISCONNECT; if(datalen>0) c.arg[0] |= ISO14A_RAW; - // Max buffer is USB_CMD_DATA_SIZE - c.arg[1] = (datalen & 0xFFFF) | (numbits << 16); + c.arg[1] = datalen; + c.arg[2] = numbits; memcpy(c.d.asBytes,data,datalen); SendCommand(&c); @@ -670,7 +507,7 @@ static void waitCmd(uint8_t iSelect) UsbCommand resp; char *hexout; - if (WaitForResponseTimeout(CMD_ACK,&resp,10000)) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0]; PrintAndLog("received %i octets",iLen); diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 2c4c5949..7e4cbd00 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -13,15 +13,17 @@ #include #include #include -#include "../common/iso14443crc.h" +#include "iso14443crc.h" #include "proxmark3.h" #include "data.h" #include "graph.h" +#include "util.h" #include "ui.h" #include "cmdparser.h" #include "cmdhf14b.h" #include "cmdmain.h" + static int CmdHelp(const char *Cmd); int CmdHF14BDemod(const char *Cmd) @@ -144,7 +146,7 @@ demodError: int CmdHF14BList(const char *Cmd) { - uint8_t got[TRACE_BUFFER_SIZE]; + uint8_t got[960]; GetFromBigBuf(got,sizeof(got),0); WaitForResponse(CMD_ACK,NULL); @@ -156,8 +158,9 @@ int CmdHF14BList(const char *Cmd) int prev = -1; for(;;) { - - if(i >= TRACE_BUFFER_SIZE) { break; } + if(i >= 900) { + break; + } bool isResponse; int timestamp = *((uint32_t *)(got+i)); @@ -174,7 +177,7 @@ int CmdHF14BList(const char *Cmd) if(len > 100) { break; } - if(i + len >= TRACE_BUFFER_SIZE) { + if(i + len >= 900) { break; } @@ -356,7 +359,7 @@ int CmdHF14BCmdRaw (const char *cmd) { SendCommand(&c); if (reply) { - if (WaitForResponseTimeout(CMD_ACK,&resp,10000)) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; PrintAndLog("received %i octets",resp.arg[0]); if(!resp.arg[0]) diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 25ae2a82..b1e04e9a 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -31,9 +31,10 @@ #include "data.h" #include "graph.h" #include "ui.h" +#include "util.h" #include "cmdparser.h" #include "cmdhf15.h" -#include "../common/iso15693tools.h" +#include "iso15693tools.h" #include "cmdmain.h" #define FrameSOF Iso15693FrameSOF @@ -44,7 +45,6 @@ #define Crc(data,datalen) Iso15693Crc(data,datalen) #define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) #define sprintUID(target,uid) Iso15693sprintUID(target,uid) -#define TRACE_BUFF_SIZE 12000 // structure and database for uid -> tagtype lookups typedef struct { @@ -255,17 +255,6 @@ int CmdHF15Read(const char *Cmd) { UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693}; SendCommand(&c); - - uint8_t data[TRACE_BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); - - for (int j = 0; j < TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]) ; - } - GraphTraceLen = TRACE_BUFF_SIZE; - RepaintGraphWindow(); return 0; } @@ -274,17 +263,6 @@ int CmdHF15Record(const char *Cmd) { UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693}; SendCommand(&c); - - uint8_t data[TRACE_BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,TRACE_BUFF_SIZE,3560); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); - - for (int j = 0; j < TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]) ; - } - GraphTraceLen = TRACE_BUFF_SIZE; - RepaintGraphWindow(); return 0; } @@ -582,9 +560,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)++; diff --git a/client/cmdhfdes.c b/client/cmdhfdes.c deleted file mode 100644 index 1876e5c1..00000000 --- a/client/cmdhfdes.c +++ /dev/null @@ -1,69 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 "); - 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 deleted file mode 100644 index e51797cb..00000000 --- a/client/cmdhfdes.h +++ /dev/null @@ -1,27 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 -#include -#include -#include -#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 diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index afcdb0fa..3286ceb9 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -13,7 +13,7 @@ #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" -#include "../include/common.h" +#include "common.h" #include "cmdmain.h" #include "sleep.h" #include "cmdhfepa.h" diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 38713220..b097eea8 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -20,7 +20,7 @@ #include "ui.h" #include "cmdparser.h" #include "cmdhficlass.h" -#include "../include/common.h" +#include "common.h" #include "util.h" #include "cmdmain.h" #include "loclass/des.h" @@ -34,53 +34,17 @@ static int CmdHelp(const char *Cmd); int xorbits_8(uint8_t val) { - uint8_t res = val ^ (val >> 1); //1st pass - res = res ^ (res >> 1); // 2nd pass - res = res ^ (res >> 2); // 3rd pass - res = res ^ (res >> 4); // 4th pass - return res & 1; -} - -#define ICLASS_CMD_ACTALL 0x0A -#define ICLASS_CMD_IDENTIFY 0x0C -#define ICLASS_CMD_READ 0x0C - -#define ICLASS_CMD_SELECT 0x81 -#define ICLASS_CMD_PAGESEL 0x84 -#define ICLASS_CMD_READCHECK 0x88 -#define ICLASS_CMD_CHECK 0x05 -#define ICLASS_CMD_SOF 0x0F -#define ICLASS_CMD_HALT 0x00 - - -void explain(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) -{ - - if(cmdsize > 1 && cmd[0] == ICLASS_CMD_READ) - { - snprintf(exp,size,"READ(%d)",cmd[1]); - return; - } - - switch(cmd[0]) - { - case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break; - case ICLASS_CMD_IDENTIFY: snprintf(exp,size,"IDENTIFY"); break; - case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; - case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL"); break; - case ICLASS_CMD_READCHECK: snprintf(exp,size,"READCHECK"); break; - case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; - case ICLASS_CMD_SOF: snprintf(exp,size,"SOF"); break; - case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; - default: snprintf(exp,size,"?"); break; - } - return; + uint8_t res = val ^ (val >> 1); //1st pass + res = res ^ (res >> 1); // 2nd pass + res = res ^ (res >> 2); // 3rd pass + res = res ^ (res >> 4); // 4th pass + return res & 1; } int CmdHFiClassList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list iclass' instead"); - return 0; + return 0; } int CmdHFiClassSnoop(const char *Cmd) @@ -140,24 +104,24 @@ int CmdHFiClassSim(const char *Cmd) 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 }; */ - uint8_t csns[8*NUM_CSNS] = { - 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 }; - - memcpy(c.d.asBytes, csns, 8*NUM_CSNS); + uint8_t csns[8*NUM_CSNS] = { + 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 }; + + memcpy(c.d.asBytes, csns, 8*NUM_CSNS); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK, &resp, -1)) { @@ -166,7 +130,7 @@ int CmdHFiClassSim(const char *Cmd) } uint8_t num_mac_responses = resp.arg[1]; - PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses, NUM_CSNS); + PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses,NUM_CSNS); size_t datalen = NUM_CSNS*24; /* @@ -245,7 +209,7 @@ int CmdHFiClassReader_Replay(const char *Cmd) if (strlen(Cmd)<1) { PrintAndLog("Usage: hf iclass replay "); PrintAndLog(" sample: hf iclass replay 00112233"); - return 0; + return 0; } if (param_gethex(Cmd, 0, MAC, 8)) { @@ -323,7 +287,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) UsbCommand c = {CMD_READER_ICLASS, {0}}; c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE| FLAG_ICLASS_READER_GET_CC; if(!fake_dummy_test) - SendCommand(&c); + SendCommand(&c); @@ -469,19 +433,64 @@ int CmdHFiClass_iso14443A_write(const char *Cmd) } return 0; } +int CmdHFiClass_loclass(const char *Cmd) +{ + char opt = param_getchar(Cmd, 0); + if (strlen(Cmd)<1 || opt == 'h') { + PrintAndLog("Usage: hf iclass loclass [options]"); + PrintAndLog("Options:"); + PrintAndLog("h Show this help"); + PrintAndLog("t Perform self-test"); + PrintAndLog("f Bruteforce iclass dumpfile"); + PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of"); + PrintAndLog(" malicious CSNs, and their protocol responses"); + PrintAndLog(" The the binary format of the file is expected to be as follows: "); + PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>"); + PrintAndLog(" ... totalling N*24 bytes"); + return 0; + } + char fileName[255] = {0}; + if(opt == 'f') + { + if(param_getstr(Cmd, 1, fileName) > 0) + { + return bruteforceFileNoKeys(fileName); + }else + { + PrintAndLog("You must specify a filename"); + } + } + else if(opt == 't') + { + int errors = testCipherUtils(); + errors += testMAC(); + errors += doKeyTests(0); + errors += testElite(); + if(errors) + { + prnlog("OBS! There were errors!!!"); + } + return errors; + } + + return 0; +} static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdHFiClassList, 0, "[Deprecated] List iClass history"}, - {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"}, - {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"}, - {"reader",CmdHFiClassReader, 0, "Read an iClass tag"}, - {"replay", CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"}, - {"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"}, - {"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"list", CmdHFiClassList, 0, "[Deprecated] List iClass history"}, + {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"}, + {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"}, + {"reader",CmdHFiClassReader, 0, "Read an iClass tag"}, + {"replay",CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"}, + {"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"}, + {"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"}, + {"loclass", CmdHFiClass_loclass, 1, "Use loclass to perform bruteforce of reader attack dump"}, + {NULL, NULL, 0, NULL} }; int CmdHFiClass(const char *Cmd) @@ -493,5 +502,5 @@ int CmdHFiClass(const char *Cmd) int CmdHelp(const char *Cmd) { CmdsHelp(CommandTable); - return 0; + return 0; } diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 35ba1f28..bf874b62 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -218,24 +218,7 @@ int CmdLegicRFRead(const char *Cmd) int CmdLegicLoad(const char *Cmd) { - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; - - if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { - PrintAndLog("It loads datasamples from the file `filename`"); - PrintAndLog("Usage: hf legic load "); - PrintAndLog(" sample: hf legic load filename"); - return 0; - } - - len = strlen(Cmd); - if (len > FILE_PATH_SIZE) { - PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE); - return 0; - } - memcpy(filename, Cmd, len); - - FILE *f = fopen(filename, "r"); + FILE *f = fopen(Cmd, "r"); if(!f) { PrintAndLog("couldn't open '%s'", Cmd); return -1; @@ -268,7 +251,7 @@ int CmdLegicSave(const char *Cmd) int requested = 1024; int offset = 0; int delivered = 0; - char filename[FILE_PATH_SIZE]; + char filename[1024]; uint8_t got[1024]; sscanf(Cmd, " %s %i %i", filename, &requested, &offset); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 49928c9a..121736e9 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -7,7 +7,7 @@ //----------------------------------------------------------------------------- // High frequency MIFARE commands //----------------------------------------------------------------------------- -#include "../include/mifare.h" + #include "cmdhfmf.h" static int CmdHelp(const char *Cmd); @@ -34,7 +34,7 @@ start: SendCommand(&c); //flush queue - while (ukbhit()) getchar(); + while (ukbhit()) getchar(); // wait cycle while (true) { @@ -66,19 +66,20 @@ start: if (isOK != 1) return 1; // execute original function from util nonce2key - if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) { + if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) + { isOK = 2; PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); } else { printf("------------------------------------------------------------------\n"); - PrintAndLog("Key found :%012"llx" \n", r_key); + PrintAndLog("Key found:%012"llx" \n", r_key); num_to_bytes(r_key, 6, keyBlock); isOK = mfCheckKeys(0, 0, 1, keyBlock, &r_key); } if (!isOK) - PrintAndLog("Found valid key :%012"llx, r_key); + PrintAndLog("Found valid key:%012"llx, r_key); else { if (isOK != 2) PrintAndLog("Found invalid key. "); @@ -124,10 +125,10 @@ int CmdHF14AMfWrBl(const char *Cmd) PrintAndLog("--block no:%d, key type:%c, key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6)); PrintAndLog("--data: %s", sprint_hex(bldata, 16)); - UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; + UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); memcpy(c.d.asBytes + 10, bldata, 16); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -140,6 +141,117 @@ int CmdHF14AMfWrBl(const char *Cmd) return 0; } +int CmdHF14AMfUWrBl(const char *Cmd) +{ + uint8_t blockNo = 0; + bool chinese_card=0; + uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + UsbCommand resp; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mf uwrbl "); + PrintAndLog(" sample: hf mf uwrbl 0 01020304"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + if (param_gethex(Cmd, 1, bldata, 8)) { + PrintAndLog("Block data must include 8 HEX symbols"); + return 1; + } + + if (strchr(Cmd,'w') != 0) { + chinese_card=1; + } + + switch(blockNo){ + case 0: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%d", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 1: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%d", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 2: + if (!chinese_card){ + PrintAndLog("Access Denied"); + }else{ + PrintAndLog("--specialblock no:%d", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(c.d.asBytes, bldata, 4); + SendCommand(&c); + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + } + break; + case 3: + PrintAndLog("--specialblock no:%d", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(d.d.asBytes,bldata, 4); + SendCommand(&d); + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + default: + PrintAndLog("--block no:%d", blockNo); + PrintAndLog("--data: %s", sprint_hex(bldata, 4)); + UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; + memcpy(e.d.asBytes,bldata, 4); + SendCommand(&e); + + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + break; + } + return 0; +} + + int CmdHF14AMfRdBl(const char *Cmd) { uint8_t blockNo = 0; @@ -168,9 +280,9 @@ int CmdHF14AMfRdBl(const char *Cmd) } PrintAndLog("--block no:%d, key type:%c, key:%s ", blockNo, keyType?'B':'A', sprint_hex(key, 6)); - UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; + UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -188,6 +300,87 @@ int CmdHF14AMfRdBl(const char *Cmd) return 0; } +int CmdHF14AMfURdBl(const char *Cmd) +{ + uint8_t blockNo = 0; + + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf mf urdbl "); + PrintAndLog(" sample: hf mf urdbl 0"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + PrintAndLog("--block no:%d", blockNo); + + UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; + 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, 4)); + else + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} + + +int CmdHF14AMfURdCard(const char *Cmd) +{ + int i; + uint8_t sectorNo = 0; + uint8_t *lockbytes_t=NULL; + uint8_t lockbytes[2]={0,0}; + bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + + PrintAndLog("Attempting to Read Ultralight... "); + + UsbCommand c = {CMD_MIFAREU_READCARD, {sectorNo}}; + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + data = resp.d.asBytes; + + PrintAndLog("isOk:%02x", isOK); + if (isOK) + { // bit 0 and 1 + PrintAndLog("Block %3d:%s ", 0,sprint_hex(data + 0 * 4, 4)); + PrintAndLog("Block %3d:%s ", 1,sprint_hex(data + 1 * 4, 4)); + // bit 2 + //process lock bytes + lockbytes_t=data+(2*4); + lockbytes[0]=lockbytes_t[2]; + lockbytes[1]=lockbytes_t[3]; + for(int j=0; j<16; j++){ + bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); + } + //remaining + for (i = 3; i < 16; i++) { + int bitnum = (23-i) % 16; + PrintAndLog("Block %3d:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[bitnum]); + } + + } + } else { + PrintAndLog("Command execute timeout"); + } + return 0; +} + + int CmdHF14AMfRdSc(const char *Cmd) { int i; @@ -278,14 +471,7 @@ int CmdHF14AMfDump(const char *Cmd) UsbCommand resp; - int size = GetCardSize(); char cmdp = param_getchar(Cmd, 0); - - if ( size > -1) - cmdp = (char)(48+size); - - PrintAndLog("Got %d",cmdp); - switch (cmdp) { case '0' : numSectors = 5; break; case '1' : @@ -305,7 +491,7 @@ int CmdHF14AMfDump(const char *Cmd) } if ((fin = fopen("dumpkeys.bin","rb")) == NULL) { - PrintAndLog("Could not find file dumpkeys.bin"); + PrintAndLog("Could not find file dumpkeys.bin"); return 1; } @@ -326,9 +512,9 @@ int CmdHF14AMfDump(const char *Cmd) return 2; } } - fclose(fin); - + // Read access rights to sectors + PrintAndLog("|-----------------------------------------|"); PrintAndLog("|------ Reading sector access bits...-----|"); PrintAndLog("|-----------------------------------------|"); @@ -358,6 +544,8 @@ int CmdHF14AMfDump(const char *Cmd) } } + // Read blocks and print to file + PrintAndLog("|-----------------------------------------|"); PrintAndLog("|----- Dumping all blocks to file... -----|"); PrintAndLog("|-----------------------------------------|"); @@ -381,12 +569,12 @@ int CmdHF14AMfDump(const char *Cmd) received = WaitForResponseTimeout(CMD_ACK,&resp,1500); } else if (rights[sectorNo][data_area] == 0x07) { // no key would work isOK = false; - PrintAndLog("Access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo); + PrintAndLog("Access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo); } else { // key A would work - UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; - memcpy(c.d.asBytes, keyA[sectorNo], 6); - SendCommand(&c); - received = WaitForResponseTimeout(CMD_ACK,&resp,1500); + UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; + memcpy(c.d.asBytes, keyA[sectorNo], 6); + SendCommand(&c); + received = WaitForResponseTimeout(CMD_ACK,&resp,1500); } } @@ -433,7 +621,7 @@ int CmdHF14AMfDump(const char *Cmd) fclose(fout); PrintAndLog("Dumped %d blocks (%d bytes) to file dumpdata.bin", numblocks, 16*numblocks); } - + return 0; } @@ -441,8 +629,8 @@ int CmdHF14AMfRestore(const char *Cmd) { uint8_t sectorNo,blockNo; uint8_t keyType = 0; - uint8_t key[6] = {0xFF}; - uint8_t bldata[16] = {0x00}; + uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t keyA[40][6]; uint8_t keyB[40][6]; uint8_t numSectors; @@ -460,7 +648,7 @@ int CmdHF14AMfRestore(const char *Cmd) default: numSectors = 16; } - if (cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: hf mf restore [card memory]"); PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLog(""); @@ -468,15 +656,22 @@ int CmdHF14AMfRestore(const char *Cmd) PrintAndLog(" hf mf restore 4"); return 0; } - + + if ((fdump = fopen("dumpdata.bin","rb")) == NULL) { + PrintAndLog("Could not find file dumpdata.bin"); + return 1; + } if ((fkeys = fopen("dumpkeys.bin","rb")) == NULL) { PrintAndLog("Could not find file dumpkeys.bin"); + fclose(fdump); return 1; } for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { if (fread(keyA[sectorNo], 1, 6, fkeys) == 0) { PrintAndLog("File reading error (dumpkeys.bin)."); + fclose(fdump); + fclose(fkeys); return 2; } } @@ -484,16 +679,13 @@ int CmdHF14AMfRestore(const char *Cmd) for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { if (fread(keyB[sectorNo], 1, 6, fkeys) == 0) { PrintAndLog("File reading error (dumpkeys.bin)."); + fclose(fdump); + fclose(fkeys); return 2; } } - fclose(fkeys); - - if ((fdump = fopen("dumpdata.bin","rb")) == NULL) { - PrintAndLog("Could not find file dumpdata.bin"); - return 1; - } + PrintAndLog("Restoring dumpdata.bin to card"); for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { @@ -551,7 +743,7 @@ int CmdHF14AMfNested(const char *Cmd) uint8_t trgKeyType = 0; uint8_t SectorsCnt = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - uint8_t keyBlock[13*6]; + uint8_t keyBlock[6*6]; uint64_t key64 = 0; bool transferToEml = false; @@ -581,15 +773,11 @@ int CmdHF14AMfNested(const char *Cmd) cmdp = param_getchar(Cmd, 0); blockNo = param_get8(Cmd, 1); ctmp = param_getchar(Cmd, 2); - if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') { PrintAndLog("Key type must be A or B"); return 1; } - - if (ctmp != 'A' && ctmp != 'a') - keyType = 1; - + if (ctmp != 'A' && ctmp != 'a') keyType = 1; if (param_gethex(Cmd, 3, key, 12)) { PrintAndLog("Key must include 12 HEX symbols"); return 1; @@ -603,10 +791,8 @@ int CmdHF14AMfNested(const char *Cmd) PrintAndLog("Target key type must be A or B"); return 1; } - if (ctmp != 'A' && ctmp != 'a') - trgKeyType = 1; + if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1; } else { - switch (cmdp) { case '0': SectorsCnt = 05; break; case '1': SectorsCnt = 16; break; @@ -668,14 +854,6 @@ int CmdHF14AMfNested(const char *Cmd) num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 3 * 6)); num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 4 * 6)); num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6)); - num_to_bytes(0x4d3a99c351dd, 6, (uint8_t*)(keyBlock + 6 * 6)); - num_to_bytes(0x1a982c7e459a, 6, (uint8_t*)(keyBlock + 7 * 6)); - num_to_bytes(0xd3f7d3f7d3f7, 6, (uint8_t*)(keyBlock + 8 * 6)); - num_to_bytes(0x714c5c886e97, 6, (uint8_t*)(keyBlock + 9 * 6)); - num_to_bytes(0x587ee5f9350f, 6, (uint8_t*)(keyBlock + 10 * 6)); - num_to_bytes(0xa0478cc39091, 6, (uint8_t*)(keyBlock + 11 * 6)); - num_to_bytes(0x533cb6c723f6, 6, (uint8_t*)(keyBlock + 12 * 6)); - num_to_bytes(0x8fd0a4f256e9, 6, (uint8_t*)(keyBlock + 13 * 6)); PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); for (i = 0; i < SectorsCnt; i++) { @@ -691,26 +869,21 @@ int CmdHF14AMfNested(const char *Cmd) } } + // nested sectors iterations = 0; PrintAndLog("nested..."); bool calibrate = true; for (i = 0; i < NESTED_SECTOR_RETRY; i++) { for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { - - if (ukbhit()) { - printf("\naborted via keyboard!\n"); - free(e_sector); - return 2; - } - for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { if (e_sector[sectorNo].foundKey[trgKeyType]) continue; PrintAndLog("-----------------------------------------------"); if(mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate)) { PrintAndLog("Nested error.\n"); free(e_sector); - return 2; } + return 2; + } else { calibrate = false; } @@ -780,7 +953,7 @@ int CmdHF14AMfNested(const char *Cmd) } fclose(fkeys); } - + free(e_sector); } return 0; @@ -789,19 +962,17 @@ int CmdHF14AMfNested(const char *Cmd) int CmdHF14AMfChk(const char *Cmd) { if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf mf chk |<*card memory> [t|d] [] []"); + PrintAndLog("Usage: hf mf chk |<*card memory> [t] [] []"); PrintAndLog(" * - all sectors"); PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); PrintAndLog("d - write keys to binary file\n"); - PrintAndLog("t - write keys to emulator memory"); PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic"); PrintAndLog(" hf mf chk *1 ? t"); - PrintAndLog(" hf mf chk *1 ? d"); return 0; - } - + } + FILE * f; - char filename[FILE_PATH_SIZE]={0}; + char filename[256]={0}; char buf[13]; uint8_t *keyBlock = NULL, *p; uint8_t stKeyBlock = 20; @@ -893,7 +1064,7 @@ int CmdHF14AMfChk(const char *Cmd) keycnt++; } else { // May be a dic file - if ( param_getstr(Cmd, 2 + i,filename) >= FILE_PATH_SIZE ) { + if ( param_getstr(Cmd, 2 + i,filename) > 255 ) { PrintAndLog("File name too long"); free(keyBlock); return 2; @@ -944,8 +1115,8 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("No key specified, trying default keys"); for (;keycnt < defaultKeysSize; keycnt++) PrintAndLog("chk default key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, - (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], - (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); + (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], + (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); } // initialize storage for found keys @@ -990,13 +1161,13 @@ int CmdHF14AMfChk(const char *Cmd) for (uint16_t t = 0; t < 2; t++) { if (validKey[t][sectorNo]) { memcpy(block + t*10, foundKey[t][sectorNo], 6); - } - } + } + } mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); } } PrintAndLog("Found keys have been transferred to the emulator memory"); - } + } if (createDumpFile) { FILE *fkeys = fopen("dumpkeys.bin","wb"); @@ -1004,7 +1175,7 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("Could not create file dumpkeys.bin"); free(keyBlock); return 1; - } + } for (uint16_t t = 0; t < 2; t++) { fwrite(foundKey[t], 1, 6*SectorsCnt, fkeys); } @@ -1014,7 +1185,7 @@ int CmdHF14AMfChk(const char *Cmd) free(keyBlock); PrintAndLog(""); - return 0; + return 0; } int CmdHF14AMf1kSim(const char *Cmd) @@ -1174,44 +1345,26 @@ int CmdHF14AMfESet(const char *Cmd) int CmdHF14AMfELoad(const char *Cmd) { FILE * f; - char filename[FILE_PATH_SIZE]; + char filename[20]; char *fnameptr = filename; char buf[64]; uint8_t buf8[64]; - int i, len, blockNum, numBlocks; - int nameParamNo = 1; + int i, len, blockNum; memset(filename, 0, sizeof(filename)); memset(buf, 0, sizeof(buf)); - char ctmp = param_getchar(Cmd, 0); - - if ( ctmp == 'h' || ctmp == 0x00) { + if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { PrintAndLog("It loads emul dump from the file `filename.eml`"); - PrintAndLog("Usage: hf mf eload [card memory] "); - PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); - PrintAndLog(""); + PrintAndLog("Usage: hf mf eload "); PrintAndLog(" sample: hf mf eload filename"); - PrintAndLog(" hf mf eload 4 filename"); return 0; } - switch (ctmp) { - case '0' : numBlocks = 5*4; break; - case '1' : - case '\0': numBlocks = 16*4; break; - case '2' : numBlocks = 32*4; break; - case '4' : numBlocks = 256; break; - default: { - numBlocks = 16*4; - nameParamNo = 0; - } - } - - len = param_getstr(Cmd,nameParamNo,filename); - - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + len = strlen(Cmd); + if (len > 14) len = 14; + memcpy(filename, Cmd, len); fnameptr += len; sprintf(fnameptr, ".eml"); @@ -1226,16 +1379,14 @@ int CmdHF14AMfELoad(const char *Cmd) blockNum = 0; while(!feof(f)){ memset(buf, 0, sizeof(buf)); - if (fgets(buf, sizeof(buf), f) == NULL) { - - if (blockNum >= numBlocks) break; - + if((blockNum == 16*4) || (blockNum == 32*4 + 8*16)) { // supports both old (1K) and new (4K) .eml files) + break; + } PrintAndLog("File reading error."); fclose(f); return 2; } - if (strlen(buf) < 32){ if(strlen(buf) && feof(f)) break; @@ -1243,7 +1394,6 @@ int CmdHF14AMfELoad(const char *Cmd) fclose(f); return 2; } - for (i = 0; i < 32; i += 2) { sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]); } @@ -1255,12 +1405,12 @@ int CmdHF14AMfELoad(const char *Cmd) } blockNum++; - if (blockNum >= numBlocks) break; + if (blockNum >= 32*4 + 8*16) break; } fclose(f); - if ((blockNum != numBlocks)) { - PrintAndLog("File content error. Got %d must be %d blocks.",blockNum, numBlocks); + if ((blockNum != 16*4) && (blockNum != 32*4 + 8*16)) { + PrintAndLog("File content error. There must be 64 or 256 blocks."); return 4; } PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename); @@ -1271,65 +1421,45 @@ int CmdHF14AMfELoad(const char *Cmd) int CmdHF14AMfESave(const char *Cmd) { FILE * f; - char filename[FILE_PATH_SIZE]; + char filename[20]; char * fnameptr = filename; uint8_t buf[64]; - int i, j, len, numBlocks; - int nameParamNo = 1; + int i, j, len; memset(filename, 0, sizeof(filename)); memset(buf, 0, sizeof(buf)); - char ctmp = param_getchar(Cmd, 0); - - if ( ctmp == 'h') { - PrintAndLog("It saves emul dump into the file `filename.eml` or `cardID.eml`"); - PrintAndLog(" Usage: hf mf esave [card memory] [file name w/o `.eml`]"); - PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); - PrintAndLog(""); + if (param_getchar(Cmd, 0) == 'h') { + PrintAndLog("It saves emul dump into the file `filename.eml` or `cardID.eml`"); + PrintAndLog("Usage: hf mf esave [file name w/o `.eml`]"); PrintAndLog(" sample: hf mf esave "); - PrintAndLog(" hf mf esave 4"); - PrintAndLog(" hf mf esave 4 filename"); + PrintAndLog(" hf mf esave filename"); return 0; } - - switch (ctmp) { - case '0' : numBlocks = 5*4; break; - case '1' : - case '\0': numBlocks = 16*4; break; - case '2' : numBlocks = 32*4; break; - case '4' : numBlocks = 256; break; - default: { - numBlocks = 16*4; - nameParamNo = 0; - } - } - len = param_getstr(Cmd,nameParamNo,filename); + len = strlen(Cmd); + if (len > 14) len = 14; - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - - // user supplied filename? if (len < 1) { - // get filename (UID from memory) + // get filename if (mfEmlGetMem(buf, 0, 1)) { - PrintAndLog("Can\'t get UID from block: %d", 0); - sprintf(filename, "dump.eml"); + PrintAndLog("Cant get block: %d", 0); + return 1; } for (j = 0; j < 7; j++, fnameptr += 2) - sprintf(fnameptr, "%02X", buf[j]); + sprintf(fnameptr, "%02x", buf[j]); } else { + memcpy(filename, Cmd, len); fnameptr += len; } - // add file extension sprintf(fnameptr, ".eml"); // open file f = fopen(filename, "w+"); // put hex - for (i = 0; i < numBlocks; i++) { + for (i = 0; i < 32*4 + 8*16; i++) { if (mfEmlGetMem(buf, i, 1)) { PrintAndLog("Cant get block: %d", i); break; @@ -1340,7 +1470,7 @@ int CmdHF14AMfESave(const char *Cmd) } fclose(f); - PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename); + PrintAndLog("Saved to file: %s", filename); return 0; } @@ -1389,34 +1519,13 @@ int CmdHF14AMfECFill(const char *Cmd) int CmdHF14AMfEKeyPrn(const char *Cmd) { int i; - uint8_t numSectors; uint8_t data[16]; uint64_t keyA, keyB; - if (param_getchar(Cmd, 0) == 'h') { - PrintAndLog("It prints the keys loaded in the emulator memory"); - PrintAndLog("Usage: hf mf ekeyprn [card memory]"); - PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); - PrintAndLog(""); - PrintAndLog(" sample: hf mf ekeyprn 1"); - return 0; - } - - char cmdp = param_getchar(Cmd, 0); - - switch (cmdp) { - case '0' : numSectors = 5; break; - case '1' : - case '\0': numSectors = 16; break; - case '2' : numSectors = 32; break; - case '4' : numSectors = 40; break; - default: numSectors = 16; - } - PrintAndLog("|---|----------------|----------------|"); PrintAndLog("|sec|key A |key B |"); PrintAndLog("|---|----------------|----------------|"); - for (i = 0; i < numSectors; i++) { + for (i = 0; i < 40; i++) { if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); break; @@ -1458,9 +1567,9 @@ int CmdHF14AMfCSetUID(const char *Cmd) res = mfCSetUID(uid, oldUid, wipeCard); if (res) { - PrintAndLog("Can't set UID. error=%d", res); - return 1; - } + PrintAndLog("Can't set UID. error=%d", res); + return 1; + } PrintAndLog("old UID:%s", sprint_hex(oldUid, 4)); PrintAndLog("new UID:%s", sprint_hex(uid, 4)); @@ -1506,7 +1615,7 @@ int CmdHF14AMfCSetBlk(const char *Cmd) int CmdHF14AMfCLoad(const char *Cmd) { FILE * f; - char filename[FILE_PATH_SIZE]; + char filename[20]; char * fnameptr = filename; char buf[64]; uint8_t buf8[64]; @@ -1547,7 +1656,7 @@ int CmdHF14AMfCLoad(const char *Cmd) return 0; } else { len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + if (len > 14) len = 14; memcpy(filename, Cmd, len); fnameptr += len; @@ -1592,7 +1701,7 @@ int CmdHF14AMfCLoad(const char *Cmd) } fclose(f); - if (blockNum != 16 * 4 && blockNum != 32 * 4 + 8 * 16){ + if (blockNum != 16 * 4){ PrintAndLog("File content error. There must be 64 blocks"); return 4; } @@ -1670,7 +1779,7 @@ int CmdHF14AMfCGetSc(const char *Cmd) { int CmdHF14AMfCSave(const char *Cmd) { FILE * f; - char filename[FILE_PATH_SIZE]; + char filename[20]; char * fnameptr = filename; uint8_t fillFromEmulator = 0; uint8_t buf[64]; @@ -1712,7 +1821,7 @@ int CmdHF14AMfCSave(const char *Cmd) { return 0; } else { len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + if (len > 14) len = 14; if (len < 1) { // get filename @@ -1876,7 +1985,7 @@ int CmdHF14AMfSniff(const char *Cmd){ mfTraceDecode(bufPtr, len, wantSaveToEmlFile); } bufPtr += len; - bufPtr += ((len-1)/8+1); // ignore parity + bufPtr += ((len-1)/8+1); // ignore parity num++; } } @@ -1886,106 +1995,14 @@ int CmdHF14AMfSniff(const char *Cmd){ return 0; } -// Tries to identify cardsize. -// Returns where num is: -// -1 unidentified -// 0 - MINI (320bytes) -// 1 - 1K -// 2 - 2K -// 4 - 4K -int GetCardSize() -{ - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; - SendCommand(&c); - - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - - if(resp.arg[0] == 0) { - PrintAndLog("iso14443a card select failed"); - return -1; - } - - iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes; - - PrintAndLog("Trying to detect card size."); - - uint16_t atqa = 0; - uint8_t sak = 0; - atqa = (card->atqa[1] & 0xff) << 8; - atqa += card->atqa[0] & 0xff; - sak = card->sak; - - // https://code.google.com/p/libnfc/source/browse/libnfc/target-subr.c - - PrintAndLog("found ATAQ: %04X SAK: %02X", atqa, sak); - - - // NXP MIFARE Mini 0.3k - if ( ( (atqa & 0xff0f) == 0x0004) && (sak == 0x09) ) return 0; - - // MIFARE Classic 1K - if ( ((atqa & 0xff0f) == 0x0004) && (sak == 0x08) ) return 1; - - // MIFARE Classik 4K - if ( ((atqa & 0xff0f) == 0x0002) && (sak == 0x18) ) return 4; - - // SmartMX with MIFARE 1K emulation - if ( ((atqa & 0xf0ff) == 0x0004) ) return 1; - - // SmartMX with MIFARE 4K emulation - if ( ((atqa & 0xf0ff) == 0x0002) ) return 4; - - // Infineon MIFARE CLASSIC 1K - if ( ((atqa & 0xffff) == 0x0004) && (sak == 0x88) ) return 1; - - // MFC 4K emulated by Nokia 6212 Classic - if ( ((atqa & 0xffff) == 0x0002) && (sak == 0x38) ) return 4; - - // MFC 4K emulated by Nokia 6131 NFC - if ( ((atqa & 0xffff) == 0x0008) && (sak == 0x38) ) return 4; - - - PrintAndLog("BEFOOO 1K %02X", (atqa & 0xff0f)); - - // MIFARE Plus (4 Byte UID or 4 Byte RID) - // MIFARE Plus (7 Byte UID) - if ( - ((atqa & 0xffff) == 0x0002) | - ((atqa & 0xffff) == 0x0004) | - ((atqa & 0xffff) == 0x0042) | - ((atqa & 0xffff) == 0x0044) - ) - { - switch(sak){ - case 0x08: - case 0x10: { - //case 0x20: - PrintAndLog("2"); - return 2; - break; - } - case 0x11: - case 0x18:{ - //case 0x20: - PrintAndLog("4"); - return 4; - break; - } - } - } - - return -1; -} - static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, - //{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"}, - //{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, - //{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, + {"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"}, + {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, + {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 45ba7cb1..22dfd4de 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -16,11 +16,11 @@ #include #include #include "proxmark3.h" -#include "../common/iso14443crc.h" +#include "iso14443crc.h" #include "data.h" #include "ui.h" #include "cmdparser.h" -#include "../include/common.h" +#include "common.h" #include "util.h" #include "mifarehost.h" @@ -53,5 +53,5 @@ int CmdHF14AMfCGetBlk(const char* cmd); int CmdHF14AMfCGetSc(const char* cmd); int CmdHF14AMfCLoad(const char* cmd); int CmdHF14AMfCSave(const char* cmd); -int GetCardSize(); + #endif diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c deleted file mode 100644 index 75aaa084..00000000 --- a/client/cmdhfmfdes.c +++ /dev/null @@ -1,685 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 -#include -#include -#include -#include -#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" - -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); -static void xor(unsigned char * dst, unsigned char * src, size_t len); -static int32_t le24toh (uint8_t data[3]); - - -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 "); - 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 "); - // 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", GetVendorStr(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",GetVendorStr(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; -} - -char * GetVendorStr( uint8_t id){ - static char buf[30]; - char *retStr = buf; - - if ( id == 0x04 ) - sprintf(retStr, "0x%02X (NXP)",id); - else - sprintf(retStr,"0x%02X (Unknown)",id); - return buf; -} - -/* - 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 << 0 ) ) - 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", 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> "); - 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 void xor(unsigned char * dst, unsigned char * src, size_t len) { - for( ; len > 0; len--,dst++,src++) - *dst ^= *src; -} - -static int32_t le24toh (uint8_t data[3]) { - return (data[2] << 16) | (data[1] << 8) | data[0]; -} - -static command_t CommandTable[] = -{ - {"help", CmdHelp, 1, "This help"}, - {"auth", CmdHF14ADesAuth, 0, "Tries a MIFARE DesFire Authentication"}, - {"rb", CmdHF14ADesRb, 0, "Read MIFARE DesFire block"}, - {"wb", CmdHF14ADesWb, 0, "write MIFARE DesFire block"}, - {"info", CmdHF14ADesInfo, 0, "Get MIFARE DesFire information"}, - {"enum", CmdHF14ADesEnumApplications,0, "Tries enumerate all applications"}, - {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 deleted file mode 100644 index 6ebc98ae..00000000 --- a/client/cmdhfmfdes.h +++ /dev/null @@ -1,75 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 * GetVendorStr( uint8_t id); -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 deleted file mode 100644 index f2c53dbf..00000000 --- a/client/cmdhfmfdesfire.c +++ /dev/null @@ -1,250 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 -#include - -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 "); - 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 "); - 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 deleted file mode 100644 index c29fd262..00000000 --- a/client/cmdhfmfdesfire.h +++ /dev/null @@ -1,5 +0,0 @@ - -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 diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c deleted file mode 100644 index 52b7ad14..00000000 --- a/client/cmdhfmfu.c +++ /dev/null @@ -1,1157 +0,0 @@ -//----------------------------------------------------------------------------- -// Ultralight Code (c) 2013,2014 Midnitesnake & Andy Davies of Pentura -// -// 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 ULTRALIGHT (C) commands -//----------------------------------------------------------------------------- -#include -#include "cmdhfmf.h" - -uint8_t MAX_ULTRA_BLOCKS= 0x0f; -uint8_t MAX_ULTRAC_BLOCKS= 0x2c; -uint8_t key1_blnk_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; -uint8_t key2_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; -uint8_t key3_3des_data[16] = { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 }; -uint8_t key4_nfc_data[16] = { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 }; -uint8_t key5_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }; - -static int CmdHelp(const char *Cmd); - -// -// Mifare Ultralight Write Single Block -// -int CmdHF14AMfUWrBl(const char *Cmd){ - uint8_t blockNo = 0; - bool chinese_card = 0; - uint8_t bldata[16] = {0x00}; - UsbCommand resp; - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf mfu uwrbl [w]"); - PrintAndLog(" sample: hf mfu uwrbl 0 01020304"); - return 0; - } - blockNo = param_get8(Cmd, 0); - if (blockNo>MAX_ULTRA_BLOCKS){ - PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); - return 1; - } - if (param_gethex(Cmd, 1, bldata, 8)) { - PrintAndLog("Block data must include 8 HEX symbols"); - return 1; - } - if (strchr(Cmd,'w') != 0) { - chinese_card=1; - } - switch(blockNo){ - case 0: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 1: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 2: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(c.d.asBytes, bldata, 4); - SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 3: - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - break; - default: - PrintAndLog("--block no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(e.d.asBytes,bldata, 4); - SendCommand(&e); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - break; - } - return 0; -} - -// -// Mifare Ultralight Read Single Block -// -int CmdHF14AMfURdBl(const char *Cmd){ - - uint8_t blockNo = 0; - - if (strlen(Cmd)<1) { - PrintAndLog("Usage: hf mfu urdbl "); - PrintAndLog(" sample: hfu mfu urdbl 0"); - return 0; - } - - blockNo = param_get8(Cmd, 0); - // if (blockNo>MAX_ULTRA_BLOCKS){ - // PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!"); - // return 1; - // } - PrintAndLog("--block no:%02x", (int)blockNo); - UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; - 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, 4)); - else - PrintAndLog("isOk:%02x", isOK); - } - else { - PrintAndLog("Command execute timeout"); - } - return 0; -} - -// -// Mifare Ultralight Read (Dump) Card Contents -// -int CmdHF14AMfURdCard(const char *Cmd){ - int i; - uint8_t BlockNo = 0; - int pages=16; - uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0x00}; - bool bit[16]={0x00}; - bool dump=false; - uint8_t datatemp[7]= {0x00}; - - uint8_t isOK = 0; - uint8_t * data = NULL; - FILE *fout = NULL; - - if (strchr(Cmd,'x') != 0){ - dump=true; - if ((fout = fopen("dump_ultralight_data.bin","wb")) == NULL) { - PrintAndLog("Could not create file name dumpdata.bin"); - return 1; - } - PrintAndLog("Dumping Ultralight Card Data..."); - } - PrintAndLog("Attempting to Read Ultralight... "); - UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo, pages}}; - SendCommand(&c); - UsbCommand resp; - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - isOK = resp.arg[0] & 0xff; - data = resp.d.asBytes; - PrintAndLog("isOk:%02x", isOK); - if (isOK) { - - // UID - memcpy( datatemp, data,3); - memcpy( datatemp+3, data+4, 4); - PrintAndLog(" UID :%s ", sprint_hex(datatemp, 7)); - // BBC - // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 - int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; - if ( data[3] == crc0 ) { - PrintAndLog(" BCC0 :%02x - Ok", data[3]); - } - else{ - PrintAndLog(" BCC0 :%02x - crc should be %02x", data[3], crc0); - } - - int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; - if ( data[8] == crc1 ){ - PrintAndLog(" BCC1 :%02x - Ok", data[8]); - } - else{ - PrintAndLog(" BCC1 :%02x - crc should be %02x", data[8], crc1 ); - } - - PrintAndLog(" Internal :%s ", sprint_hex(data + 9, 1)); - - memcpy(datatemp, data+10, 2); - PrintAndLog(" Lock :%s - %s", sprint_hex(datatemp, 2),printBits( 2, &datatemp) ); - - PrintAndLog(" OneTimePad :%s ", sprint_hex(data + 3*4, 4)); - PrintAndLog(""); - - for (i = 0; i < pages; i++) { - switch(i){ - case 2: - //process lock bytes - lockbytes_t=data+(i*4); - lockbytes[0]=lockbytes_t[2]; - lockbytes[1]=lockbytes_t[3]; - for(int j=0; j<16; j++){ - bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); - } - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 3: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 4: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 5: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 6: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 7: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 8: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 9: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 10: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 11: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 12: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 13: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 14: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 15: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - default: - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - } - } - } - } else { - PrintAndLog("Command1 execute timeout"); - } - if (dump) fclose(fout); - return 0; -} - -int CmdHF14AMfUDump(const char *Cmd){ - int i; - uint8_t BlockNo = 0; - int Pages = 16; - uint8_t *lockbytes_t = NULL; - uint8_t lockbytes[2] = {0x00}; - bool bit[16] = {0x00}; - uint8_t datatemp[5] = {0x00}; - bool dump = true; - uint8_t isOK = 0; - uint8_t * data = NULL; - FILE *fout; - - if ((fout = fopen("dump_ultralight_data.bin","wb")) == NULL) { - PrintAndLog("Could not create file name dumpdata.bin"); - return 1; - } - PrintAndLog("Dumping Ultralight Card Data..."); - - PrintAndLog("Attempting to Read Ultralight... "); - UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; - SendCommand(&c); - UsbCommand resp; - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - isOK = resp.arg[0] & 0xff; - data = resp.d.asBytes; - PrintAndLog("isOk:%02x", isOK); - if (isOK) - for (i = 0; i < Pages; i++) { - switch(i){ - case 2: - //process lock bytes - lockbytes_t=data+(i*4); - lockbytes[0]=lockbytes_t[2]; - lockbytes[1]=lockbytes_t[3]; - for(int j=0; j<16; j++){ - bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); - } - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 3: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 4: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 5: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 6: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 7: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 8: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 9: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 10: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 11: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 12: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 13: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 14: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 15: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - default: - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - } - } - } else { - PrintAndLog("Command1 execute timeout"); - } - if (dump) fclose(fout); - return 0; -} - -// Needed to Authenticate to Ultralight C tags -void rol (uint8_t *data, const size_t len){ - uint8_t first = data[0]; - for (size_t i = 0; i < len-1; i++) { - data[i] = data[i+1]; - } - data[len-1] = first; -} - -//------------------------------------------------------------------------------- -// Ultralight C Methods -//------------------------------------------------------------------------------- - -// -// Ultralight C Authentication Demo {currently uses hard-coded key} -// -int CmdHF14AMfucAuth(const char *Cmd){ - - uint8_t blockNo = 0, keyNo=0; - uint8_t e_RndB[8] = {0x00}; - uint32_t cuid=0; - unsigned char RndARndB[16] = {0x00}; - uint8_t key[16] = {0x00}; - DES_cblock RndA, RndB; - DES_cblock iv; - DES_key_schedule ks1,ks2; - DES_cblock key1,key2; - - // - memset(iv, 0, 8); - - if (strlen(Cmd)<1) { - PrintAndLog("Usage: hf mfu auth k "); - PrintAndLog(" sample: hf mfu auth k 0"); - return 0; - } - - //Change key to user defined one - if (strchr(Cmd,'k') != 0){ - //choose a key - keyNo = param_get8(Cmd, 1); - switch(keyNo){ - case 0: - memcpy(key,key1_blnk_data,16); - break; - case 1: - memcpy(key,key2_defa_data,16); - break; - case 2: - memcpy(key,key4_nfc_data,16); - break; - case 3: - memcpy(key,key5_ones_data,16); - break; - default: - memcpy(key,key3_3des_data,16); - break; - } - }else{ - memcpy(key,key3_3des_data,16); - } - 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_MIFAREUC_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(RndB):%s", sprint_hex(data+1, 8)); - memcpy(e_RndB,data+1,8); - } - } else { - PrintAndLog("Command execute timeout"); - } - - //Do crypto magic - DES_random_key(&RndA); - DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); - PrintAndLog(" RndB:%s",sprint_hex(RndB, 8)); - PrintAndLog(" RndA:%s",sprint_hex(RndA, 8)); - rol(RndB,8); - memcpy(RndARndB,RndA,8); - memcpy(RndARndB+8,RndB,8); - PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); - DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); - PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); - - //Auth2 - UsbCommand d = {CMD_MIFAREUC_AUTH2, {cuid}}; - memcpy(d.d.asBytes,RndARndB, 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("enc(RndA'):%s", sprint_hex(data2+1, 8)); - } - - } else { - PrintAndLog("Command execute timeout"); - } - return 1; -} - -// -// Ultralight C Read Single Block -// -int CmdHF14AMfUCRdBl(const char *Cmd) -{ - uint8_t blockNo = 0; - - if (strlen(Cmd)<1) { - PrintAndLog("Usage: hf mfu ucrdbl "); - PrintAndLog(" sample: hf mfu ucrdbl 0"); - return 0; - } - - blockNo = param_get8(Cmd, 0); - if (blockNo>MAX_ULTRAC_BLOCKS){ - PrintAndLog("Error: Maximum number of readable blocks is 44 for Ultralight Cards!"); - return 1; - } - PrintAndLog("--block no:%02x", (int)blockNo); - - //Read Block - UsbCommand e = {CMD_MIFAREU_READBL, {blockNo}}; - SendCommand(&e); - UsbCommand resp_c; - if (WaitForResponseTimeout(CMD_ACK,&resp_c,1500)) { - uint8_t isOK = resp_c.arg[0] & 0xff; - uint8_t * data = resp_c.d.asBytes; - if (isOK) - PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4)); - else - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - return 0; -} - -// -// Ultralight C Read (or Dump) Card Contents -// -int CmdHF14AMfUCRdCard(const char *Cmd){ - int i; - uint8_t BlockNo = 0; - int Pages=44; - uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0x00}; - uint8_t *lockbytes_t2=NULL; - uint8_t lockbytes2[2]={0x00}; - bool bit[16]={0x00}; - bool bit2[16]={0x00}; - bool dump=false; - uint8_t datatemp[5]={0x00}; - uint8_t isOK = 0; - uint8_t * data = NULL; - FILE *fout = NULL; - - if (strchr(Cmd,'x') != 0){ - dump=true; - if ((fout = fopen("dump_ultralightc_data.bin","wb")) == NULL) { - PrintAndLog("Could not create file name dumpdata.bin"); - return 1; - } - PrintAndLog("Dumping Ultralight C Card Data..."); - } - PrintAndLog("Attempting to Read Ultralight C... "); - UsbCommand c = {CMD_MIFAREUC_READCARD, {BlockNo, Pages}}; - SendCommand(&c); - UsbCommand resp; - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - isOK = resp.arg[0] & 0xff; - data = resp.d.asBytes; - - PrintAndLog("isOk:%02x", isOK); - if (isOK) - for (i = 0; i < Pages; i++) { - switch(i){ - case 2: - //process lock bytes - lockbytes_t=data+(i*4); - lockbytes[0]=lockbytes_t[2]; - lockbytes[1]=lockbytes_t[3]; - for(int j=0; j<16; j++){ - bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); - } - //might as well read bottom lockbytes too - lockbytes_t2=data+(40*4); - lockbytes2[0]=lockbytes_t2[2]; - lockbytes2[1]=lockbytes_t2[3]; - for(int j=0; j<16; j++){ - bit2[j]=lockbytes2[j/8] & ( 1 <<(7-j%8)); - } - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 3: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 4: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 5: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 6: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 7: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 8: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 9: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 10: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 11: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 12: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 13: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 14: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 15: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 16: - case 17: - case 18: - case 19: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[6]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 20: - case 21: - case 22: - case 23: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[5]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 24: - case 25: - case 26: - case 27: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[4]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 28: - case 29: - case 30: - case 31: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[2]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 32: - case 33: - case 34: - case 35: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[1]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 36: - case 37: - case 38: - case 39: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[0]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 40: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[12]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 41: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[11]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 42: - //auth0 - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[10]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 43: - //auth1 - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[9]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - default: - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - } - } - - } else { - PrintAndLog("Command1 execute timeout"); - } - if (dump) fclose(fout); - return 0; -} - -// -// Ultralight C Dump Card Contents to file -// -int CmdHF14AMfUCDump(const char *Cmd){ - int i; - uint8_t BlockNo = 0; - int Pages=44; - uint8_t *lockbytes_t=NULL; - uint8_t lockbytes[2]={0x00}; - uint8_t *lockbytes_t2=NULL; - uint8_t lockbytes2[2]={0x00}; - bool bit[16]={0x00}; - bool bit2[16]={0x00}; - bool dump=true; - uint8_t datatemp[5]={0x00}; - - uint8_t isOK = 0; - uint8_t * data = NULL; - FILE *fout; - - if ((fout = fopen("dump_ultralightc_data.bin","wb")) == NULL) { - PrintAndLog("Could not create file name dumpdata.bin"); - return 1; - } - PrintAndLog("Dumping Ultralight C Card Data..."); - PrintAndLog("Attempting to Read Ultralight C... "); - UsbCommand c = {CMD_MIFAREU_READCARD, {BlockNo,Pages}}; - SendCommand(&c); - UsbCommand resp; - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - isOK = resp.arg[0] & 0xff; - data = resp.d.asBytes; - PrintAndLog("isOk:%02x", isOK); - if (isOK) - for (i = 0; i < Pages; i++) { - switch(i){ - case 2: - //process lock bytes - lockbytes_t=data+(i*4); - lockbytes[0]=lockbytes_t[2]; - lockbytes[1]=lockbytes_t[3]; - for(int j=0; j<16; j++){ - bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8)); - - } - //might as well read bottom lockbytes too - lockbytes_t2=data+(40*4); - lockbytes2[0]=lockbytes_t2[2]; - lockbytes2[1]=lockbytes_t2[3]; - for(int j=0; j<16; j++){ - bit2[j]=lockbytes2[j/8] & ( 1 <<(7-j%8)); - } - - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 3: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 4: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 5: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 6: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 7: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 8: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 9: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 10: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 11: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 12: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 13: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 14: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 15: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 16: - case 17: - case 18: - case 19: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[6]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 20: - case 21: - case 22: - case 23: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[5]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 24: - case 25: - case 26: - case 27: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[4]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 28: - case 29: - case 30: - case 31: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[2]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 32: - case 33: - case 34: - case 35: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[1]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 36: - case 37: - case 38: - case 39: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[0]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 40: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[12]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 41: - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[11]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 42: - //auth0 - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[10]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - case 43: - //auth1 - PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit2[9]); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - default: - PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4)); - memcpy(datatemp,data + i * 4,4); - if (dump) fwrite ( datatemp, 1, 4, fout ); - break; - } - } - - } else { - PrintAndLog("Command1 execute timeout"); - } - if (dump) fclose(fout); - return 0; -} - -// -// Mifare Ultralight C Write Single Block -// -int CmdHF14AMfUCWrBl(const char *Cmd){ - - uint8_t blockNo = 0; - bool chinese_card = 0; - uint8_t bldata[16] = {0x00}; - UsbCommand resp; - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf mfu ucwrbl [w]"); - PrintAndLog(" sample: hf mfu uwrbl 0 01020304"); - return 0; - } - blockNo = param_get8(Cmd, 0); - if (blockNo>(MAX_ULTRAC_BLOCKS+4)){ - PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight Cards!"); - return 1; - } - if (param_gethex(Cmd, 1, bldata, 8)) { - PrintAndLog("Block data must include 8 HEX symbols"); - return 1; - } - if (strchr(Cmd,'w') != 0) { - chinese_card=1; - } - switch(blockNo){ - case 0: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 1: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 2: - if (!chinese_card){ - PrintAndLog("Access Denied"); - }else{ - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(c.d.asBytes, bldata, 4); - SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - } - break; - case 3: - PrintAndLog("--specialblock no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(d.d.asBytes,bldata, 4); - SendCommand(&d); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - break; - default: - PrintAndLog("--block no:%02x", blockNo); - PrintAndLog("--data: %s", sprint_hex(bldata, 4)); - UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(e.d.asBytes,bldata, 4); - SendCommand(&e); - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - break; - } - return 0; -} - -//------------------------------------ -// Menu Stuff -//------------------------------------ -static command_t CommandTable[] = -{ - {"help", CmdHelp, 1,"This help"}, - {"dbg", CmdHF14AMfDbg, 0,"Set default debug mode"}, - {"urdbl", CmdHF14AMfURdBl, 0,"Read MIFARE Ultralight block"}, - {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"}, - {"udump", CmdHF14AMfUDump, 0,"Dump MIFARE Ultralight tag to binary file"}, - {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"}, - {"ucrdbl", CmdHF14AMfUCRdBl, 0,"Read MIFARE Ultralight C block"}, - {"ucrdcard",CmdHF14AMfUCRdCard, 0,"Read MIFARE Ultralight C Card"}, - {"ucdump", CmdHF14AMfUCDump, 0,"Dump MIFARE Ultralight C tag to binary file"}, - {"ucwrbl", CmdHF14AMfUCWrBl, 0,"Write MIFARE Ultralight C block"}, - {"auth", CmdHF14AMfucAuth, 0,"Ultralight C Authentication"}, - {NULL, NULL, 0, NULL} -}; - -int CmdHFMFUltra(const char *Cmd){ - WaitForResponseTimeout(CMD_ACK,NULL,100); - CmdsParse(CommandTable, Cmd); - return 0; -} - -int CmdHelp(const char *Cmd){ - CmdsHelp(CommandTable); - return 0; -} \ No newline at end of file diff --git a/client/cmdhfmfu.h b/client/cmdhfmfu.h deleted file mode 100644 index 20f25d1d..00000000 --- a/client/cmdhfmfu.h +++ /dev/null @@ -1,16 +0,0 @@ -#include "cmdhfmf.h" - -//standard ultralight -int CmdHF14AMfUWrBl(const char *Cmd); -int CmdHF14AMfURdBl(const char *Cmd); -int CmdHF14AMfURdCard(const char *Cmd); -int CmdHF14AMfUDump(const char *Cmd); -//Crypto Cards -int CmdHF14AMfUCRdBl(const char *Cmd); -int CmdHF14AMfUCRdCard(const char *Cmd); -int CmdHF14AMfUCDump(const char *Cmd); -int CmdHF14AMfucAuth(const char *Cmd); -void rol (uint8_t *data, const size_t len); - -//general stuff -int CmdHFMFUltra(const char *Cmd); diff --git a/client/cmdhw.c b/client/cmdhw.c index 642f63c5..443973b8 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -13,11 +13,12 @@ #include #include #include "ui.h" +//#include "proxusb.h" #include "proxmark3.h" #include "cmdparser.h" -#include "cmddata.h" #include "cmdhw.h" #include "cmdmain.h" +#include "cmddata.h" /* low-level hardware control */ @@ -417,7 +418,7 @@ static command_t CommandTable[] = {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"}, {"setmux", CmdSetMux, 0, " -- Set the ADC mux to a specific value"}, {"tune", CmdTune, 0, "Measure antenna tuning"}, - {"version", CmdVersion, 0, "Show version information about the connected Proxmark"}, + {"version", CmdVersion, 0, "Show version inforation about the connected Proxmark"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlf.c b/client/cmdlf.c index e38eee51..18bcf747 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -20,7 +20,6 @@ #include "cmdmain.h" #include "cmddata.h" #include "cmdlf.h" -#include "cmdlfawid26.h" #include "cmdlfhid.h" #include "cmdlfti.h" #include "cmdlfem4x.h" @@ -48,377 +47,374 @@ int CmdLFCommandRead(const char *Cmd) 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; - } +#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; + 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); - } + 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); - } - } + 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; - } - } + int j; + for (j = 0; j < 32; j++) { + GraphBuffer[i++] = phase; + phase = !phase; + } + } - RepaintGraphWindow(); - return 0; + 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; - } - } + 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); + 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; - } + // 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; - } - } + 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; - } + 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]; - } - } + // Inverting signal if needed + if (first == 1) { + for (i = start; i < rawbit; i++) { + rawbits[i] = !rawbits[i]; + } + } - // Dumping UID + // Dumping UID uint8_t bits[224] = {0x00}; char showbits[225] = {0x00}; - int bit; - i = start; - int times = 0; + 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; - } + 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; + //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; - } + 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); + PrintAndLog("Occurrences: %d (expected %d)", times, (rawbit - start) / uidlen); - // Remodulating for tag cloning + // 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; - } - } + 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; + 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; + 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; + 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; - } + 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; + SendCommand(&c); + return 0; } int CmdLFRead(const char *Cmd) { - UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K}; + UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K}; - // 'h' means higher-low-frequency, 134 kHz - if(*Cmd == 'h') { - c.arg[0] = 1; - } else if (*Cmd == '\0') { - c.arg[0] = 0; - } else if (sscanf(Cmd, "%"lli, &c.arg[0]) != 1) { + // 'h' means higher-low-frequency, 134 kHz + if(*Cmd == 'h') { + c.arg[0] = 1; + } else if (*Cmd == '\0') { + c.arg[0] = 0; + } else if (sscanf(Cmd, "%"lli, &c.arg[0]) != 1) { PrintAndLog("Samples 1: 'lf read'"); PrintAndLog(" 2: 'lf read h'"); PrintAndLog(" 3: 'lf read '"); - return 0; - } - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - - CmdSamples(""); - ShowGraphWindow(); - return 0; + return 0; + } + SendCommand(&c); + WaitForResponse(CMD_ACK,NULL); + return 0; } static void ChkBitstream(const char *str) { - int i; + int i; - /* convert to bitstream if necessary */ - for (i = 0; i < (int)(GraphTraceLen / 2); i++){ - if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) { - CmdBitstream(str); - break; - } - } + /* convert to bitstream if necessary */ + for (i = 0; i < (int)(GraphTraceLen / 2); i++) + { + if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) + { + CmdBitstream(str); + break; + } + } } int CmdLFSim(const char *Cmd) { - int i,j; - static int gap; + int i; + static int gap; - sscanf(Cmd, "%i", &gap); + sscanf(Cmd, "%i", &gap); - /* convert to bitstream if necessary */ - ChkBitstream(Cmd); + /* convert to bitstream if necessary */ + ChkBitstream(Cmd); - 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}}; + PrintAndLog("Sending data, please wait..."); + for (i = 0; i < GraphTraceLen; i += 48) { + UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}}; + int j; + for (j = 0; j < 48; j++) { + c.d.asBytes[j] = GraphBuffer[i+j]; + } + SendCommand(&c); + WaitForResponse(CMD_ACK,NULL); + } - 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; + PrintAndLog("Starting simulator..."); + UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}}; + SendCommand(&c); + return 0; } int CmdLFSimBidir(const char *Cmd) @@ -434,57 +430,48 @@ int CmdLFSimBidir(const char *Cmd) /* simulate an LF Manchester encoded tag with specified bitstream, clock rate and inter-id gap */ int CmdLFSimManchester(const char *Cmd) { - static int clock, gap; - static char data[1024], gapstring[8]; + static int clock, gap; + static char data[1024], gapstring[8]; - sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap); + sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap); - ClearGraph(0); + ClearGraph(0); - for (int i = 0; i < strlen(data) ; ++i) - AppendGraph(0, clock, data[i]- '0'); + for (int i = 0; i < strlen(data) ; ++i) + AppendGraph(0, clock, data[i]- '0'); - CmdManchesterMod(""); + CmdManchesterMod(""); - RepaintGraphWindow(); + RepaintGraphWindow(); - sprintf(&gapstring[0], "%i", gap); - CmdLFSim(gapstring); - return 0; + sprintf(&gapstring[0], "%i", gap); + CmdLFSim(gapstring); + return 0; } int CmdLFSnoop(const char *Cmd) { - UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES}; + UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES}; - // 'h' means higher-low-frequency, 134 kHz - c.arg[0] = 0; - c.arg[1] = -1; + // 'h' means higher-low-frequency, 134 kHz + c.arg[0] = 0; + c.arg[1] = -1; if (*Cmd == 'l') { - sscanf(Cmd, "l %"lli, &c.arg[1]); - } else if (*Cmd == 'h') { - c.arg[0] = 1; - sscanf(Cmd, "h %"lli, &c.arg[1]); - } else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) { + sscanf(Cmd, "l %"lli, &c.arg[1]); + } else if(*Cmd == 'h') { + c.arg[0] = 1; + sscanf(Cmd, "h %"lli, &c.arg[1]); + } else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) { PrintAndLog("usage 1: snoop"); PrintAndLog(" 2: snoop {l,h} [trigger threshold]"); PrintAndLog(" 3: snoop [trigger threshold]"); - return 0; - } + return 0; + } - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - - #define BUFF_SIZE 8000 - uint8_t data[BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,BUFF_SIZE,0); - WaitForResponseTimeout(CMD_ACK,NULL, 1500); - - SetGraphBuf(data, BUFF_SIZE); - - return 0; + SendCommand(&c); + WaitForResponse(CMD_ACK,NULL); + return 0; } int CmdVchDemod(const char *Cmd) @@ -566,81 +553,49 @@ int CmdVchDemod(const char *Cmd) //by marshmellow int CmdLFfind(const char *Cmd) { - int ans = 0; - char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: lf search <0|1>"); - PrintAndLog(" , if not set, try reading data from tag."); - PrintAndLog(""); - PrintAndLog(" sample: lf search"); - PrintAndLog(" : lf search 1"); - return 0; - } - - if (!offline || (cmdp != '1') ){ - ans = CmdLFRead(""); - } else if (GraphTraceLen < 1000) { - PrintAndLog("Data in Graphbuffer was too small."); - return 0; - } - - PrintAndLog("Checking for known tags:"); - - ans = Cmdaskmandemod(""); - PrintAndLog("ASK_MAN: %s", (ans) ? "YES":"NO" ); - - ans = CmdFSKdemodHID(""); - PrintAndLog("HID: %s", (ans) ? "YES":"NO" ); - - ans = CmdFSKdemodIO(""); - PrintAndLog("IO prox: %s", (ans) ? "YES":"NO" ); - - ans = CmdIndalaDemod(""); - PrintAndLog("Indala (64): %s", (ans) ? "YES":"NO" ); - - ans = CmdIndalaDemod("224"); - PrintAndLog("Indala (224): %s", (ans) ? "YES":"NO" ); - - // ans = CmdVchDemod(""); - // PrintAndLog("VeriChip: %s", (ans) ? "YES":"NO" ); - - // ans = CmdFlexdemod(""); - // PrintAndLog("FlexPass: %s", (ans) ? "YES":"NO" ); - - if (!ans) - PrintAndLog("No Known Tags Found!\n"); - - return 0; + int ans=0; + if (!offline){ + ans=CmdLFRead(""); + ans=CmdSamples("20000"); + } + if (GraphTraceLen<1000) return 0; + PrintAndLog("Checking for known tags:"); + ans=Cmdaskmandemod(""); + if (ans>0) return 1; + ans=CmdFSKdemodHID(""); + if (ans>0) return 1; + ans=CmdFSKdemodIO(""); + if (ans>0) return 1; + //add psk and indala + ans=CmdIndalaDemod(""); + if (ans>0) return 1; + ans=CmdIndalaDemod("224"); + if (ans>0) return 1; + PrintAndLog("No Known Tags Found!\n"); + return 0; } static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"cmdread", CmdLFCommandRead, 0, " <'0' period> <'1' period> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)"}, - + {"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"}, {"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, " ['l']-- Clone Indala to T55x7 (UID in HEX)(option 'l' for 224 UID"}, - {"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"}, - - + {"indalaclone", CmdIndalaClone, 0, " ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"}, {"read", CmdLFRead, 0, "['h' or ] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134, alternatively: f=12MHz/(divisor+1))"}, {"search", CmdLFfind, 1, "Read and Search for valid known tag (in offline mode it you can load first then search)"}, {"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"}, {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, {"simman", CmdLFSimManchester, 0, " [GAP] Simulate arbitrary Manchester LF tag"}, {"snoop", CmdLFSnoop, 0, "['l'|'h'|] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"}, - - {"awid26", CmdLFAWID26, 1, "{ AWID26 tags }"}, - {"em4x", CmdLFEM4X, 1, "{ EM4X tags }"}, - {"hid", CmdLFHID, 1, "{ HID tags }"}, - {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders }"}, - {"io", CmdLFIO, 1, "{ ioProx tags }"}, - {"pcf7931", CmdLFPCF7931, 1, "{ PCF7931 tags }"}, - {"ti", CmdLFTI, 1, "{ TI tags }"}, - {"t55xx", CmdLFT55XX, 1, "{ T55xx tags }"}, - + {"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} }; diff --git a/client/cmdlfawid26.c b/client/cmdlfawid26.c deleted file mode 100644 index 48e599db..00000000 --- a/client/cmdlfawid26.c +++ /dev/null @@ -1,208 +0,0 @@ -//----------------------------------------------------------------------------- -// -// 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 -#include -#include -#include -#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 "); - 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, " -- 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 deleted file mode 100644 index 7c23d567..00000000 --- a/client/cmdlfawid26.h +++ /dev/null @@ -1,18 +0,0 @@ -//----------------------------------------------------------------------------- -// -// 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 diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index a0cd87ca..32a0ff7c 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -1,4 +1,4 @@ - //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh // // This code is licensed to you under the terms of the GNU GPL, version 2 or, @@ -13,18 +13,12 @@ #include #include "proxmark3.h" #include "ui.h" +#include "util.h" #include "graph.h" -#include "cmdmain.h" #include "cmdparser.h" #include "cmddata.h" #include "cmdlf.h" #include "cmdlfem4x.h" -#include "util.h" -#include "data.h" -#define LF_TRACE_BUFF_SIZE 12000 -#define LF_BITSSTREAM_LEN 1000 - -char *global_em410xId; static int CmdHelp(const char *Cmd); @@ -32,10 +26,10 @@ int CmdEMdemodASK(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); int findone = (cmdp == '1') ? 1 : 0; - UsbCommand c = { CMD_EM410X_DEMOD }; - c.arg[0] = findone; - SendCommand(&c); - return 0; + UsbCommand c={CMD_EM410X_DEMOD}; + c.arg[0]=findone; + SendCommand(&c); + return 0; } /* Read the ID of an EM410x tag. @@ -56,19 +50,23 @@ int CmdEM410xRead(const char *Cmd) uint8_t BitStream[MAX_GRAPH_TRACE_LEN]; high = low = 0; - // get clock - clock = GetClock(Cmd, 0); - - // Detect high and lows and clock - DetectHighLowInGraph( &high, &low, TRUE); + /* Detect high and lows and clock */ + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } - PrintAndLog("NUMNUM"); - - // parity for our 4 columns + /* get clock */ + clock = GetClock(Cmd, high, 0); + + /* parity for our 4 columns */ parity[0] = parity[1] = parity[2] = parity[3] = 0; header = rows = 0; - // manchester demodulate + /* manchester demodulate */ bit = bit2idx = 0; for (i = 0; i < (int)(GraphTraceLen / clock); i++) { @@ -79,9 +77,9 @@ int CmdEM410xRead(const char *Cmd) /* Find out if we hit both high and low peaks */ for (j = 0; j < clock; j++) { - if (GraphBuffer[(i * clock) + j] >= high) + if (GraphBuffer[(i * clock) + j] == high) hithigh = 1; - else if (GraphBuffer[(i * clock) + j] <= low) + else if (GraphBuffer[(i * clock) + j] == low) hitlow = 1; /* it doesn't count if it's the first part of our read @@ -101,10 +99,10 @@ int CmdEM410xRead(const char *Cmd) BitStream[bit2idx++] = bit; } - + retest: /* We go till 5 before the graph ends because we'll get that far below */ - for (i = 0; i < bit2idx - 5; i++) + for (i = 1; i < bit2idx - 5; i++) { /* Step 2: We have our header but need our tag ID */ if (header == 9 && rows < 10) @@ -133,7 +131,7 @@ retest: PrintAndLog("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i); /* Start back rows * 5 + 9 header bits, -1 to not start at same place */ - i -= 9 + (5 * rows) -5; + i -= 9 + (5 * rows) - 5; rows = header = 0; } @@ -151,8 +149,6 @@ retest: PrintAndLog("EM410x Tag ID: %s", id); PrintAndLog("Unique Tag ID: %s", id2); - global_em410xId = id; - /* Stop any loops */ return 1; } @@ -181,14 +177,12 @@ retest: } /* if we've already retested after flipping bits, return */ - if (retested++){ - PrintAndLog("Failed to decode"); - return 0; - } + if (retested++) + return 0; /* if this didn't work, try flipping bits */ - for (i = 0; i < bit2idx; i++) - BitStream[i] ^= 1; + for (i = 0; i < bit2idx; i++) + BitStream[i] ^= 1; goto retest; } @@ -202,7 +196,7 @@ retest: * 0 <-- stop bit, end of tag */ int CmdEM410xSim(const char *Cmd) -{ +{ int i, n, j, binary[4], parity[4]; char cmdp = param_getchar(Cmd, 0); @@ -222,13 +216,13 @@ int CmdEM410xSim(const char *Cmd) PrintAndLog("Starting simulating UID %02X%02X%02X%02X%02X", uid[0],uid[1],uid[2],uid[3],uid[4]); PrintAndLog("Press pm3-button to about simulation"); - + /* clock is 64 in EM410x tags */ int clock = 64; /* clear our graph */ ClearGraph(0); - + /* write 9 start bits */ for (i = 0; i < 9; i++) AppendGraph(0, clock, 1); @@ -264,7 +258,7 @@ int CmdEM410xSim(const char *Cmd) AppendGraph(0, clock, parity[2]); AppendGraph(0, clock, parity[3]); - /* stop bit */ + /* stop bit */ AppendGraph(1, clock, 0); CmdLFSim("240"); //240 start_gap. @@ -285,30 +279,20 @@ int CmdEM410xWatch(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); int read_h = (cmdp == 'h'); - do - { + do { if (ukbhit()) { printf("\naborted via keyboard!\n"); break; } CmdLFRead(read_h ? "h" : ""); - CmdSamples("6000"); - + CmdSamples("6000"); } while ( !CmdEM410xRead("") ); return 0; } -int CmdEM410xWatchnSpoof(const char *Cmd) -{ - CmdEM410xWatch(Cmd); - PrintAndLog("# Replaying : %s",global_em410xId); - CmdEM410xSim(global_em410xId); - return 0; -} - /* Read the transmitted data of an EM4x50 tag * Format: * @@ -523,80 +507,48 @@ int CmdEM410xWrite(const char *Cmd) int CmdReadWord(const char *Cmd) { - int Word = -1; //default to invalid word - UsbCommand c; + int Word = 16; //default to invalid word + UsbCommand c; - sscanf(Cmd, "%d", &Word); + sscanf(Cmd, "%d", &Word); - if ( (Word > 15) | (Word < 0) ) { - PrintAndLog("Word must be between 0 and 15"); - return 1; - } + if (Word > 15) { + PrintAndLog("Word must be between 0 and 15"); + return 1; + } - PrintAndLog("Reading word %d", Word); + PrintAndLog("Reading word %d", Word); - c.cmd = CMD_EM4X_READ_WORD; - c.d.asBytes[0] = 0x0; //Normal mode - c.arg[0] = 0; - c.arg[1] = Word; - c.arg[2] = 0; - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); - - uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); - - for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]); - } - GraphTraceLen = LF_TRACE_BUFF_SIZE; - - uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; - uint8_t * bitstream = bits; - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream,LF_BITSSTREAM_LEN); - RepaintGraphWindow(); + c.cmd = CMD_EM4X_READ_WORD; + c.d.asBytes[0] = 0x0; //Normal mode + c.arg[0] = 0; + c.arg[1] = Word; + c.arg[2] = 0; + SendCommand(&c); return 0; } int CmdReadWordPWD(const char *Cmd) { - int Word = -1; //default to invalid word - int Password = 0xFFFFFFFF; //default to blank password - UsbCommand c; - - sscanf(Cmd, "%d %x", &Word, &Password); - - if ( (Word > 15) | (Word < 0) ) { - PrintAndLog("Word must be between 0 and 15"); - return 1; - } + int Word = 16; //default to invalid word + int Password = 0xFFFFFFFF; //default to blank password + UsbCommand c; - PrintAndLog("Reading word %d with password %08X", Word, Password); - - c.cmd = CMD_EM4X_READ_WORD; - c.d.asBytes[0] = 0x1; //Password mode - c.arg[0] = 0; - c.arg[1] = Word; - c.arg[2] = Password; - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); - - uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); - - for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]); - } - GraphTraceLen = LF_TRACE_BUFF_SIZE; - - uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; - uint8_t * bitstream = bits; - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); - RepaintGraphWindow(); + sscanf(Cmd, "%d %x", &Word, &Password); + + if (Word > 15) { + PrintAndLog("Word must be between 0 and 15"); + return 1; + } + + PrintAndLog("Reading word %d with password %08X", Word, Password); + + c.cmd = CMD_EM4X_READ_WORD; + c.d.asBytes[0] = 0x1; //Password mode + c.arg[0] = 0; + c.arg[1] = Word; + c.arg[2] = Password; + SendCommand(&c); return 0; } @@ -613,7 +565,7 @@ int CmdWriteWord(const char *Cmd) return 1; } - PrintAndLog("Writing word %d with data %08X", Word, Data); + PrintAndLog("Writting word %d with data %08X", Word, Data); c.cmd = CMD_EM4X_WRITE_WORD; c.d.asBytes[0] = 0x0; //Normal mode @@ -626,7 +578,7 @@ int CmdWriteWord(const char *Cmd) int CmdWriteWordPWD(const char *Cmd) { - int Word = 16; //default to invalid word + int Word = 8; //default to invalid word int Data = 0xFFFFFFFF; //default to blank data int Password = 0xFFFFFFFF; //default to blank password UsbCommand c; @@ -638,7 +590,7 @@ int CmdWriteWordPWD(const char *Cmd) return 1; } - PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password); + PrintAndLog("Writting word %d with data %08X and password %08X", Word, Data, Password); c.cmd = CMD_EM4X_WRITE_WORD; c.d.asBytes[0] = 0x1; //Password mode @@ -649,283 +601,24 @@ int CmdWriteWordPWD(const char *Cmd) return 0; } + + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"410xdemod", CmdEMdemodASK, 0, "[clock rate] -- Extract ID from EM410x tag"}, - {"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, - {"410xsim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, - {"replay", MWRem4xReplay, 0, "Watches for tag and simulates manchester encoded em4x tag"}, - {"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, - {"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, - {"410xwrite", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, - {"4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, - {"rd", CmdReadWord, 1, " -- Read EM4xxx word data"}, - {"rdpwd", CmdReadWordPWD, 1, " -- Read EM4xxx word data in password mode "}, - {"wr", CmdWriteWord, 1, " -- Write EM4xxx word data"}, - {"wrpwd", CmdWriteWordPWD, 1, " -- Write EM4xxx word data in password mode"}, + {"em410xdemod", CmdEMdemodASK, 0, "[clock rate] -- Extract ID from EM410x tag"}, + {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, + {"em410xsim", CmdEM410xSim, 0, " -- Simulate EM410x tag"}, + {"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, + {"em410xwrite", CmdEM410xWrite, 1, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, + {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, + {"readword", CmdReadWord, 1, " -- Read EM4xxx word data"}, + {"readwordPWD", CmdReadWordPWD, 1, " -- Read EM4xxx word data in password mode"}, + {"writeword", CmdWriteWord, 1, " -- Write EM4xxx word data"}, + {"writewordPWD", CmdWriteWordPWD, 1, " -- Write EM4xxx word data in password mode"}, {NULL, NULL, 0, NULL} }; - -//Confirms the parity of a bitstream as well as obtaining the data (TagID) from within the appropriate memory space. -//Arguments: -// Pointer to a string containing the desired bitsream -// Pointer to a string that will receive the decoded tag ID -// Length of the bitsream pointed at in the first argument, char* _strBitStream -//Retuns: -//1 Parity confirmed -//0 Parity not confirmed -int ConfirmEm410xTagParity( char* _strBitStream, char* pID, int LengthOfBitstream ) -{ - int i = 0; - int rows = 0; - int Parity[4] = {0x00}; - char ID[11] = {0x00}; - int k = 0; - int BitStream[70] = {0x00}; - int counter = 0; - //prepare variables - for ( i = 0; i <= LengthOfBitstream; i++) - { - if (_strBitStream[i] == '1') - { - k =1; - memcpy(&BitStream[i], &k,4); - } - else if (_strBitStream[i] == '0') - { - k = 0; - memcpy(&BitStream[i], &k,4); - } - } - while ( counter < 2 ) - { - //set/reset variables and counters - memset(ID,0x00,sizeof(ID)); - memset(Parity,0x00,sizeof(Parity)); - rows = 0; - for ( i = 9; i <= LengthOfBitstream; i++) - { - if ( rows < 10 ) - { - if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4]) - { - sprintf(ID+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3])); - rows++; - /* Keep parity info and move four bits ahead*/ - Parity[0] ^= BitStream[i]; - Parity[1] ^= BitStream[i+1]; - Parity[2] ^= BitStream[i+2]; - Parity[3] ^= BitStream[i+3]; - i += 4; - } - } - if ( rows == 10 ) - { - if ( BitStream[i] == Parity[0] && BitStream[i+1] == Parity[1] && - BitStream[i+2] == Parity[2] && BitStream[i+3] == Parity[3] && - BitStream[i+4] == 0) - { - memcpy(pID,ID,strlen(ID)); - return 1; - } - } - } - printf("[PARITY ->]Failed. Flipping Bits, and rechecking parity for bitstream:\n[PARITY ->]"); - for (k = 0; k < LengthOfBitstream; k++) - { - BitStream[k] ^= 1; - printf("%i", BitStream[k]); - } - puts(" "); - counter++; - } - return 0; -} -//Reads and demodulates an em410x RFID tag. It further allows slight modification to the decoded bitstream -//Once a suitable bitstream has been identified, and if needed, modified, it is replayed. Allowing emulation of the -//"stolen" rfid tag. -//No meaningful returns or arguments. -int MWRem4xReplay(const char* Cmd) -{ - // //header traces - // static char ArrayTraceZero[] = { '0','0','0','0','0','0','0','0','0' }; - // static char ArrayTraceOne[] = { '1','1','1','1','1','1','1','1','1' }; - // //local string variables - // char strClockRate[10] = {0x00}; - // char strAnswer[4] = {0x00}; - // char strTempBufferMini[2] = {0x00}; - // //our outbound bit-stream - // char strSimulateBitStream[65] = {0x00}; - // //integers - // int iClockRate = 0; - // int needle = 0; - // int j = 0; - // int iFirstHeaderOffset = 0x00000000; - // int numManchesterDemodBits=0; - // //boolean values - // bool bInverted = false; - // //pointers to strings. memory will be allocated. - // char* pstrInvertBitStream = 0x00000000; - // char* pTempBuffer = 0x00000000; - // char* pID = 0x00000000; - // char* strBitStreamBuffer = 0x00000000; - - - // puts("###################################"); - // puts("#### Em4x Replay ##"); - // puts("#### R.A.M. June 2013 ##"); - // puts("###################################"); - // //initialize - // CmdLFRead(""); - // //Collect ourselves 10,000 samples - // CmdSamples("10000"); - // puts("[->]preforming ASK demodulation\n"); - // //demodulate ask - // Cmdaskdemod("0"); - // iClockRate = DetectClock(0); - // sprintf(strClockRate, "%i\n",iClockRate); - // printf("[->]Detected ClockRate: %s\n", strClockRate); - - // //If detected clock rate is something completely unreasonable, dont go ahead - // if ( iClockRate < 0xFFFE ) - // { - // pTempBuffer = (char*)malloc(MAX_GRAPH_TRACE_LEN); - // if (pTempBuffer == 0x00000000) - // return 0; - // memset(pTempBuffer,0x00,MAX_GRAPH_TRACE_LEN); - // //Preform manchester de-modulation and display in a single line. - // numManchesterDemodBits = CmdManchesterDemod( strClockRate ); - // //note: numManchesterDemodBits is set above in CmdManchesterDemod() - // if ( numManchesterDemodBits == 0 ) - // return 0; - // strBitStreamBuffer = malloc(numManchesterDemodBits+1); - // if ( strBitStreamBuffer == 0x00000000 ) - // return 0; - // memset(strBitStreamBuffer, 0x00, (numManchesterDemodBits+1)); - // //fill strBitStreamBuffer with demodulated, string formatted bits. - // for ( j = 0; j <= numManchesterDemodBits; j++ ) - // { - // sprintf(strTempBufferMini, "%i",BitStream[j]); - // strcat(strBitStreamBuffer,strTempBufferMini); - // } - // printf("[->]Demodulated Bitstream: \n%s\n", strBitStreamBuffer); - // //Reset counter and select most probable bit stream - // j = 0; - // while ( j < numManchesterDemodBits ) - // { - // memset(strSimulateBitStream,0x00,64); - // //search for header of nine (9) 0's : 000000000 or nine (9) 1's : 1111 1111 1 - // if ( ( strncmp(strBitStreamBuffer+j, ArrayTraceZero, sizeof(ArrayTraceZero)) == 0 ) || - // ( strncmp(strBitStreamBuffer+j, ArrayTraceOne, sizeof(ArrayTraceOne)) == 0 ) ) - // { - // iFirstHeaderOffset = j; - // memcpy(strSimulateBitStream, strBitStreamBuffer+j,64); - // printf("[->]Offset of Header"); - // if ( strncmp(strBitStreamBuffer+iFirstHeaderOffset, "0", 1) == 0 ) - // printf("'%s'", ArrayTraceZero ); - // else - // printf("'%s'", ArrayTraceOne ); - // printf(": %i\nHighlighted string : %s\n",iFirstHeaderOffset,strSimulateBitStream); - // //allow us to escape loop or choose another frame - // puts("[<-]Are we happy with this sample? [Y]es/[N]o"); - // gets(strAnswer); - // if ( ( strncmp(strAnswer,"y",1) == 0 ) || ( strncmp(strAnswer,"Y",1) == 0 ) ) - // { - // j = numManchesterDemodBits+1; - // break; - // } - // } - // j++; - // } - // } - // else return 0; - - // //Do we want the buffer inverted? - // memset(strAnswer, 0x00, sizeof(strAnswer)); - // printf("[<-]Do you wish to invert the highlighted bitstream? [Y]es/[N]o\n"); - // gets(strAnswer); - // if ( ( strncmp("y", strAnswer,1) == 0 ) || ( strncmp("Y", strAnswer, 1 ) == 0 ) ) - // { - // //allocate heap memory - // pstrInvertBitStream = (char*)malloc(numManchesterDemodBits); - // if ( pstrInvertBitStream != 0x00000000 ) - // { - // memset(pstrInvertBitStream,0x00,numManchesterDemodBits); - // bInverted = true; - // //Invert Bitstream - // for ( needle = 0; needle <= numManchesterDemodBits; needle++ ) - // { - // if (strSimulateBitStream[needle] == '0') - // strcat(pstrInvertBitStream,"1"); - // else if (strSimulateBitStream[needle] == '1') - // strcat(pstrInvertBitStream,"0"); - // } - // printf("[->]Inverted bitstream: %s\n", pstrInvertBitStream); - // } - // } - // //Confirm parity of selected string - // pID = (char*)malloc(11); - // if (pID != 0x00000000) - // { - // memset(pID, 0x00, 11); - // if (ConfirmEm410xTagParity(strSimulateBitStream,pID, 64) == 1) - // { - // printf("[->]Parity confirmed for selected bitstream!\n"); - // printf("[->]Tag ID was detected as: [hex]:%s\n",pID ); - // } - // else - // printf("[->]Parity check failed for the selected bitstream!\n"); - // } - - // //Spoof - // memset(strAnswer, 0x00, sizeof(strAnswer)); - // printf("[<-]Do you wish to continue with the EM4x simulation? [Y]es/[N]o\n"); - // gets(strAnswer); - // if ( ( strncmp(strAnswer,"y",1) == 0 ) || ( strncmp(strAnswer,"Y",1) == 0 ) ) - // { - // strcat(pTempBuffer, strClockRate); - // strcat(pTempBuffer, " "); - // if (bInverted == true) - // strcat(pTempBuffer,pstrInvertBitStream); - // if (bInverted == false) - // strcat(pTempBuffer,strSimulateBitStream); - // //inform the user - // puts("[->]Starting simulation now: \n"); - // //Simulate tag with prepared buffer. - // CmdLFSimManchester(pTempBuffer); - // } - // else if ( ( strcmp("n", strAnswer) == 0 ) || ( strcmp("N", strAnswer ) == 0 ) ) - // printf("[->]Exiting procedure now...\n"); - // else - // printf("[->]Erroneous selection\nExiting procedure now....\n"); - - // //Clean up -- Exit function - // //clear memory, then release pointer. - // if ( pstrInvertBitStream != 0x00000000 ) - // { - // memset(pstrInvertBitStream,0x00,numManchesterDemodBits); - // free(pstrInvertBitStream); - // } - // if ( pTempBuffer != 0x00000000 ) - // { - // memset(pTempBuffer,0x00,MAX_GRAPH_TRACE_LEN); - // free(pTempBuffer); - // } - // if ( pID != 0x00000000 ) - // { - // memset(pID,0x00,11); - // free(pID); - // } - // if ( strBitStreamBuffer != 0x00000000 ) - // { - // memset(strBitStreamBuffer,0x00,numManchesterDemodBits); - // free(strBitStreamBuffer); - // } - return 0; -} - int CmdLFEM4X(const char *Cmd) { CmdsParse(CommandTable, Cmd); diff --git a/client/cmdlfem4x.h b/client/cmdlfem4x.h index 2282f64e..6363e347 100644 --- a/client/cmdlfem4x.h +++ b/client/cmdlfem4x.h @@ -22,6 +22,5 @@ int CmdReadWord(const char *Cmd); int CmdReadWordPWD(const char *Cmd); int CmdWriteWord(const char *Cmd); int CmdWriteWordPWD(const char *Cmd); -int MWRem4xReplay(const char* Cmd); #endif diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 93d06406..c6d54e78 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -39,12 +39,12 @@ int CmdHIDDemod(const char *Cmd) int CmdHIDDemodFSK(const char *Cmd) { - int findone = 0; + int findone=0; if(Cmd[0]=='1') findone=1; - UsbCommand c = {CMD_HID_DEMOD_FSK}; - c.arg[0]=findone; - SendCommand(&c); - return 0; + UsbCommand c={CMD_HID_DEMOD_FSK}; + c.arg[0]=findone; + SendCommand(&c); + return 0; } int CmdHIDSim(const char *Cmd) diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 74578eea..ab4a2609 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -15,9 +15,9 @@ #include "proxmark3.h" #include "ui.h" #include "cmdparser.h" -#include "../include/common.h" +#include "common.h" #include "util.h" -#include "../include/hitag2.h" +#include "hitag2.h" #include "sleep.h" #include "cmdmain.h" @@ -29,7 +29,7 @@ size_t nbytes(size_t nbits) { int CmdLFHitagList(const char *Cmd) { - uint8_t got[TRACE_BUFFER_SIZE]; + uint8_t got[3000]; GetFromBigBuf(got,sizeof(got),0); WaitForResponse(CMD_ACK,NULL); @@ -39,25 +39,11 @@ int CmdLFHitagList(const char *Cmd) int i = 0; int prev = -1; - int len = strlen(Cmd); - char filename[FILE_PATH_SIZE] = { 0x00 }; - FILE* pf = NULL; - - if (len > FILE_PATH_SIZE) - len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); - - if (strlen(filename) > 0) { - if ((pf = fopen(filename,"wb")) == NULL) { - PrintAndLog("Error: Could not open file [%s]",filename); - return 1; - } - } - for (;;) { - - if(i >= TRACE_BUFFER_SIZE) { break; } + if(i >= 1900) { + break; + } bool isResponse; int timestamp = *((uint32_t *)(got+i)); @@ -82,7 +68,9 @@ int CmdLFHitagList(const char *Cmd) if (len > 100) { break; } - if (i + len >= TRACE_BUFFER_SIZE) { break;} + if (i + len >= 1900) { + break; + } uint8_t *frame = (got+i+9); @@ -115,23 +103,19 @@ int CmdLFHitagList(const char *Cmd) line); - if (pf) { - fprintf(pf," +%7d: %3d: %s %s\n", - (prev < 0 ? 0 : (timestamp - prev)), - bits, - (isResponse ? "TAG" : " "), - line); - } +// if (pf) { +// fprintf(pf," +%7d: %3d: %s %s\n", +// (prev < 0 ? 0 : (timestamp - prev)), +// bits, +// (isResponse ? "TAG" : " "), +// line); +// } prev = timestamp; i += (len + 9); } - if (pf) { - fclose(pf); - PrintAndLog("Recorded activity succesfully written to file: %s", filename); - } - + return 0; } @@ -142,15 +126,13 @@ int CmdLFHitagSnoop(const char *Cmd) { } int CmdLFHitagSim(const char *Cmd) { - - UsbCommand c = {CMD_SIMULATE_HITAG}; - char filename[FILE_PATH_SIZE] = { 0x00 }; + UsbCommand c = {CMD_SIMULATE_HITAG}; + char filename[256] = { 0x00 }; FILE* pf; bool tag_mem_supplied; - int len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); - + + param_getstr(Cmd,0,filename); + if (strlen(filename) > 0) { if ((pf = fopen(filename,"rb+")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); @@ -158,10 +140,10 @@ int CmdLFHitagSim(const char *Cmd) { } tag_mem_supplied = true; if (fread(c.d.asBytes,48,1,pf) == 0) { - PrintAndLog("Error: File reading error"); + PrintAndLog("Error: File reading error"); fclose(pf); return 1; - } + } fclose(pf); } else { tag_mem_supplied = false; @@ -245,11 +227,11 @@ int CmdLFHitagReader(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"list", CmdLFHitagList, 1, " List Hitag trace history"}, + {"list", CmdLFHitagList, 1, "List Hitag trace history"}, {"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"}, - {"sim", CmdLFHitagSim, 1, " Simulate Hitag transponder"}, + {"sim", CmdLFHitagSim, 1, "Simulate Hitag transponder"}, {"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; int CmdLFHitag(const char *Cmd) diff --git a/client/cmdlfio.c b/client/cmdlfio.c index 129323ac..14ce5498 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -16,13 +16,13 @@ static int CmdHelp(const char *Cmd); int CmdIODemodFSK(const char *Cmd) { - int findone = 0; - if (Cmd[0] =='1') findone = 1; + int findone=0; + if(Cmd[0]=='1') findone=1; - UsbCommand c={CMD_IO_DEMOD_FSK}; - c.arg[0] = findone; - SendCommand(&c); - return 0; + UsbCommand c={CMD_IO_DEMOD_FSK}; + c.arg[0]=findone; + SendCommand(&c); + return 0; } int CmdIOProxDemod(const char *Cmd){ @@ -66,10 +66,10 @@ int CmdIOClone(const char *Cmd) static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"demod", CmdIOProxDemod, 1, "Demodulate Stream"}, - {"fskdemod", CmdIODemodFSK, 0, "['1'] Realtime IO FSK demodulator (option '1' for one tag only)"}, - {"clone", CmdIOClone, 0, "Clone ioProx Tag"}, + {"help", CmdHelp, 1, "This help"}, + {"demod", CmdIOProxDemod, 1, "Demodulate Stream"}, + {"fskdemod", CmdIODemodFSK, 0, "['1'] Realtime IO FSK demodulator (option '1' for one tag only)"}, + {"clone", CmdIOClone, 0, "Clone ioProx Tag"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 24685eb9..a719c7ad 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -13,86 +13,58 @@ #include "proxmark3.h" #include "ui.h" #include "graph.h" -#include "cmdmain.h" #include "cmdparser.h" #include "cmddata.h" #include "cmdlf.h" #include "cmdlft55xx.h" -#include "util.h" -#include "data.h" - -#define LF_TRACE_BUFF_SIZE 20000 // 32 x 32 x 10 (32 bit times numofblock (7), times clock skip..) -#define LF_BITSSTREAM_LEN 1000 // more then 1000 bits shouldn't happend.. 8block * 4 bytes * 8bits = static int CmdHelp(const char *Cmd); + int CmdReadBlk(const char *Cmd) { - int block = -1; - sscanf(Cmd, "%d", &block); + int Block = 8; //default to invalid block + UsbCommand c; - if ((block > 7) | (block < 0)) { - PrintAndLog("Block must be between 0 and 7"); - return 1; - } + sscanf(Cmd, "%d", &Block); - UsbCommand c; - c.cmd = CMD_T55XX_READ_BLOCK; - c.d.asBytes[0] = 0x00; - c.arg[0] = 0; - c.arg[1] = block; - c.arg[2] = 0; - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); - - uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); + if (Block > 7) { + PrintAndLog("Block must be between 0 and 7"); + return 1; + } - for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = (int)data[j]; - } - GraphTraceLen = LF_TRACE_BUFF_SIZE; - ManchesterDemod(block); - RepaintGraphWindow(); + PrintAndLog("Reading block %d", Block); + + c.cmd = CMD_T55XX_READ_BLOCK; + c.d.asBytes[0] = 0x0; //Normal mode + c.arg[0] = 0; + c.arg[1] = Block; + c.arg[2] = 0; + SendCommand(&c); return 0; } int CmdReadBlkPWD(const char *Cmd) { - int Block = -1; //default to invalid block - int Password = 0xFFFFFFFF; //default to blank Block 7 - UsbCommand c; + int Block = 8; //default to invalid block + int Password = 0xFFFFFFFF; //default to blank Block 7 + UsbCommand c; - sscanf(Cmd, "%d %x", &Block, &Password); + sscanf(Cmd, "%d %x", &Block, &Password); - if ((Block > 7) | (Block < 0)) { - PrintAndLog("Block must be between 0 and 7"); - return 1; - } + if (Block > 7) { + PrintAndLog("Block must be between 0 and 7"); + return 1; + } - PrintAndLog("Reading page 0 block %d pwd %08X", Block, Password); + PrintAndLog("Reading block %d with password %08X", Block, Password); - c.cmd = CMD_T55XX_READ_BLOCK; - c.d.asBytes[0] = 0x1; //Password mode - c.arg[0] = 0; - c.arg[1] = Block; - c.arg[2] = Password; - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); - - uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); - - for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]); - } - GraphTraceLen = LF_TRACE_BUFF_SIZE; - ManchesterDemod(Block); - RepaintGraphWindow(); + c.cmd = CMD_T55XX_READ_BLOCK; + c.d.asBytes[0] = 0x1; //Password mode + c.arg[0] = 0; + c.arg[1] = Block; + c.arg[2] = Password; + SendCommand(&c); return 0; } @@ -147,349 +119,22 @@ int CmdWriteBlkPWD(const char *Cmd) int CmdReadTrace(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: lf t55xx trace [use data from Graphbuffer]"); - PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); - PrintAndLog(""); - PrintAndLog(" sample: lf t55xx trace"); - PrintAndLog(" sample: lf t55xx trace 1"); - return 0; - } + PrintAndLog("Reading traceability data"); - if ( strlen(Cmd)==0){ - UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}}; - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); - - uint8_t data[LF_TRACE_BUFF_SIZE] = {0x00}; - - GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,0); //3560 -- should be offset.. - WaitForResponseTimeout(CMD_ACK,NULL, 1500); - - for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) { - GraphBuffer[j] = ((int)data[j]); - } - GraphTraceLen = LF_TRACE_BUFF_SIZE; - } - - uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; - uint8_t * bitstream = bits; - - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); - RepaintGraphWindow(); - - 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 ); - PrintAndLog(" Manufactured"); - PrintAndLog(" Year/Quarter : %d/%d",2000+year, quarter ); - PrintAndLog(" Lot ID : %d", lotid ); - PrintAndLog(" Wafer number : %d", wafer); - PrintAndLog(" Die Number : %d", dw); - PrintAndLog("-------------------------------------------------------------"); - PrintAndLog(" Raw Data - Page 1"); - PrintAndLog(" Block 0 : 0x%08X %s", bl0, sprint_bin(bitstream+5,32) ); - PrintAndLog(" Block 0 : 0x%08X %s", bl1, sprint_bin(bitstream+37,32) ); - PrintAndLog("-------------------------------------------------------------"); - /* - TRACE - BLOCK O - Bits Definition HEX - 1-8 ACL Allocation class (ISO/IEC 15963-1) 0xE0 - 9-16 MFC Manufacturer ID (ISO/IEC 7816-6) 0x15 Atmel Corporation - 17-21 CID 0x1 = Atmel ATA5577M1 0x2 = Atmel ATA5577M2 - 22-24 ICR IC revision - 25-28 YEAR (BCD encoded) 9 (= 2009) - 29-30 QUARTER 1,2,3,4 - 31-32 LOT ID - - TRACE - BLOCK 1 - 1-12 LOT ID - 13-17 Wafer number - 18-32 DW, die number sequential - */ - + UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}}; + SendCommand(&c); return 0; } -int CmdInfo(const char *Cmd){ - /* - Page 0 Block 0 Configuration data. - Normal mode - Extended mode - */ - char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: lf t55xx info [use data from Graphbuffer]"); - PrintAndLog(" [use data from Graphbuffer], if not set, try reading data from tag."); - PrintAndLog(""); - PrintAndLog(" sample: lf t55xx info"); - PrintAndLog(" sample: lf t55xx info 1"); - return 0; - } - - if ( strlen(Cmd) == 0 ){ - CmdReadBlk("0"); - } - - uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; - - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bits, LF_BITSSTREAM_LEN); - - uint8_t si = 5; - uint32_t bl0 = PackBits(si, 32, bits); - - uint32_t safer = PackBits(si, 4, bits); si += 4; - uint32_t resv = PackBits(si, 7, bits); si += 7; - uint32_t dbr = PackBits(si, 3, bits); si += 3; - uint32_t extend = PackBits(si, 1, bits); si += 1; - uint32_t datamodulation = PackBits(si, 5, bits); si += 5; - uint32_t pskcf = PackBits(si, 2, bits); si += 2; - uint32_t aor = PackBits(si, 1, bits); si += 1; - uint32_t otp = PackBits(si, 1, bits); si += 1; - uint32_t maxblk = PackBits(si, 3, bits); si += 3; - uint32_t pwd = PackBits(si, 1, bits); si += 1; - uint32_t sst = PackBits(si, 1, bits); si += 1; - uint32_t fw = PackBits(si, 1, bits); si += 1; - uint32_t inv = PackBits(si, 1, bits); si += 1; - uint32_t por = PackBits(si, 1, bits); si += 1; - - PrintAndLog(""); - PrintAndLog("-- T55xx Configuration --------------------------------------"); - PrintAndLog("-------------------------------------------------------------"); - PrintAndLog(" Safer key : %s", GetSaferStr(safer)); - PrintAndLog(" reserved : %d", resv); - PrintAndLog(" Data bit rate : %s", GetBitRateStr(dbr)); - PrintAndLog(" eXtended mode : %s", (extend) ? "Yes - Warning":"No"); - PrintAndLog(" Modulation : %s", GetModulationStr(datamodulation) ); - PrintAndLog(" PSK clock freq : %d", pskcf); - PrintAndLog(" AOR - Answer on Request : %s", (aor) ? "Yes":"No"); - PrintAndLog(" OTP - One Time Pad : %s", (otp) ? "Yes - Warning":"No" ); - PrintAndLog(" Max block : %d", maxblk); - PrintAndLog(" Password mode : %s", (pwd) ? "Yes":"No"); - PrintAndLog(" Sequence Start Terminator : %s", (sst) ? "Yes":"No"); - PrintAndLog(" Fast Write : %s", (fw) ? "Yes":"No"); - PrintAndLog(" Inverse data : %s", (inv) ? "Yes":"No"); - PrintAndLog(" POR-Delay : %s", (por) ? "Yes":"No"); - PrintAndLog("-------------------------------------------------------------"); - PrintAndLog(" Raw Data - Page 0"); - PrintAndLog(" Block 0 : 0x%08X %s", bl0, sprint_bin(bits+5,32) ); - PrintAndLog("-------------------------------------------------------------"); - - return 0; -} - -int CmdDump(const char *Cmd){ - - char cmdp = param_getchar(Cmd, 0); - char s[20]; - uint8_t pwd[4] = {0x00}; - bool hasPwd = ( strlen(Cmd) > 0); - - if ( cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: lf t55xx dump "); - PrintAndLog(" sample: lf t55xx dump FFFFFFFF"); - return 0; - } - - if ( hasPwd ){ - if (param_gethex(Cmd, 0, pwd, 8)) { - PrintAndLog("password must include 8 HEX symbols"); - return 0; - } - } - - for ( int i = 0; i <8; ++i){ - memset(s,0,sizeof(s)); - if ( hasPwd ) { - sprintf(s,"%d %02x%02x%02x%02x", i, pwd[0],pwd[1],pwd[2],pwd[3]); - CmdReadBlkPWD(s); - } else { - sprintf(s,"%d", i); - CmdReadBlk(s); - } - } - return 0; -} - -int CmdIceFsk(const char *Cmd){ - - if (!HasGraphData()) return 0; - - iceFsk3(GraphBuffer, LF_TRACE_BUFF_SIZE); - RepaintGraphWindow(); - return 0; -} -int CmdIceManchester(const char *Cmd){ - ManchesterDemod( -1); - return 0; -} -int ManchesterDemod(int blockNum){ - - if (!HasGraphData()) return 0; - - uint8_t sizebyte = 32; - // the value 5 was selected during empirical studies of the decoded data. Some signal noise to skip. - uint8_t offset = 5; - uint32_t blockData; - uint8_t bits[LF_BITSSTREAM_LEN] = {0x00}; - uint8_t * bitstream = bits; - - //manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bitstream, LF_BITSSTREAM_LEN); - manchester_decode(GraphBuffer, LF_TRACE_BUFF_SIZE, bits, LF_BITSSTREAM_LEN); - //blockData = PackBits(offset, sizebyte, bitstream); - blockData = PackBits(offset, sizebyte, bits); - - if ( blockNum < 0) - PrintAndLog(" Decoded : 0x%08X %s", blockData, sprint_bin(bitstream+offset,sizebyte) ); - else - PrintAndLog(" Block %d : 0x%08X %s", blockNum, blockData, sprint_bin(bitstream+offset,sizebyte) ); - - return 0; -} - -char * GetBitRateStr(uint32_t id){ - static char buf[40]; - char *retStr = buf; - switch (id){ - case 0: - sprintf(retStr,"%d - RF/8",id); - break; - case 1: - sprintf(retStr,"%d - RF/16",id); - break; - case 2: - sprintf(retStr,"%d - RF/32",id); - break; - case 3: - sprintf(retStr,"%d - RF/40",id); - break; - case 4: - sprintf(retStr,"%d - RF/50",id); - break; - case 5: - sprintf(retStr,"%d - RF/64",id); - break; - case 6: - sprintf(retStr,"%d - RF/100",id); - break; - case 7: - sprintf(retStr,"%d - RF/128",id); - break; - default: - sprintf(retStr,"%d - (Unknown)",id); - break; - } - - return buf; -} - -char * GetSaferStr(uint32_t id){ - static char buf[40]; - char *retStr = buf; - - sprintf(retStr,"%d",id); - if (id == 6) { - sprintf(retStr,"%d - pasdwd",id); - } - if (id == 9 ){ - sprintf(retStr,"%d - testmode ",id); - } - - return buf; -} -char * GetModulationStr( uint32_t id){ - static char buf[40]; - char *retStr = buf; - - switch (id){ - case 0: - sprintf(retStr,"%d - DIRECT (ASK/NRZ)",id); - break; - case 1: - sprintf(retStr,"%d - PSK 1 phase change when input changes",id); - break; - case 2: - sprintf(retStr,"%d - PSK 2 phase change on bitclk if input high",id); - break; - case 3: - sprintf(retStr,"%d - PSK 3 phase change on rising edge of input",id); - break; - case 4: - sprintf(retStr,"%d - FSK 1 RF/8 RF/5",id); - break; - case 5: - sprintf(retStr,"%d - FSK 2 RF/8 RF/10",id); - break; - case 6: - sprintf(retStr,"%d - FSK 1a RF/5 RF/8",id); - break; - case 7: - sprintf(retStr,"%d - FSK 2a RF/10 RF/8",id); - break; - case 8: - sprintf(retStr,"%d - Manschester",id); - break; - case 16: - sprintf(retStr,"%d - Biphase",id); - break; - case 17: - sprintf(retStr,"%d - Reserved",id); - break; - default: - sprintf(retStr,"0x%02X (Unknown)",id); - break; - } - return buf; -} - - -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; -} - static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"rd", CmdReadBlk, 0, " -- Read T55xx block data (page 0)"}, - {"rdpwd", CmdReadBlkPWD, 0, " -- Read T55xx block data with password mode"}, - {"wr", CmdWriteBlk, 0, " -- Write T55xx block data (page 0)"}, - {"wrpwd", CmdWriteBlkPWD, 0, " -- Write T55xx block data with password"}, - {"trace", CmdReadTrace, 0, "[1] Read T55xx traceability data (page 1/ blk 0-1)"}, - {"info", CmdInfo, 0, "[1] Read T55xx configuration data (page 0/ blk 0)"}, - {"dump", CmdDump, 0, "[password] Dump T55xx card block 0-7. optional with password"}, - {"fsk", CmdIceFsk, 0, "FSK demod"}, - {"man", CmdIceManchester, 0, "Manchester demod (with SST)"}, + {"help", CmdHelp, 1, "This help"}, + {"readblock", CmdReadBlk, 1, " -- Read T55xx block data (page 0)"}, + {"readblockPWD", CmdReadBlkPWD, 1, " -- Read T55xx block data in password mode(page 0)"}, + {"writeblock", CmdWriteBlk, 1, " -- Write T55xx block data (page 0)"}, + {"writeblockPWD", CmdWriteBlkPWD, 1, " -- Write T55xx block data in password mode(page 0)"}, + {"readtrace", CmdReadTrace, 1, "Read T55xx traceability data (page 1)"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 8c0cdf58..25503e87 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -17,12 +17,5 @@ int CmdReadBlkPWD(const char *Cmd); int CmdWriteBlk(const char *Cmd); int CmdWriteBLkPWD(const char *Cmd); int CmdReadTrace(const char *Cmd); -int CmdInfo(const char *Cmd); -int CmdIceFsk(const char *Cmd); -int CmdIceManchester(const char *Cmd); -int ManchesterDemod(int block); -char * GetBitRateStr(uint32_t id); -char * GetSaferStr(uint32_t id); -char * GetModulationStr( uint32_t id); -uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bitstream); + #endif diff --git a/client/cmdmain.c b/client/cmdmain.c index b3f04e10..df3d4b2e 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -16,7 +16,7 @@ #include "cmdparser.h" #include "proxmark3.h" #include "data.h" -#include "../include/usb_cmd.h" +#include "usb_cmd.h" #include "ui.h" #include "cmdhf.h" #include "cmddata.h" @@ -42,14 +42,14 @@ static int cmd_tail;//Starts as 0 static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help. Use ' help' for details of a particular command."}, - {"data", CmdData, 1, "{ Plot window / data buffer manipulation... }"}, + {"help", CmdHelp, 1, "This help. Use ' 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... }"}, + {"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"}, + {"script", CmdScript, 1,"{ Scripting commands }"}, + {"quit", CmdQuit, 1, "Exit program"}, + {"exit", CmdQuit, 1, "Exit program"}, {NULL, NULL, 0, NULL} }; @@ -130,26 +130,27 @@ int getCommand(UsbCommand* response) * @return true if command was returned, otherwise false */ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) { + + UsbCommand resp; - UsbCommand resp; - - if (response == NULL) - response = &resp; + if (response == NULL) { + response = &resp; + } + // Wait until the command is received + for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { - // Wait until the command is received - for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { - - while(getCommand(response)) { - if(response->cmd == cmd){ - return true; - } - } - msleep(10); // XXX ugh - if (dm_seconds == 200) { // Two seconds elapsed - PrintAndLog("Waiting for a response from the proxmark..."); - PrintAndLog("Don't forget to cancel its operation first by pressing on the button"); - } + while(getCommand(response)) + { + if(response->cmd == cmd){ + return true; + } + } + msleep(10); // XXX ugh + if (dm_seconds == 200) { // Two seconds elapsed + PrintAndLog("Waiting for a response from the proxmark..."); + PrintAndLog("Don't forget to cancel its operation first by pressing on the button"); + } } return false; } @@ -172,29 +173,29 @@ void CommandReceived(char *Cmd) { //----------------------------------------------------------------------------- void UsbCommandReceived(UsbCommand *UC) { - switch(UC->cmd) { - // First check if we are handling a debug message - case CMD_DEBUG_PRINT_STRING: { + switch(UC->cmd) { + // First check if we are handling a debug message + case CMD_DEBUG_PRINT_STRING: { char s[USB_CMD_DATA_SIZE+1] = {0x00}; - size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); - memcpy(s,UC->d.asBytes,len); - PrintAndLog("#db# %s ", s); - return; - } break; + size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); + memcpy(s,UC->d.asBytes,len); + PrintAndLog("#db# %s ", s); + return; + } break; - case CMD_DEBUG_PRINT_INTEGERS: { - PrintAndLog("#db# %08x, %08x, %08x \r\n", UC->arg[0], UC->arg[1], UC->arg[2]); - return; - } break; - - case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: { - sample_buf_len += UC->arg[1]; - memcpy(sample_buf+(UC->arg[0]),UC->d.asBytes,UC->arg[1]); - } break; + case CMD_DEBUG_PRINT_INTEGERS: { + PrintAndLog("#db# %08x, %08x, %08x \r\n", UC->arg[0], UC->arg[1], UC->arg[2]); + return; + } break; + + case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: { + sample_buf_len += UC->arg[1]; + memcpy(sample_buf+(UC->arg[0]),UC->d.asBytes,UC->arg[1]); + } break; default: - break; - } + break; + } storeCommand(UC); } diff --git a/client/cmdmain.h b/client/cmdmain.h index 5e4ee73a..0cf2b35d 100644 --- a/client/cmdmain.h +++ b/client/cmdmain.h @@ -11,7 +11,7 @@ #ifndef CMDMAIN_H__ #define CMDMAIN_H__ -#include "../include/usb_cmd.h" +#include "usb_cmd.h" #include "cmdparser.h" void UsbCommandReceived(UsbCommand *UC); void CommandReceived(char *Cmd); diff --git a/client/data.h b/client/data.h index 41bd9a41..33ee9d04 100644 --- a/client/data.h +++ b/client/data.h @@ -13,9 +13,6 @@ #include -//trace buffer size as defined in armsrc/apps.h TRACE_SIZE -#define TRACE_BUFFER_SIZE 4096 -#define FILE_PATH_SIZE 1000 #define SAMPLE_BUFFER_SIZE 64 extern uint8_t* sample_buf; diff --git a/client/flash.c b/client/flash.c index 7976d410..4e222ece 100644 --- a/client/flash.c +++ b/client/flash.c @@ -16,7 +16,7 @@ #include "flash.h" #include "elf.h" #include "proxendian.h" -#include "../include/usb_cmd.h" +#include "usb_cmd.h" void SendCommand(UsbCommand* txcmd); void ReceiveCommand(UsbCommand* rxcmd); @@ -275,7 +275,7 @@ static int get_proxmark_state(uint32_t *state) { UsbCommand c; c.cmd = CMD_DEVICE_INFO; - SendCommand(&c); + SendCommand(&c); UsbCommand resp; ReceiveCommand(&resp); @@ -404,11 +404,11 @@ static int write_block(uint32_t address, uint8_t *data, uint32_t length) memset(block_buf, 0xFF, BLOCK_SIZE); memcpy(block_buf, data, length); - UsbCommand c; + UsbCommand c; c.cmd = CMD_FINISH_WRITE; c.arg[0] = address; memcpy(c.d.asBytes, block_buf, length); - SendCommand(&c); + SendCommand(&c); return wait_for_ack(); } @@ -469,7 +469,7 @@ void flash_free(flash_file_t *ctx) // just reset the unit int flash_stop_flashing(void) { UsbCommand c = {CMD_HARDWARE_RESET}; - SendCommand(&c); - msleep(100); - return 0; + SendCommand(&c); + msleep(100); + return 0; } diff --git a/client/flasher.c b/client/flasher.c index 1390d817..2a24ba8f 100644 --- a/client/flasher.c +++ b/client/flasher.c @@ -13,7 +13,7 @@ #include "proxmark3.h" #include "flash.h" #include "uart.h" -#include "../include/usb_cmd.h" +#include "usb_cmd.h" #ifdef _WIN32 # define unlink(x) diff --git a/client/graph.c b/client/graph.c index d0f6fe74..a0e85ffd 100644 --- a/client/graph.c +++ b/client/graph.c @@ -9,7 +9,6 @@ //----------------------------------------------------------------------------- #include -#include #include #include "ui.h" #include "graph.h" @@ -22,13 +21,11 @@ int GraphTraceLen; void AppendGraph(int redraw, int clock, int bit) { int i; - int half = (int)(clock/2); - int firstbit = bit ^ 1; - - for (i = 0; i < half; ++i) - GraphBuffer[GraphTraceLen++] = firstbit; + + for (i = 0; i < (int)(clock / 2); ++i) + GraphBuffer[GraphTraceLen++] = bit ^ 1; - for (i = 0; i <= half; ++i) + for (i = (int)(clock / 2); i < clock; ++i) GraphBuffer[GraphTraceLen++] = bit; if (redraw) @@ -39,106 +36,154 @@ void AppendGraph(int redraw, int clock, int bit) int ClearGraph(int redraw) { int gtl = GraphTraceLen; - memset(GraphBuffer, 0x00, GraphTraceLen); - GraphTraceLen = 0; - + if (redraw) RepaintGraphWindow(); return gtl; } -void SetGraphBuf(uint8_t *buff, int size) +/* + * Detect clock rate + */ + //decommissioned - has difficulty detecting rf/32 +/* +int DetectClockOld(int peak) { - if ( buff == NULL ) return; - - uint16_t i = 0; - if ( size > MAX_GRAPH_TRACE_LEN ) - size = MAX_GRAPH_TRACE_LEN; - ClearGraph(0); - for (; i < size; ++i){ - GraphBuffer[i] = buff[i]; - } - GraphTraceLen = size; - RepaintGraphWindow(); - return; -} + int i; + int clock = 0xFFFF; + int lastpeak = 0; -// Copies grahpbuff to buff. -// while triming values to the range -127 -- 127. -int GetFromGraphBuf(uint8_t *buff) + // Detect peak if we don't have one + if (!peak) + for (i = 0; i < GraphTraceLen; ++i) + if (GraphBuffer[i] > peak) + peak = GraphBuffer[i]; + + // peak=(int)(peak*.75); + for (i = 1; i < GraphTraceLen; ++i) + { + // If this is the beginning of a peak + if (GraphBuffer[i - 1] != GraphBuffer[i] && GraphBuffer[i] >= peak) + { + // Find lowest difference between peaks + if (lastpeak && i - lastpeak < clock) + clock = i - lastpeak; + lastpeak = i; + } + } + + return clock; +} +*/ +/* +NOW IN LFDEMOD.C + +// by marshmellow +// not perfect especially with lower clocks or VERY good antennas (heavy wave clipping) +// maybe somehow adjust peak trimming value based on samples to fix? +int DetectASKClock(int peak) { - if ( buff == NULL ) return -1; - uint32_t i = 0; - - for (; i < GraphTraceLen; ++i){ - - // trim upper and lower values. - if (GraphBuffer[i] > 127) - GraphBuffer[i] = 127; - else if (GraphBuffer[i] < -127) - GraphBuffer[i] = -127; - - buff[i] = (uint8_t)(GraphBuffer[i] + 128); - } - return i; + int i=0; + int low=0; + int clk[]={16,32,40,50,64,100,128,256}; + int loopCnt = 256; + if (GraphTraceLenpeak){ + peak = GraphBuffer[i]; + } + if(GraphBuffer[i]=peak) || (GraphBuffer[ii]<=low)){ + errCnt[clkCnt]=0; + for (i=0; i<((int)(GraphTraceLen/clk[clkCnt])-1); ++i){ + if (GraphBuffer[ii+(i*clk[clkCnt])]>=peak || GraphBuffer[ii+(i*clk[clkCnt])]<=low){ + }else if(GraphBuffer[ii+(i*clk[clkCnt])-tol]>=peak || GraphBuffer[ii+(i*clk[clkCnt])-tol]<=low){ + }else if(GraphBuffer[ii+(i*clk[clkCnt])+tol]>=peak || GraphBuffer[ii+(i*clk[clkCnt])+tol]<=low){ + }else{ //error no peak detected + errCnt[clkCnt]++; + } + } + if(errCnt[clkCnt]==0) return clk[clkCnt]; + if(errCnt[clkCnt]127) GraphBuffer[i]=127; //trim + if (GraphBuffer[i]<-127) GraphBuffer[i]=-127; //trim + buff[i]=(uint8_t)(GraphBuffer[i]+128); + } + return i; } /* Get or auto-detect clock rate */ -int GetClock(const char *str, int verbose) +int GetClock(const char *str, int peak, int verbose) { - int clock; + int clock; +// int clock2; + sscanf(str, "%i", &clock); + if (!strcmp(str, "")) + clock = 0; - sscanf(str, "%i", &clock); - if (!strcmp(str, "")) - clock = 0; + /* Auto-detect clock */ + if (!clock) + { + uint8_t grph[MAX_GRAPH_TRACE_LEN]={0}; + int size = getFromGraphBuf(grph); + clock = DetectASKClock(grph,size,0); + //clock2 = DetectClock2(peak); + /* Only print this message if we're not looping something */ + if (!verbose){ + PrintAndLog("Auto-detected clock rate: %d", clock); + //PrintAndLog("clock2: %d",clock2); + } + } - /* Auto-detect clock */ - if (!clock) { - - uint8_t grph[MAX_GRAPH_TRACE_LEN] = {0x00}; - int size = GetFromGraphBuf(grph); - if ( size < 0 ) { - PrintAndLog("Failed to copy from graphbuffer"); - return -1; - } - clock = DetectASKClock(grph, size, 0); - - /* Only print this message if we're not looping something */ - if (verbose) - PrintAndLog("Auto-detected clock rate: %d", clock); - } - return clock; + return clock; } - -// A simple test to see if there is any data inside Graphbuffer. -bool HasGraphData(){ - - if ( GraphTraceLen <= 0) { - PrintAndLog("No data available, try reading something first"); - return false; - } - return true; -} - -// Detect high and lows in Grapbuffer. -// Only loops the first 256 values. -void DetectHighLowInGraph(int *high, int *low, bool addFuzz) { - - uint8_t loopMax = 255; - if ( loopMax > GraphTraceLen) - loopMax = GraphTraceLen; - - for (uint8_t i = 0; i < loopMax; ++i) { - if (GraphBuffer[i] > *high) - *high = GraphBuffer[i]; - else if (GraphBuffer[i] < *low) - *low = GraphBuffer[i]; - } - - //12% fuzz in case highs and lows aren't clipped - if (addFuzz) { - *high = (int)(*high * .88); - *low = (int)(*low * .88); - } -} \ No newline at end of file diff --git a/client/graph.h b/client/graph.h index c745270d..325582a6 100644 --- a/client/graph.h +++ b/client/graph.h @@ -10,16 +10,17 @@ #ifndef GRAPH_H__ #define GRAPH_H__ +#include void AppendGraph(int redraw, int clock, int bit); int ClearGraph(int redraw); -int GetFromGraphBuf(uint8_t *buff); -int GetClock(const char *str, int verbose); -void SetGraphBuf(uint8_t *buff,int size); -bool HasGraphData(); -void DetectHighLowInGraph(int *high, int *low, bool addFuzz); +//int DetectClock(int peak); +int getFromGraphBuf(uint8_t *buff); +int GetClock(const char *str, int peak, int verbose); +void setGraphBuf(uint8_t *buff,int size); #define MAX_GRAPH_TRACE_LEN (1024*128) extern int GraphBuffer[MAX_GRAPH_TRACE_LEN]; extern int GraphTraceLen; + #endif diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 1c9dae8b..463ba9be 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -1,17 +1,5 @@ /***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine + * This file is part of iClassCipher. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -215,7 +203,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, int length, uint8_t *div_key_p, uint8_t mac[4]) { @@ -224,17 +212,17 @@ void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4]) cc_nr=(uint8_t*)malloc(length+1); memcpy(cc_nr,cc_nr_p,length); memcpy(div_key,div_key_p,8); - - reverse_arraybytes(cc_nr,length); - BitstreamIn bitstream = {cc_nr,length * 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); + + reverse_arraybytes(cc_nr,length); + BitstreamIn bitstream = {cc_nr,length * 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); //printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]); - free(cc_nr); + free(cc_nr); return; } @@ -260,8 +248,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; } diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h index 314a560a..4bfbe0b7 100644 --- a/client/loclass/cipher.h +++ b/client/loclass/cipher.h @@ -1,17 +1,5 @@ /***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine + * This file is part of iClassCipher. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index f82a11ce..e11e8d22 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -1,17 +1,5 @@ /***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine + * This file is part of iClassCipher. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h index e2338534..acf96115 100644 --- a/client/loclass/cipherutils.h +++ b/client/loclass/cipherutils.h @@ -1,17 +1,5 @@ /***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine + * This file is part of iClassCipher. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index 3801d662..f0eb964b 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -1,41 +1,3 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * - ****************************************************************************/ - #include #include #include @@ -552,6 +514,7 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) */ int bruteforceFile(const char *filename, uint16_t keytable[]) { + FILE *f = fopen(filename, "rb"); if(!f) { prnlog("Failed to read from file '%s'", filename); @@ -563,7 +526,7 @@ int bruteforceFile(const char *filename, uint16_t keytable[]) fseek(f, 0, SEEK_SET); uint8_t *dump = malloc(fsize); - size_t bytes_read = fread(dump, fsize, 1, f); + size_t bytes_read = fread(dump, 1, fsize, f); fclose(f); if (bytes_read < fsize) @@ -614,9 +577,18 @@ int _testBruteforce() **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 **** **/ uint16_t keytable[128] = {0}; - //save some time... - startvalue = 0x7B0000; - errors |= bruteforceFile("iclass_dump.bin",keytable); + + //Test a few variants + if(fileExists("iclass_dump.bin")) + { + errors |= bruteforceFile("iclass_dump.bin",keytable); + }else if(fileExists("loclass/iclass_dump.bin")){ + errors |= bruteforceFile("loclass/iclass_dump.bin",keytable); + }else if(fileExists("client/loclass/iclass_dump.bin")){ + errors |= bruteforceFile("client/loclass/iclass_dump.bin",keytable); + }else{ + prnlog("Error: The file iclass_dump.bin was not found!"); + } } return errors; } diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h index fb27355f..21004e59 100644 --- a/client/loclass/elite_crack.h +++ b/client/loclass/elite_crack.h @@ -1,42 +1,3 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * - ****************************************************************************/ - - #ifndef ELITE_CRACK_H #define ELITE_CRACK_H void permutekey(uint8_t key[8], uint8_t dest[8]); diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index 443070c1..f96f8652 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -1,41 +1,3 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * - ****************************************************************************/ - #include #include #include @@ -51,11 +13,11 @@ int fileExists(const char *filename) { #ifdef _WIN32 - struct _stat fileStat; - int result = _stat(filename, &fileStat); + struct _stat st; + int result = _stat(filename, &st); #else - struct stat fileStat; - int result = stat(filename, &fileStat); + struct stat st; + int result = stat(filename, &st); #endif return result == 0; } @@ -76,33 +38,21 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si /* We should have a valid filename now, e.g. dumpdata-3.bin */ /*Opening file for writing in binary mode*/ - FILE *fh=fopen(fileName,"wb"); - if(!fh) { + FILE *fileHandle=fopen(fileName,"wb"); + if(!fileHandle) { PrintAndLog("Failed to write to file '%s'", fileName); - free(fh); + free(fileName); return 1; } - fwrite(data, 1, datalen, fh); - fclose(fh); - PrintAndLog("Saved data to '%s'", fileName); + fwrite(data, 1, datalen, fileHandle); + fclose(fileHandle); + PrintAndLog(">Saved data to '%s'", fileName); + free(fileName); return 0; } -int loadFile(const char *fileName, void* data, size_t datalen) -{ - FILE *filehandle = fopen(fileName, "rb"); - if(!filehandle) { - PrintAndLog("Failed to read from file '%s'", fileName); - free(filehandle); - return 1; - } - fread(data,datalen,1,filehandle); - fclose(filehandle); - free(filehandle); - return 0; -} /** * Utility function to print to console. This is used consistently within the library instead * of printf, but it actually only calls printf (and adds a linebreak). @@ -113,11 +63,11 @@ int loadFile(const char *fileName, void* data, size_t datalen) */ void prnlog(char *fmt, ...) { - + char buffer[2048] = {0}; va_list args; va_start(args,fmt); - PrintAndLog(fmt, args); - //vprintf(fmt,args); + vsprintf (buffer,fmt, args); va_end(args); - //printf("\n"); + PrintAndLog(buffer); + } diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h index 405c9704..e02079d5 100644 --- a/client/loclass/fileutils.h +++ b/client/loclass/fileutils.h @@ -1,41 +1,3 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * - ****************************************************************************/ - #ifndef FILEUTILS_H #define FILEUTILS_H /** @@ -49,16 +11,7 @@ * @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 loadFile(const char *fileName, void* data, size_t datalen); /** * Utility function to print to console. This is used consistently within the library instead @@ -68,4 +21,5 @@ int loadFile(const char *fileName, void* data, size_t datalen); * @param fmt */ void prnlog(char *fmt, ...); +int fileExists(const char *filename); #endif // FILEUTILS_H diff --git a/client/loclass/hash1_brute.c b/client/loclass/hash1_brute.c deleted file mode 100644 index a9fe0d19..00000000 --- a/client/loclass/hash1_brute.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include "cipherutils.h" -#include -#include -#include -#include -#include -#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 deleted file mode 100644 index b26ad96d..00000000 --- a/client/loclass/hash1_brute.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef HASH1_BRUTE_H -#define HASH1_BRUTE_H -void brute_hash1(); - -#endif // HASH1_BRUTE_H diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index fccd71d8..4749181e 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -1,17 +1,5 @@ /***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine + * This file is part of iClassCipher. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -737,6 +725,7 @@ int doTestsWithKnownInputs() int readKeyFile(uint8_t key[8]) { + FILE *f; int retval = 1; f = fopen("iclass_key.bin", "rb"); @@ -749,6 +738,7 @@ int readKeyFile(uint8_t key[8]) fclose(f); } return retval; + } diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h index 13096194..1de46b62 100644 --- a/client/loclass/ikeys.h +++ b/client/loclass/ikeys.h @@ -1,41 +1,3 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * - ****************************************************************************/ - #ifndef IKEYS_H #define IKEYS_H diff --git a/client/loclass/main.c b/client/loclass/main.c index 50671a19..42019072 100644 --- a/client/loclass/main.c +++ b/client/loclass/main.c @@ -1,17 +1,5 @@ /***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine + * This file is part of iClassCipher. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -30,13 +18,9 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * + * along with IClassCipher. If not, see . ****************************************************************************/ - #include #include #include @@ -80,18 +64,7 @@ int main (int argc, char **argv) { prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n"); prnlog("Comes with ABSOLUTELY NO WARRANTY"); - prnlog("Released as GPLv2\n"); - prnlog("WARNING"); - prnlog(""); - prnlog("THIS TOOL IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. "); - prnlog(""); - prnlog("USAGE OF THIS TOOL IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL "); - prnlog("PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, "); - prnlog("AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. "); - prnlog(""); - prnlog("THIS TOOL SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. "); - - + prnlog("This is free software, and you are welcome to use, abuse and repackage, please keep the credits\n"); char *fileName = NULL; int c; while ((c = getopt (argc, argv, "thf:")) != -1) diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index d2acb3be..aeba31a7 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -48,8 +48,8 @@ local _commands = { CMD_EM4X_READ_WORD = 0x0218, CMD_EM4X_WRITE_WORD = 0x0219, CMD_IO_DEMOD_FSK = 0x021A, - CMD_IO_CLONE_TAG = 0x021B, - CMD_EM410X_DEMOD = 0x021c, + CMD_IO_CLONE_TAG = 0x021B, + CMD_EM410X_DEMOD = 0x021C, --/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ --// For the 13.56 MHz tags @@ -64,7 +64,6 @@ local _commands = { CMD_ISO_15693_COMMAND_DONE = 0x0314, CMD_ISO_15693_FIND_AFI = 0x0315, CMD_ISO_15693_DEBUG = 0x0316, - CMD_LF_SNOOP_RAW_ADC_SAMPLES = 0x0317, --// For Hitag2 transponders CMD_SNOOP_HITAG = 0x0370, @@ -81,13 +80,10 @@ local _commands = { CMD_READER_LEGIC_RF = 0x0388, CMD_WRITER_LEGIC_RF = 0x0389, CMD_EPA_PACE_COLLECT_NONCE = 0x038A, - --//CMD_EPA_ = 0x038B, CMD_SNOOP_ICLASS = 0x0392, CMD_SIMULATE_TAG_ICLASS = 0x0393, CMD_READER_ICLASS = 0x0394, - CMD_READER_ICLASS_REPLAY = 0x0395, - CMD_ICLASS_ISO14443A_WRITE = 0x0397, --// For measurements of the antenna tuning CMD_MEASURE_ANTENNA_TUNING = 0x0400, @@ -104,54 +100,30 @@ local _commands = { CMD_MIFARE_EML_MEMSET = 0x0602, CMD_MIFARE_EML_MEMGET = 0x0603, CMD_MIFARE_EML_CARDLOAD = 0x0604, - - --// magic chinese card commands - CMD_MIFARE_CSETBLOCK = 0x0605, - CMD_MIFARE_CGETBLOCK = 0x0606, - CMD_MIFARE_CIDENT = 0x0607, - + CMD_MIFARE_EML_CSETBLOCK = 0x0605, + CMD_MIFARE_EML_CGETBLOCK = 0x0606, + CMD_SIMULATE_MIFARE_CARD = 0x0610, CMD_READER_MIFARE = 0x0611, CMD_MIFARE_NESTED = 0x0612, CMD_MIFARE_READBL = 0x0620, - CMD_MIFAREU_READBL = 0x0720, - CMD_MIFARE_READSC = 0x0621, - CMD_MIFAREU_READCARD = 0x0721, - CMD_MIFARE_WRITEBL = 0x0622, - CMD_MIFAREU_WRITEBL = 0x0722, - CMD_MIFAREU_WRITEBL_COMPAT = 0x0723, - CMD_MIFARE_CHKKEYS = 0x0623, CMD_MIFARE_SNIFFER = 0x0630, - --//ultralightC - CMD_MIFAREUC_AUTH1 = 0x0724, - CMD_MIFAREUC_AUTH2 = 0x0725, - CMD_MIFAREUC_READCARD = 0x0726, - - --// mifare desfire - CMD_MIFARE_DESFIRE_READBL = 0x0728, - CMD_MIFARE_DESFIRE_WRITEBL = 0x0729, - CMD_MIFARE_DESFIRE_AUTH1 = 0x072a, - CMD_MIFARE_DESFIRE_AUTH2 = 0x072b, - CMD_MIFARE_DES_READER = 0x072c, - CMD_MIFARE_DESFIRE_INFO = 0x072d, - CMD_MIFARE_DESFIRE = 0x072e, - CMD_UNKNOWN = 0xFFFF, } local _reverse_lookup,k,v = {} - for k, v in pairs(_commands) do - _reverse_lookup[v] = k - end - _commands.tostring = function(command) +for k, v in pairs(_commands) do + _reverse_lookup[v] = k +end +_commands.tostring = function(command) if(type(command) == 'number') then return ("%s (%d)"):format(_reverse_lookup[command]or "ERROR UNDEFINED!", command) end @@ -213,6 +185,7 @@ function Command:getBytes() local cmd = self.cmd local arg1, arg2, arg3 = self.arg1, self.arg2, self.arg3 + return bin.pack("LLLLH",cmd, arg1, arg2, arg3,data); end return _commands \ No newline at end of file diff --git a/client/lualibs/default_toys.lua b/client/lualibs/default_toys.lua deleted file mode 100644 index abb56515..00000000 --- a/client/lualibs/default_toys.lua +++ /dev/null @@ -1,63 +0,0 @@ -local _names = { - --[[ - --]] - ["0400"]="BASH", - ["1600"]="BOOMER" , - ["1800"]="CAMO", - ["3000"]="CHOPCHOP" , - ["2000"]="CYNDER", - ["6400"]="JET-VAC", - ["6700"]="FLASHWING", - ["7000"]="TREE REX", - ["7100"]="LIGHTCORE SHROOMBOOM", - ["1C00"]="DARK SPYRO", - ["0600"]="DINORANG" , - ["1200"]="DOUBLE TROUBLE" , - ["1500"]="DRILLSERGEANT" , - ["1400"]="DROBOT", - ["0900"]="LIGHTCORE ERUPTOR" , - ["0B00"]="FLAMESLINGER" , - ["1F00"]="GHOST ROASTER", - ["0E00"]="GILL GRUNT" , - ["1D00"]="HEX", - ["0A00"]="IGNITOR", - ["0300"]="LIGHTNINGROD", - ["0700"]="LIGHTCORE PRISM BREAK", - ["1500"]="SLAMBAM", - ["0100"]="SONIC BOOM", - ["1000"]="SPYRO", - ["1A00"]="STEALTH ELF", - ["1B00"]="STUMP SMASH", - ["0800"]="SUNBURN", - ["0500"]="TERRAFIN", - ["1300"]="TRIGGER HAPPY", - ["1100"]="VOODOOD", - ["0200"]="WARNADO", - ["0D00"]="WHAM SHELL", - ["0000"]="WHIRLWIND", - ["1700"]="WRECKING BALL", - ["0C00"]="ZAP", - ["1900"]="ZOOK", - ["0300"]="DRAGON", - ["012D"]="ICE", - ["012E"]="PIRATE", - ["0130"]="PVPUNLOCK", - ["012F"]="UNDEAD", - ["0200"]="ANVIL" , - ["CB00"]="CROSSED SWORDS", - ["CC00"]="HOURGLASS", - ["CA00"]="REGENERATION", - ["C900"]="SECRET STASH", - ["CD00"]="SHIELD", - ["CF00"]="SPARX", - ["CE00"]="SPEED BOOTS", - ["0194"]="LEGENDARY BASH", - ["0430"]="LEGENDARY CHOPCHOP", - ["01A0"]="LEGENDARY SPYRO", - ["01A3"]="LEGENDARY TRIGGER HAPPY", - ["0202"]="PET GILL GRUNT", - ["020E"]="PET STEALTH ELF", - ["01F9"]="PET TERRAFIN", - ["0207"]="PET TRIGGER HAPPY", -} -return _names diff --git a/client/lualibs/html_dumplib.lua b/client/lualibs/html_dumplib.lua index a7890885..b8c7ccaa 100644 --- a/client/lualibs/html_dumplib.lua +++ b/client/lualibs/html_dumplib.lua @@ -47,18 +47,6 @@ local function save_HTML(javascript, filename) end -local function save_TEXT(data,filename) - -- Open the output file - local outfile = io.open(filename, "wb") - if outfile == nil then - return oops(string.format("Could not write to file %s",tostring(filename))) - end - - outfile:write(data) - io.close(outfile) - return filename -end - local function save_BIN(data, filename) -- Open the output file @@ -192,7 +180,5 @@ end 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, - SaveAsText = save_TEXT, + convert_eml_to_bin = convert_eml_to_bin, } diff --git a/client/lualibs/htmlskel.lua b/client/lualibs/htmlskel.lua index b468eb2d..a52abdef 100644 --- a/client/lualibs/htmlskel.lua +++ b/client/lualibs/htmlskel.lua @@ -55,7 +55,6 @@ local skel_1 = [[ return "UNKNOWN" } - add("04,,,Mifare TNP3xxx Activision 1K,0f01,01"); add("04,,,Mifare Mini,0004,09"); add("04,,,Mifare Classic 1k/Mifare Plus(4 byte UID) 2K SL1,0004,08"); add("04,,,Mifare Plus (4 byte UID) 2K SL2,0004,10"); diff --git a/client/lualibs/md5.lua b/client/lualibs/md5.lua deleted file mode 100644 index 2390f957..00000000 --- a/client/lualibs/md5.lua +++ /dev/null @@ -1,384 +0,0 @@ -local md5 = { - _VERSION = "md5.lua 0.5.0", - _DESCRIPTION = "MD5 computation in Lua (5.1)", - _URL = "https://github.com/kikito/md5.lua", - _LICENSE = [[ - MIT LICENSE - - Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ]] -} - --- bit lib implementions - -local floor, abs, max = math.floor, math.abs, math.max -local char, byte, format, rep, sub = - string.char, string.byte, string.format, string.rep, string.sub - -local function check_int(n) - -- checking not float - if(n - floor(n) > 0) then - error("trying to use bitwise operation on non-integer!") - end -end - -local function tbl2number(tbl) - local n = #tbl - - local rslt = 0 - local power = 1 - for i = 1, n do - rslt = rslt + tbl[i]*power - power = power*2 - end - - return rslt -end - -local function expand(tbl_m, tbl_n) - local big = {} - local small = {} - if(#tbl_m > #tbl_n) then - big = tbl_m - small = tbl_n - else - big = tbl_n - small = tbl_m - end - -- expand small - for i = #small + 1, #big do - small[i] = 0 - end - -end - -local to_bits -- needs to be declared before bit_not - -local function bit_not(n) - local tbl = to_bits(n) - local size = max(#tbl, 32) - for i = 1, size do - if(tbl[i] == 1) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - return tbl2number(tbl) -end - --- defined as local above -to_bits = function (n) - check_int(n) - if(n < 0) then - -- negative - return to_bits(bit_not(abs(n)) + 1) - end - -- to bits table - local tbl = {} - local cnt = 1 - while (n > 0) do - local last = math.fmod(n,2) - if(last == 1) then - tbl[cnt] = 1 - else - tbl[cnt] = 0 - end - n = (n-last)/2 - cnt = cnt + 1 - end - - return tbl -end - -local function bit_or(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - local rslt = max(#tbl_m, #tbl_n) - for i = 1, rslt do - if(tbl_m[i]== 0 and tbl_n[i] == 0) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - - return tbl2number(tbl) -end - -local function bit_and(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - local rslt = max(#tbl_m, #tbl_n) - for i = 1, rslt do - if(tbl_m[i]== 0 or tbl_n[i] == 0) then - tbl[i] = 0 - else - tbl[i] = 1 - end - end - - return tbl2number(tbl) -end - -local function bit_xor(m, n) - local tbl_m = to_bits(m) - local tbl_n = to_bits(n) - expand(tbl_m, tbl_n) - - local tbl = {} - local rslt = max(#tbl_m, #tbl_n) - for i = 1, rslt do - if(tbl_m[i] ~= tbl_n[i]) then - tbl[i] = 1 - else - tbl[i] = 0 - end - end - - return tbl2number(tbl) -end - -local function bit_rshift(n, bits) - check_int(n) - - local high_bit = 0 - if(n < 0) then - -- negative - n = bit_not(abs(n)) + 1 - high_bit = 2147483648 -- 0x80000000 - end - - for i=1, bits do - n = n/2 - n = bit_or(floor(n), high_bit) - end - return floor(n) -end - -local function bit_lshift(n, bits) - check_int(n) - - if(n < 0) then - -- negative - n = bit_not(abs(n)) + 1 - end - - for i=1, bits do - n = n*2 - end - return bit_and(n, 4294967295) -- 0xFFFFFFFF -end - --- convert little-endian 32-bit int to a 4-char string -local function lei2str(i) - local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end - return f(0)..f(8)..f(16)..f(24) -end - --- convert raw string to big-endian int -local function str2bei(s) - local v=0 - for i=1, #s do - v = v * 256 + byte(s, i) - end - return v -end - --- convert raw string to little-endian int -local function str2lei(s) - local v=0 - for i = #s,1,-1 do - v = v*256 + byte(s, i) - end - return v -end - --- cut up a string in little-endian ints of given size -local function cut_le_str(s,...) - local o, r = 1, {} - local args = {...} - for i=1, #args do - table.insert(r, str2lei(sub(s, o, o + args[i] - 1))) - o = o + args[i] - end - return r -end - -local swap = function (w) return str2bei(lei2str(w)) end - -local function hex2binaryaux(hexval) - return char(tonumber(hexval, 16)) -end - -local function hex2binary(hex) - local result, _ = hex:gsub('..', hex2binaryaux) - return result -end - --- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) --- 10/02/2001 jcw@equi4.com - -local FF = 0xffffffff -local CONSTS = { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, - 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 -} - -local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end -local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end -local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end -local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end -local z=function (f,a,b,c,d,x,s,ac) - a=bit_and(a+f(b,c,d)+x+ac,FF) - -- be *very* careful that left shift does not cause rounding! - return bit_or(bit_lshift(bit_and(a,bit_rshift(FF,s)),s),bit_rshift(a,32-s))+b -end - -local function transform(A,B,C,D,X) - local a,b,c,d=A,B,C,D - local t=CONSTS - - a=z(f,a,b,c,d,X[ 0], 7,t[ 1]) - d=z(f,d,a,b,c,X[ 1],12,t[ 2]) - c=z(f,c,d,a,b,X[ 2],17,t[ 3]) - b=z(f,b,c,d,a,X[ 3],22,t[ 4]) - a=z(f,a,b,c,d,X[ 4], 7,t[ 5]) - d=z(f,d,a,b,c,X[ 5],12,t[ 6]) - c=z(f,c,d,a,b,X[ 6],17,t[ 7]) - b=z(f,b,c,d,a,X[ 7],22,t[ 8]) - a=z(f,a,b,c,d,X[ 8], 7,t[ 9]) - d=z(f,d,a,b,c,X[ 9],12,t[10]) - c=z(f,c,d,a,b,X[10],17,t[11]) - b=z(f,b,c,d,a,X[11],22,t[12]) - a=z(f,a,b,c,d,X[12], 7,t[13]) - d=z(f,d,a,b,c,X[13],12,t[14]) - c=z(f,c,d,a,b,X[14],17,t[15]) - b=z(f,b,c,d,a,X[15],22,t[16]) - - a=z(g,a,b,c,d,X[ 1], 5,t[17]) - d=z(g,d,a,b,c,X[ 6], 9,t[18]) - c=z(g,c,d,a,b,X[11],14,t[19]) - b=z(g,b,c,d,a,X[ 0],20,t[20]) - a=z(g,a,b,c,d,X[ 5], 5,t[21]) - d=z(g,d,a,b,c,X[10], 9,t[22]) - c=z(g,c,d,a,b,X[15],14,t[23]) - b=z(g,b,c,d,a,X[ 4],20,t[24]) - a=z(g,a,b,c,d,X[ 9], 5,t[25]) - d=z(g,d,a,b,c,X[14], 9,t[26]) - c=z(g,c,d,a,b,X[ 3],14,t[27]) - b=z(g,b,c,d,a,X[ 8],20,t[28]) - a=z(g,a,b,c,d,X[13], 5,t[29]) - d=z(g,d,a,b,c,X[ 2], 9,t[30]) - c=z(g,c,d,a,b,X[ 7],14,t[31]) - b=z(g,b,c,d,a,X[12],20,t[32]) - - a=z(h,a,b,c,d,X[ 5], 4,t[33]) - d=z(h,d,a,b,c,X[ 8],11,t[34]) - c=z(h,c,d,a,b,X[11],16,t[35]) - b=z(h,b,c,d,a,X[14],23,t[36]) - a=z(h,a,b,c,d,X[ 1], 4,t[37]) - d=z(h,d,a,b,c,X[ 4],11,t[38]) - c=z(h,c,d,a,b,X[ 7],16,t[39]) - b=z(h,b,c,d,a,X[10],23,t[40]) - a=z(h,a,b,c,d,X[13], 4,t[41]) - d=z(h,d,a,b,c,X[ 0],11,t[42]) - c=z(h,c,d,a,b,X[ 3],16,t[43]) - b=z(h,b,c,d,a,X[ 6],23,t[44]) - a=z(h,a,b,c,d,X[ 9], 4,t[45]) - d=z(h,d,a,b,c,X[12],11,t[46]) - c=z(h,c,d,a,b,X[15],16,t[47]) - b=z(h,b,c,d,a,X[ 2],23,t[48]) - - a=z(i,a,b,c,d,X[ 0], 6,t[49]) - d=z(i,d,a,b,c,X[ 7],10,t[50]) - c=z(i,c,d,a,b,X[14],15,t[51]) - b=z(i,b,c,d,a,X[ 5],21,t[52]) - a=z(i,a,b,c,d,X[12], 6,t[53]) - d=z(i,d,a,b,c,X[ 3],10,t[54]) - c=z(i,c,d,a,b,X[10],15,t[55]) - b=z(i,b,c,d,a,X[ 1],21,t[56]) - a=z(i,a,b,c,d,X[ 8], 6,t[57]) - d=z(i,d,a,b,c,X[15],10,t[58]) - c=z(i,c,d,a,b,X[ 6],15,t[59]) - b=z(i,b,c,d,a,X[13],21,t[60]) - a=z(i,a,b,c,d,X[ 4], 6,t[61]) - d=z(i,d,a,b,c,X[11],10,t[62]) - c=z(i,c,d,a,b,X[ 2],15,t[63]) - b=z(i,b,c,d,a,X[ 9],21,t[64]) - - return A+a,B+b,C+c,D+d -end - ----------------------------------------------------------------- - -function md5.sumhexa(s) - local msgLen = #s - local padLen = 56 - msgLen % 64 - - if msgLen % 64 > 56 then padLen = padLen + 64 end - - if padLen == 0 then padLen = 64 end - - s = s .. char(128) .. rep(char(0),padLen-1) .. lei2str(8*msgLen) .. lei2str(0) - - assert(#s % 64 == 0) - - local t = CONSTS - local a,b,c,d = t[65],t[66],t[67],t[68] - - for i=1,#s,64 do - local X = cut_le_str(sub(s,i,i+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) - assert(#X == 16) - X[0] = table.remove(X,1) -- zero based! - a,b,c,d = transform(a,b,c,d,X) - end - - return format("%08x%08x%08x%08x",swap(a),swap(b),swap(c),swap(d)) -end - -function md5.sum(s) - return hex2binary(md5.sumhexa(s)) -end - -return md5 diff --git a/client/lualibs/mf_default_keys.lua b/client/lualibs/mf_default_keys.lua index 810f0d6e..4859ff0c 100644 --- a/client/lualibs/mf_default_keys.lua +++ b/client/lualibs/mf_default_keys.lua @@ -141,25 +141,7 @@ local _keys = { '200000000000', 'a00000000000', 'b00000000000', - - --[[ - Should be for Mifare TNP3xxx tags A KEY. - --]] - '4b0b20107ccb', - - --[[ - Kiev metro cards - --]] - '8fe644038790', - 'f14ee7cae863', - '632193be1c3c', - '569369c5a0e5', - '9de89e070277', - 'eff603e1efe9', - '644672bd4afe', - - 'b5ff67cba951', -} + } --- -- The keys above have just been pasted in, for completeness sake. They contain duplicates. diff --git a/client/lualibs/read14a.lua b/client/lualibs/read14a.lua index 10e7c2d4..24021a1d 100644 --- a/client/lualibs/read14a.lua +++ b/client/lualibs/read14a.lua @@ -25,7 +25,6 @@ local ISO14A_COMMAND = { local ISO14443a_TYPES = {} ISO14443a_TYPES[0x00] = "NXP MIFARE Ultralight | Ultralight C" -ISO14443a_TYPES[0x01] = "NXP MIFARE TNP3xxx Activision Game Appliance" ISO14443a_TYPES[0x04] = "NXP MIFARE (various !DESFire !DESFire EV1)" ISO14443a_TYPES[0x08] = "NXP MIFARE CLASSIC 1k | Plus 2k" ISO14443a_TYPES[0x09] = "NXP MIFARE Mini 0.3k" diff --git a/client/lualibs/utils.lua b/client/lualibs/utils.lua index 9b36dfc8..3d27d5b6 100644 --- a/client/lualibs/utils.lua +++ b/client/lualibs/utils.lua @@ -33,86 +33,9 @@ local Utils = return answer end, - - ------------ FILE READING - ReadDumpFile = function (filename) - - if filename == nil then - return nil, 'Filename is empty' - end - if #filename == 0 then - return nil, 'Filename length is zero' - end - - infile = io.open(filename, "rb") - if infile == nil then - return nil, string.format("Could not read file %s",filename) - end - local t = infile:read("*all") - len = string.len(t) - local _,hex = bin.unpack(("H%d"):format(len),t) - io.close(infile) - return hex - end, - - ------------ string split function - Split = function( inSplitPattern, outResults ) - if not outResults then - outResults = {} - end - local start = 1 - local splitStart, splitEnd = string.find( self, inSplitPattern, start ) - while splitStart do - table.insert( outResults, string.sub( self, start, splitStart-1 ) ) - start = splitEnd + 1 - splitStart, splitEnd = string.find( self, inSplitPattern, start ) - end - table.insert( outResults, string.sub( self, start ) ) - return outResults - end, - - ------------ CRC-16 ccitt checksums - - -- Takes a hex string and calculates a crc16 - Crc16 = function(s) - if s == nil then return nil end - if #s == 0 then return nil end - if type(s) == 'string' then - local utils = require('utils') - local asc = utils.ConvertHexToAscii(s) - local hash = core.crc16(asc) - return hash - end - return nil - end, - - -- input parameter is a string - -- Swaps the endianess and returns a number, - -- IE: 'cd7a' -> '7acd' -> 0x7acd - SwapEndianness = function(s, len) - if s == nil then return nil end - if #s == 0 then return '' end - if type(s) ~= 'string' then return nil end - - local retval = 0 - if len == 16 then - local t = s:sub(3,4)..s:sub(1,2) - retval = tonumber(t,16) - elseif len == 24 then - local t = s:sub(5,6)..s:sub(3,4)..s:sub(1,2) - retval = tonumber(t,16) - elseif len == 32 then - local t = s:sub(7,8)..s:sub(5,6)..s:sub(3,4)..s:sub(1,2) - retval = tonumber(t,16) - end - return retval - end, - - ------------ CONVERSIONS - -- -- Converts DECIMAL to HEX - ConvertDecToHex = function(IN) + ConvertDec2Hex = function(IN) local B,K,OUT,I,D=16,"0123456789ABCDEF","",0 while IN>0 do I=I+1 @@ -123,100 +46,12 @@ local Utils = end, --- -- Convert Byte array to string of hex - ConvertBytesToHex = function(bytes) - if #bytes == 0 then - return '' - end - local s={} + ConvertBytes2String = function(bytes) + s = {} for i = 1, #(bytes) do - s[i] = string.format("%02X",bytes[i]) + s[i] = string.format("%02X",bytes[i]) end return table.concat(s) end, - -- Convert byte array to string with ascii - ConvertBytesToAscii = function(bytes) - if #bytes == 0 then - return '' - end - local s={} - for i = 1, #(bytes) do - s[i] = string.char(bytes[i]) - end - return table.concat(s) - end, - ConvertHexToBytes = function(s) - local t={} - if s == nil then return t end - if #s == 0 then return t end - for k in s:gmatch"(%x%x)" do - table.insert(t,tonumber(k,16)) - end - return t - end, - ConvertAsciiToBytes = function(s) - local t={} - if s == nil then return t end - if #s == 0 then return t end - - for k in s:gmatch"(.)" do - table.insert(t, string.byte(k)) - end - return t - end, - ConvertHexToAscii = function(s) - local t={} - if s == nil then return t end - if #s == 0 then return t end - for k in s:gmatch"(%x%x)" do - table.insert(t, string.char(tonumber(k,16))) - end - return table.concat(t) - end, - - -- function convertStringToBytes(str) - -- local bytes = {} - -- local strLength = string.len(str) - -- for i=1,strLength do - -- table.insert(bytes, string.byte(str, i)) - -- end - - -- return bytes --- end - --- function convertBytesToString(bytes) - -- local bytesLength = table.getn(bytes) - -- local str = "" - -- for i=1,bytesLength do - -- str = str .. string.char(bytes[i]) - -- end - - -- return str --- end - --- function convertHexStringToBytes(str) - -- local bytes = {} - -- local strLength = string.len(str) - -- for k=2,strLength,2 do - -- local hexString = "0x" .. string.sub(str, (k - 1), k) - -- table.insert(bytes, hex.to_dec(hexString)) - -- end - - -- return bytes --- end - --- function convertBytesToHexString(bytes) - -- local str = "" - -- local bytesLength = table.getn(bytes) - -- for i=1,bytesLength do - -- local hexString = string.sub(hex.to_hex(bytes[i]), 3) - -- if string.len(hexString) == 1 then - -- hexString = "0" .. hexString - -- end - -- str = str .. hexString - -- end - - -- return str --- end - } return Utils \ No newline at end of file diff --git a/client/mifarehost.c b/client/mifarehost.c index 3516fca4..d025918d 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -72,7 +72,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo uint16_t i, len; uint32_t uid; UsbCommand resp; - + StateList_t statelists[2]; struct Crypto1State *p1, *p2, *p3, *p4; @@ -216,7 +216,7 @@ int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) { UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}}; SendCommand(&c); - UsbCommand resp; + UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) return 1; memcpy(data, resp.d.asBytes, blocksCount * 16); return 0; @@ -250,7 +250,7 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uin memcpy(c.d.asBytes, data, 16); SendCommand(&c); - UsbCommand resp; + UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { isOK = resp.arg[0] & 0xff; if (uid != NULL) memcpy(uid, resp.d.asBytes, 4); @@ -339,10 +339,10 @@ int loadTraceCard(uint8_t *tuid) { while(!feof(f)){ memset(buf, 0, sizeof(buf)); if (fgets(buf, sizeof(buf), f) == NULL) { - PrintAndLog("File reading error."); + PrintAndLog("File reading error."); fclose(f); return 2; - } + } if (strlen(buf) < 32){ if (feof(f)) break; @@ -440,7 +440,7 @@ int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile) { } // AUTHENTICATION - if ((len == 4) && ((data[0] == 0x60) || (data[0] == 0x61))) { + if ((len ==4) && ((data[0] == 0x60) || (data[0] == 0x61))) { traceState = TRACE_AUTH1; traceCurBlock = data[1]; traceCurKey = data[0] == 60 ? 1:0; diff --git a/client/nonce2key/crapto1.c b/client/nonce2key/crapto1.c index c2dd7a54..61215420 100644 --- a/client/nonce2key/crapto1.c +++ b/client/nonce2key/crapto1.c @@ -545,10 +545,11 @@ 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? if(!statelist || !odd || !even) { - free(statelist); - free(odd); - free(even); - return 0; + free(statelist); + free(odd); + free(even); + return 0; + } s = statelist; diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index 3e9bdfd5..a820fe41 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -280,7 +280,7 @@ void ProxWidget::paintEvent(QPaintEvent *event) ProxWidget::ProxWidget(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoint(1) { - resize(600, 300); + resize(600, 500); QPalette palette(QColor(0,0,0,0)); palette.setColor(QPalette::WindowText, QColor(255,255,255)); diff --git a/client/proxmark3.c b/client/proxmark3.c index 4b463f1d..16a8fa02 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -47,7 +47,7 @@ void SendCommand(UsbCommand *c) { PrintAndLog("Sending bytes to proxmark failed - offline"); return; } - /** + /** The while-loop below causes hangups at times, when the pm3 unit is unresponsive or disconnected. The main console thread is alive, but comm thread just spins here. Not good.../holiman diff --git a/client/proxmark3.h b/client/proxmark3.h index a634fd68..8236bfe7 100644 --- a/client/proxmark3.h +++ b/client/proxmark3.h @@ -20,7 +20,7 @@ #include "usb_cmd.h" -#define PROXPROMPT "pm3 --> " +#define PROXPROMPT "proxmark3> " void SendCommand(UsbCommand *c); diff --git a/client/scripting.c b/client/scripting.c index cc59f995..963bb64c 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -18,8 +18,6 @@ #include "util.h" #include "nonce2key/nonce2key.h" #include "../common/iso15693tools.h" -#include -#include "../common/crc16.h" /** * The following params expected: * UsbCommand c @@ -226,54 +224,6 @@ static int l_iso15693_crc(lua_State *L) return 1; } -/* - Simple AES 128 cbc hook up to OpenSSL. - params: key, input -*/ -static int l_aes(lua_State *L) -{ - //Check number of arguments - int i; - size_t size; - const char *p_key = luaL_checklstring(L, 1, &size); - if(size != 32) return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size); - - const char *p_encTxt = luaL_checklstring(L, 2, &size); - - unsigned char indata[AES_BLOCK_SIZE] = {0x00}; - unsigned char outdata[AES_BLOCK_SIZE] = {0x00}; - unsigned char aes_key[AES_BLOCK_SIZE] = {0x00}; - unsigned char iv[AES_BLOCK_SIZE] = {0x00}; - - // convert key to bytearray - for (i = 0; i < 32; i += 2) { - sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]); - } - - // convert input to bytearray - for (i = 0; i < 32; i += 2) { - sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]); - } - - AES_KEY key; - AES_set_decrypt_key(aes_key, 128, &key); - AES_cbc_encrypt(indata, outdata, sizeof(indata), &key, iv, AES_DECRYPT); - - //Push decrypted array as a string - lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); - return 1;// return 1 to signal one return value -} - -static int l_crc16(lua_State *L) -{ - size_t size; - 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; -} - /** * @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be * able to do "require('foobar')" if foobar.lua is within lualibs folder. @@ -309,10 +259,8 @@ int set_pm3_libraries(lua_State *L) {"foobar", l_foobar}, {"ukbhit", l_ukbhit}, {"clearCommandBuffer", l_clearCommandBuffer}, - {"console", l_CmdConsole}, - {"iso15693_crc", l_iso15693_crc}, - {"aes", l_aes}, - {"crc16", l_crc16}, + {"console", l_CmdConsole}, + {"iso15693_crc", l_iso15693_crc}, {NULL, NULL} }; diff --git a/client/scripts/formatMifare.lua b/client/scripts/formatMifare.lua index 66a61fba..1ced0c28 100644 --- a/client/scripts/formatMifare.lua +++ b/client/scripts/formatMifare.lua @@ -80,20 +80,18 @@ function GetCardInfo() core.clearCommandBuffer() - if 0x18 == result.sak then -- NXP MIFARE Classic 4k | Plus 4k + if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k -- IFARE Classic 4K offers 4096 bytes split into forty sectors, -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. numSectors = 40 - elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k + elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k -- 1K offers 1024 bytes of data storage, split into 16 sector numSectors = 16 - elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k + elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k -- MIFARE Classic mini offers 320 bytes split into five sectors. numSectors = 5 - elseif 0x10 == result.sak then -- NXP MIFARE Plus 2k + elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k" numSectors = 32 - elseif 0x01 == sak then -- NXP MIFARE TNP3xxx 1K - numSectors = 16 else print("I don't know how many sectors there are on this type of card, defaulting to 16") end diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index eb98ffbf..8d0d358f 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -133,8 +133,6 @@ function nested(key,sak) typ = 0 elseif 0x10 == sak then-- "NXP MIFARE Plus 2k" typ = 2 - elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K" - typ = 1 else print("I don't know how many sectors there are on this type of card, defaulting to 16") end diff --git a/client/scripts/tnp3dump.lua b/client/scripts/tnp3dump.lua deleted file mode 100644 index 520161b9..00000000 --- a/client/scripts/tnp3dump.lua +++ /dev/null @@ -1,272 +0,0 @@ -local cmds = require('commands') -local getopt = require('getopt') -local bin = require('bin') -local lib14a = require('read14a') -local utils = require('utils') -local md5 = require('md5') -local dumplib = require('html_dumplib') -local toyNames = require('default_toys') - -example =[[ - 1. script run tnp3dump - 2. script run tnp3dump -n - 3. script run tnp3dump -k aabbccddeeff - 4. script run tnp3dump -k aabbccddeeff -n - 5. script run tnp3dump -o myfile - 6. script run tnp3dump -n -o myfile - 7. script run tnp3dump -k aabbccddeeff -n -o myfile -]] -author = "Iceman" -usage = "script run tnp3dump -k -n -o " -desc =[[ -This script will try to dump the contents of a Mifare TNP3xxx card. -It will need a valid KeyA in order to find the other keys and decode the card. -Arguments: - -h : this help - -k : Sector 0 Key A. - -n : Use the nested cmd to find all keys - -o : filename for the saved dumps -]] - -local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' - -local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds -local DEBUG = false -- the debug flag -local numBlocks = 64 -local numSectors = 16 ---- --- A debug printout-function -function dbg(args) - if not DEBUG then - return - end - - if type(args) == "table" then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print("###", args) - end -end ---- --- This is only meant to be used when errors occur -function oops(err) - print("ERROR: ",err) -end ---- --- Usage help -function help() - print(desc) - print("Example usage") - print(example) -end --- --- Exit message -function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() -end - -local function readdumpkeys(infile) - t = infile:read("*all") - len = string.len(t) - local len,hex = bin.unpack(("H%d"):format(len),t) - return hex -end - -local function waitCmd() - local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) - if response then - local count,cmd,arg0 = bin.unpack('LL',response) - if(arg0==1) then - local count,arg1,arg2,data = bin.unpack('LLH511',response,count) - return data:sub(1,32) - else - return nil, "Couldn't read block.." - end - end - return nil, "No response from device" -end - -local function computeCrc16(s) - local hash = core.crc16(utils.ConvertHexToAscii(s)) - return hash -end - -local function reverseCrcBytes(crc) - crc2 = crc:sub(3,4)..crc:sub(1,2) - return tonumber(crc2,16) -end - -local function main(args) - - print( string.rep('--',20) ) - print( string.rep('--',20) ) - - local keyA - local cmd - local err - local useNested = false - local cmdReadBlockString = 'hf mf rdbl %d A %s' - local input = "dumpkeys.bin" - local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S"); - - -- Arguments for the script - for o, a in getopt.getopt(args, 'hk:no:') do - if o == "h" then return help() end - if o == "k" then keyA = a end - if o == "n" then useNested = true end - if o == "o" then outputTemplate = a end - end - - -- validate input args. - keyA = keyA or '4b0b20107ccb' - if #(keyA) ~= 12 then - return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA)) - end - - -- Turn off Debug - local cmdSetDbgOff = "hf mf dbg 0" - core.console( cmdSetDbgOff) - - result, err = lib14a.read1443a(false) - if not result then - return oops(err) - end - - core.clearCommandBuffer() - - if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx - return oops('This is not a TNP3xxx tag. aborting.') - end - - -- Show tag info - print((' Found tag : %s'):format(result.name)) - print(('Using keyA : %s'):format(keyA)) - - --Trying to find the other keys - if useNested then - core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) - end - - core.clearCommandBuffer() - - -- Loading keyfile - print('Loading dumpkeys.bin') - local hex, err = utils.ReadDumpFile(input) - if not hex then - return oops(err) - end - - local akeys = hex:sub(0,12*16) - - -- Read block 0 - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA} - err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local block0, err = waitCmd() - if err then return oops(err) end - - -- Read block 1 - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1,arg2 = 0,arg3 = 0, data = keyA} - err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local block1, err = waitCmd() - if err then return oops(err) end - - local key - local pos = 0 - local blockNo - local blocks = {} - - print('Reading card data') - core.clearCommandBuffer() - - -- main loop - io.write('Decrypting blocks > ') - for blockNo = 0, numBlocks-1, 1 do - - if core.ukbhit() then - print("aborted by user") - break - end - - pos = (math.floor( blockNo / 4 ) * 12)+1 - key = akeys:sub(pos, pos + 11 ) - cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key} - local err = core.SendCommand(cmd:getBytes()) - if err then return oops(err) end - local blockdata, err = waitCmd() - if err then return oops(err) end - - if blockNo%4 ~= 3 then - if blockNo < 8 then - -- Block 0-7 not encrypted - blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) - else - local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT) - local baseStr = utils.ConvertHexToAscii(base) - local md5hash = md5.sumhexa(baseStr) - local aestest = core.aes(md5hash, blockdata) - - local hex = utils.ConvertAsciiToBytes(aestest) - hex = utils.ConvertBytesToHex(hex) - - -- blocks with zero not encrypted. - if string.find(blockdata, '^0+$') then - blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) - else - blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) - io.write( blockNo..',') - end - end - else - -- Sectorblocks, not encrypted - blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32)) - end - end - io.write('\n') - - core.clearCommandBuffer() - - -- Print results - local bindata = {} - local emldata = '' - - for _,s in pairs(blocks) do - local slice = s:sub(8,#s) - local str = utils.ConvertBytesToAscii( - utils.ConvertHexToBytes(slice) - ) - emldata = emldata..slice..'\n' - for c in (str):gmatch('.') do - bindata[#bindata+1] = c - end - end - - -- Write dump to files - if not DEBUG then - local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'.bin') - print(("Wrote a BIN dump to the file %s"):format(foo)) - local bar = dumplib.SaveAsText(emldata, outputTemplate..'.eml') - print(("Wrote a EML dump to the file %s"):format(bar)) - end - - local uid = block0:sub(1,8) - local itemtype = block1:sub(1,4) - local cardid = block1:sub(9,24) - - -- Show info - print( string.rep('--',20) ) - print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) ) - print( (' UID : 0x%s'):format(uid) ) - print( (' CARDID : 0x%s'):format(cardid ) ) - print( string.rep('--',20) ) - -end -main(args) \ No newline at end of file diff --git a/client/scripts/tnp3sim.lua b/client/scripts/tnp3sim.lua deleted file mode 100644 index f43dafa2..00000000 --- a/client/scripts/tnp3sim.lua +++ /dev/null @@ -1,355 +0,0 @@ -local cmds = require('commands') -local getopt = require('getopt') -local bin = require('bin') -local lib14a = require('read14a') -local utils = require('utils') -local md5 = require('md5') -local toyNames = require('default_toys') - -example =[[ - 1. script run tnp3sim - 2. script run tnp3sim -m - 3. script run tnp3sim -m -i myfile -]] -author = "Iceman" -usage = "script run tnp3sim -h -m -i " -desc =[[ -This script will try to load a binary datadump of a Mifare TNP3xxx card. -It vill try to validate all checksums and view some information stored in the dump -For an experimental mode, it tries to manipulate some data. -At last it sends all data to the PM3 device memory where it can be used in the command "hf mf sim" - -Arguments: - -h : this help - -m : Maxed out items (experimental) - -i : filename for the datadump to read (bin) -]] - -local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds -local DEBUG = true -- the debug flag ---- --- A debug printout-function -function dbg(args) - if not DEBUG then - return - end - - if type(args) == "table" then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print("###", args) - end -end ---- --- This is only meant to be used when errors occur -function oops(err) - print("ERROR: ",err) -end ---- --- Usage help -function help() - print(desc) - print("Example usage") - print(example) -end --- --- Exit message -function ExitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() -end - - -local function writedumpfile(infile) - t = infile:read("*all") - len = string.len(t) - local len,hex = bin.unpack(("H%d"):format(len),t) - return hex -end --- blocks with data --- there are two dataareas, in block 8 or block 36, ( 1==8 , --- checksum type = 0, 1, 2, 3 -local function GetCheckSum(blocks, dataarea, chksumtype) - - local crc - local area = 36 - if dataarea == 1 then - area = 8 - end - - if chksumtype == 0 then - crc = blocks[1]:sub(29,32) - elseif chksumtype == 1 then - crc = blocks[area]:sub(29,32) - elseif chksumtype == 2 then - crc = blocks[area]:sub(25,28) - elseif chksumtype == 3 then - crc = blocks[area]:sub(21,24) - end - return utils.SwapEndianness(crc,16) -end - -local function SetCheckSum(blocks, chksumtype) - - if blocks == nil then return nil, 'Argument \"blocks\" nil' end - local newcrc - local area1 = 8 - local area2 = 36 - - if chksumtype == 0 then - newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0)) - blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) - elseif chksumtype == 1 then - newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1)) - blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) - newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1)) - blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2) - elseif chksumtype == 2 then - newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2)) - blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32) - newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2)) - blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32) - elseif chksumtype == 3 then - newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3)) - blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32) - newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3)) - blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32) - end -end - -function CalcCheckSum(blocks, dataarea, chksumtype) - local area = 36 - if dataarea == 1 then - area = 8 - end - - if chksumtype == 0 then - data = blocks[0]..blocks[1]:sub(1,28) - elseif chksumtype == 1 then - data = blocks[area]:sub(1,28)..'0500' - elseif chksumtype == 2 then - data = blocks[area+1]..blocks[area+2]..blocks[area+4] - elseif chksumtype == 3 then - data = blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0) - end - return utils.Crc16(data) -end - -local function ValidateCheckSums(blocks) - - local isOk, crc, calc - -- Checksum Type 0 - crc = GetCheckSum(blocks,1,0) - calc = CalcCheckSum(blocks, 1, 0) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 0 : %04x = %04x -- %s\n'):format(crc,calc,isOk)) - - -- Checksum Type 1 (DATAAREAHEADER 1) - crc = GetCheckSum(blocks,1,1) - calc = CalcCheckSum(blocks,1,1) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - - -- Checksum Type 1 (DATAAREAHEADER 2) - crc = GetCheckSum(blocks,2,1) - calc = CalcCheckSum(blocks,2,1) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - - -- Checksum Type 2 (DATAAREA 1) - crc = GetCheckSum(blocks,1,2) - calc = CalcCheckSum(blocks,1,2) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - - -- Checksum Type 2 (DATAAREA 2) - crc = GetCheckSum(blocks,2,2) - calc = CalcCheckSum(blocks,2,2) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - - -- Checksum Type 3 (DATAAREA 1) - crc = GetCheckSum(blocks,1,3) - calc = CalcCheckSum(blocks,1,3) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk)) - - -- Checksum Type 3 (DATAAREA 2) - crc = GetCheckSum(blocks,2,3) - calc = CalcCheckSum(blocks,2,3) - if crc == calc then isOk='Ok' else isOk = 'Error' end - io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) -end - - -local function LoadEmulator(blocks) - local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' - local cmd - local blockdata - for _,b in pairs(blocks) do - - blockdata = b - - if _%4 ~= 3 then - if (_ >= 8 and _<=21) or (_ >= 36 and _<=49) then - local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , HASHCONSTANT) - local baseStr = utils.ConvertHexToAscii(base) - local key = md5.sumhexa(baseStr) - local enc = core.aes(key, blockdata) - local hex = utils.ConvertAsciiToBytes(enc) - hex = utils.ConvertBytesToHex(hex) - - blockdata = hex - io.write( _..',') - end - end - - cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 0, data = blockdata} - local err = core.SendCommand(cmd:getBytes()) - if err then - return err - end - end - io.write('\n') -end - -local function main(args) - - print( string.rep('--',20) ) - print( string.rep('--',20) ) - - local result, err, hex - local maxed = false - local inputTemplate = "dumpdata.bin" - local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M"); - - -- Arguments for the script - for o, a in getopt.getopt(args, 'hmi:o:') do - if o == "h" then return help() end - if o == "m" then maxed = true end - if o == "o" then outputTemplate = a end - if o == "i" then inputTemplate = a end - end - - -- Turn off Debug - local cmdSetDbgOff = "hf mf dbg 0" - core.console( cmdSetDbgOff) - - -- Look for tag present on reader, - result, err = lib14a.read1443a(false) - if not result then return oops(err) end - - core.clearCommandBuffer() - - if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx - return oops('This is not a TNP3xxx tag. aborting.') - end - - -- Show tag info - print((' Found tag : %s'):format(result.name)) - - -- Load dump.bin file - print( (' Load data from %s'):format(inputTemplate)) - hex, err = utils.ReadDumpFile(inputTemplate) - if not hex then return oops(err) end - - local blocks = {} - local blockindex = 0 - for i = 1, #hex, 32 do - blocks[blockindex] = hex:sub(i,i+31) - blockindex = blockindex + 1 - end - - if DEBUG then - print('Validating checksums in the loaded datadump') - ValidateCheckSums(blocks) - end - - -- - print( string.rep('--',20) ) - print(' Gathering info') - local uid = blocks[0]:sub(1,8) - local itemtype = blocks[1]:sub(1,4) - local cardid = blocks[1]:sub(9,24) - - -- Show info - print( string.rep('--',20) ) - print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) ) - print( (' UID : 0x%s'):format(uid) ) - print( (' CARDID : 0x%s'):format(cardid ) ) - print( string.rep('--',20) ) - - -- lets do something. - -- - local experience = blocks[8]:sub(1,6) - print(('Experience : %d'):format(utils.SwapEndianness(experience,24))) - local money = blocks[8]:sub(7,10) - print(('Money : %d'):format(utils.SwapEndianness(money,16))) - local fairy = blocks[9]:sub(1,8) - --FD0F = Left, FF0F = Right - local path = 'not choosen' - if fairy:sub(2,2) == 'D' then - path = 'Left' - elseif fairy:sub(2,2) == 'F' then - path = 'Right' - end - print(('Fairy : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path)) - - local hat = blocks[9]:sub(8,11) - print(('Hat : %d'):format(utils.SwapEndianness(hat,16))) - - --0x0D 0x29 0x0A 0x02 16-bit hero points value. Maximum 100. - local heropoints = blocks[13]:sub(20,23) - print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16))) - - --0x10 0x2C 0x0C 0x04 32 bit flag value indicating heroic challenges completed. - local challenges = blocks[16]:sub(25,32) - print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32))) - - if maxed then - print('Lets try to max out some values') - -- max out money, experience - --print (blocks[8]) - blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32) - blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32) - --print (blocks[8]) - - -- max out hero challenges - --print (blocks[16]) - blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF' - blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF' - --print (blocks[16]) - - -- max out heropoints - --print (blocks[13]) - blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32) - blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32) - --print (blocks[13]) - - -- Update Checksums - print('Updating all checksums') - SetCheckSum(blocks, 3) - SetCheckSum(blocks, 2) - SetCheckSum(blocks, 1) - SetCheckSum(blocks, 0) - - print('Validating all checksums') - ValidateCheckSums(blocks) - end - - --Load dumpdata to emulator memory - if DEBUG then - print('Sending dumpdata to emulator memory') - err = LoadEmulator(blocks) - if err then return oops(err) end - core.clearCommandBuffer() - print('The simulation is now prepared.\n --> run \"hf mf sim 5 '..uid..'\" <--') - end -end -main(args) \ No newline at end of file diff --git a/client/ui.c b/client/ui.c index e464a533..c0d01bc3 100644 --- a/client/ui.c +++ b/client/ui.c @@ -12,22 +12,16 @@ #include #include #include -#include #include #include #include -#include "loclass/cipherutils.h" + #include "ui.h" -#include "cmdmain.h" -#include "cmddata.h" -#include "graph.h" -//#include -#define M_PI 3.14159265358979323846264338327 double CursorScaleFactor; int PlotGridX, PlotGridY, PlotGridXdefault= 64, PlotGridYdefault= 64; int offline; -int flushAfterWrite = 0; +int flushAfterWrite = 0; //buzzy extern pthread_mutex_t print_lock; static char *logfilename = "proxmark3.log"; @@ -38,13 +32,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; @@ -83,401 +77,16 @@ void PrintAndLog(char *fmt, ...) } va_end(argptr2); - if (flushAfterWrite == 1) { + if (flushAfterWrite == 1) //buzzy + { 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 = GetClock("", 0); - - 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){ - - PrintAndLog(" Path B"); - - 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 60)? 100:0; - } - } - - for (j=0; j 0)? 10 : -10; - } - - // show data - for (j=0; j0 ? 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; -} diff --git a/client/ui.h b/client/ui.h index 6a45fcfd..a45799d5 100644 --- a/client/ui.h +++ b/client/ui.h @@ -11,10 +11,6 @@ #ifndef UI_H__ #define UI_H__ -#include -#include -#include "util.h" - void ShowGui(void); void HideGraphWindow(void); void ShowGraphWindow(void); @@ -27,13 +23,4 @@ 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 diff --git a/client/util.c b/client/util.c index b8d5c316..15e911a1 100644 --- a/client/util.c +++ b/client/util.c @@ -13,7 +13,6 @@ #ifndef _WIN32 #include #include - int ukbhit(void) { int cnt = 0; @@ -46,18 +45,12 @@ int ukbhit(void) { #endif // log files functions -void AddLogLine(char *file, char *extData, char *c) { +void AddLogLine(char *fileName, char *extData, char *c) { FILE *fLog = NULL; - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; - len = strlen(file); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, file, len); - - fLog = fopen(filename, "a"); + fLog = fopen(fileName, "a"); if (!fLog) { - printf("Could not append log file %s", filename); + printf("Could not append log file %s", fileName); return; } @@ -109,31 +102,16 @@ void print_hex(const uint8_t * data, const size_t len) } char * sprint_hex(const uint8_t * data, const size_t len) { - - int maxLen = ( len > 1024/3) ? 1024/3 : len; static char buf[1024]; char * tmp = buf; size_t i; - for (i=0; i < maxLen; ++i, tmp += 3) + for (i=0; i < len && i < 1024/3; i++, tmp += 3) sprintf(tmp, "%02x ", data[i]); return buf; } -char * sprint_bin(const uint8_t * data, const size_t len) { - - int maxLen = ( len > 1024) ? 1024 : len; - static char buf[1024]; - char * tmp = buf; - size_t i; - - for (i=0; i < maxLen; ++i, ++tmp) - sprintf(tmp, "%u", data[i]); - - return buf; -} - void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { @@ -153,28 +131,6 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } -//assumes little endian -char * printBits(size_t const size, void const * const ptr) -{ - unsigned char *b = (unsigned char*) ptr; - unsigned char byte; - static char buf[1024]; - char * tmp = buf; - int i, j; - - for (i=size-1;i>=0;i--) - { - for (j=7;j>=0;j--) - { - byte = b[i] & (1<>= j; - sprintf(tmp, "%u", byte); - tmp++; - } - } - return buf; -} - // ------------------------------------------------------------------------- // string parameters lib // ------------------------------------------------------------------------- @@ -292,102 +248,3 @@ int param_getstr(const char *line, int paramnum, char * str) return en - bg + 1; } - -/* -The following methods comes from Rfidler sourcecode. -https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/ -*/ - -// convert hex to sequence of 0/1 bit values -// returns number of bits converted -int hextobinarray(char *target, char *source) -{ - int length, i, count= 0; - char x; - - length = strlen(source); - // process 4 bits (1 hex digit) at a time - while(length--) - { - x= *(source++); - // capitalize - if (x >= 'a' && x <= 'f') - x -= 32; - // convert to numeric value - if (x >= '0' && x <= '9') - x -= '0'; - else if (x >= 'A' && x <= 'F') - x -= 'A' - 10; - else - return 0; - // output - for(i= 0 ; i < 4 ; ++i, ++count) - *(target++)= (x >> (3 - i)) & 1; - } - - return count; -} - -// convert hex to human readable binary string -int hextobinstring(char *target, char *source) -{ - int length; - - if(!(length= hextobinarray(target, source))) - return 0; - binarraytobinstring(target, target, length); - return length; -} - -// 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) -{ - unsigned char i, x; - int j = length; - - if(j % 4) - return 0; - - while(j) - { - for(i= x= 0 ; i < 4 ; ++i) - x += ( source[i] << (3 - i)); - sprintf(target,"%X", x); - ++target; - source += 4; - j -= 4; - } - return length; -} - -// convert binary array to human readable binary -void binarraytobinstring(char *target, char *source, int length) -{ - int i; - - for(i= 0 ; i < length ; ++i) - *(target++)= *(source++) + '0'; - *target= '\0'; -} - -// return parity bit required to match type -uint8_t GetParity( char *bits, uint8_t type, int length) -{ - int x; - - for(x= 0 ; length > 0 ; --length) - x += bits[length - 1]; - x %= 2; - - return x ^ type; -} - -// add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half -void wiegand_add_parity(char *target, char *source, char length) -{ - *(target++)= GetParity(source, EVEN, length / 2); - memcpy(target, source, length); - target += length; - *(target)= GetParity(source + length / 2, ODD, length / 2); -} diff --git a/client/util.h b/client/util.h index 22d41e0c..ce8876ed 100644 --- a/client/util.h +++ b/client/util.h @@ -15,7 +15,6 @@ #include #include #include -#include "data.h" #ifndef MIN # define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -23,10 +22,6 @@ #ifndef MAX # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif -#define TRUE 1 -#define FALSE 0 -#define EVEN 0 -#define ODD 1 int ukbhit(void); @@ -38,11 +33,9 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount); void print_hex(const uint8_t * data, const size_t len); char * sprint_hex(const uint8_t * data, const size_t len); -char * sprint_bin(const uint8_t * data, const size_t len); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); -char * printBits(size_t const size, void const * const ptr); char param_getchar(const char *line, int paramnum); uint8_t param_get8(const char *line, int paramnum); @@ -52,10 +45,3 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base); int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt); int param_getstr(const char *line, int paramnum, char * str); - int hextobinarray( char *target, char *source); - int hextobinstring( char *target, char *source); - int binarraytohex( char *target, char *source, int length); -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); - diff --git a/common/Makefile.common b/common/Makefile.common index b30294a8..2befd456 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -54,8 +54,7 @@ DELETE=del /q MOVE=ren COPY=copy PATHSEP=\\# -#FLASH_TOOL=winsrc\\prox.exe -FLASH_TOOL=winsrc\\flash.exe +FLASH_TOOL=winsrc\\prox.exe DETECTED_OS=Windows endif @@ -68,8 +67,7 @@ INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gp CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 $(APP_CFLAGS) -Os LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n - -LIBS = -lgcc +LIBS = -lgcc THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(THUMBSRC)) ARMOBJ = $(ARMSRC:%.c=$(OBJDIR)/%.o) diff --git a/common/cmd.c b/common/cmd.c index 66b93990..49d9d942 100644 --- a/common/cmd.c +++ b/common/cmd.c @@ -32,7 +32,9 @@ #include "cmd.h" #include "string.h" -#include "../include/proxmark3.h" +#include "proxmark3.h" + +//static UsbCommand txcmd; bool cmd_receive(UsbCommand* cmd) { diff --git a/common/cmd.h b/common/cmd.h index 35885de4..b330a219 100644 --- a/common/cmd.h +++ b/common/cmd.h @@ -33,8 +33,8 @@ #ifndef _PROXMARK_CMD_H_ #define _PROXMARK_CMD_H_ -#include "../include/common.h" -#include "../include/usb_cmd.h" +#include +#include #include "usb_cdc.h" bool cmd_receive(UsbCommand* cmd); diff --git a/common/crc.h b/common/crc.h deleted file mode 100644 index 8e68f3b3..00000000 --- a/common/crc.h +++ /dev/null @@ -1,48 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// Generic CRC calculation code. -//----------------------------------------------------------------------------- - -#ifndef __CRC_H -#define __CRC_H - -#include - -typedef struct crc { - uint32_t state; - int order; - uint32_t polynom; - uint32_t initial_value; - uint32_t final_xor; - uint32_t mask; -} crc_t; - -/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32 - * polynom is the CRC polynom. initial_value is the initial value of a clean state. - * final_xor is XORed onto the state before returning it from crc_result(). */ -extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor); - -/* Update the crc state. data is the data of length data_width bits (only the the - * data_width lower-most bits are used). - */ -extern void crc_update(crc_t *crc, uint32_t data, int data_width); - -/* Clean the crc state, e.g. reset it to initial_value */ -extern void crc_clear(crc_t *crc); - -/* Get the result of the crc calculation */ -extern uint32_t crc_finish(crc_t *crc); - -/* Static initialization of a crc structure */ -#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \ - .state = ((_initial_value) & ((1L<<(_order))-1)), \ - .order = (_order), \ - .polynom = (_polynom), \ - .initial_value = (_initial_value), \ - .final_xor = (_final_xor), \ - .mask = ((1L<<(_order))-1) } - -#endif /* __CRC_H */ diff --git a/common/crc16.c b/common/crc16.c index 973cd103..d181bb2a 100644 --- a/common/crc16.c +++ b/common/crc16.c @@ -8,7 +8,6 @@ #include "crc16.h" - unsigned short update_crc16( unsigned short crc, unsigned char c ) { unsigned short i, v, tcrc = 0; @@ -21,25 +20,3 @@ unsigned short update_crc16( unsigned short crc, unsigned char c ) 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; -} - -uint16_t crc16_ccitt(uint8_t const *message, int length) { - return crc16(message, length, 0xffff, 0x1021); -} diff --git a/common/crc16.h b/common/crc16.h index d16d83b5..055a60bc 100644 --- a/common/crc16.h +++ b/common/crc16.h @@ -5,11 +5,10 @@ //----------------------------------------------------------------------------- // CRC16 //----------------------------------------------------------------------------- -#include #ifndef __CRC16_H #define __CRC16_H + unsigned short update_crc16(unsigned short crc, unsigned char c); -uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial); -uint16_t crc16_ccitt(uint8_t const *message, int length); + #endif diff --git a/common/crc32.c b/common/crc32.c deleted file mode 100644 index 69d770f4..00000000 --- a/common/crc32.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include "crc32.h" - -#define htole32(x) (x) -#define CRC32_PRESET 0xFFFFFFFF - - -static void crc32_byte (uint32_t *crc, const uint8_t value); - -static void crc32_byte (uint32_t *crc, const uint8_t value) { - /* x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 */ - const uint32_t poly = 0xEDB88320; - - *crc ^= value; - for (int current_bit = 7; current_bit >= 0; current_bit--) { - int bit_out = (*crc) & 0x00000001; - *crc >>= 1; - if (bit_out) - *crc ^= poly; - } -} - -void crc32 (const uint8_t *data, const size_t len, uint8_t *crc) { - uint32_t desfire_crc = CRC32_PRESET; - for (size_t i = 0; i < len; i++) { - crc32_byte (&desfire_crc, data[i]); - } - - *((uint32_t *)(crc)) = htole32 (desfire_crc); -} - -void crc32_append (uint8_t *data, const size_t len) { - crc32 (data, len, data + len); -} diff --git a/common/crc32.h b/common/crc32.h deleted file mode 100644 index 0dd2a328..00000000 --- a/common/crc32.h +++ /dev/null @@ -1,15 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// CRC32 -//----------------------------------------------------------------------------- - -#ifndef __CRC32_H -#define __CRC32_H - -void crc32 (const uint8_t *data, const size_t len, uint8_t *crc); -void crc32_append (uint8_t *data, const size_t len); - -#endif diff --git a/common/desfire.h b/common/desfire.h deleted file mode 100644 index c163c5c5..00000000 --- a/common/desfire.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef __DESFIRE_H -#define __DESFIRE_H - -#include -#include - -#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 - diff --git a/common/iso14443crc.c b/common/iso14443crc.c index 851546ae..a6def1a9 100644 --- a/common/iso14443crc.c +++ b/common/iso14443crc.c @@ -6,7 +6,7 @@ // ISO14443 CRC calculation code. //----------------------------------------------------------------------------- -#include "../common/iso14443crc.h" +#include "iso14443crc.h" static unsigned short UpdateCrc14443(unsigned char ch, unsigned short *lpwCrc) { diff --git a/common/iso14443crc.h b/common/iso14443crc.h index 80941116..87347714 100644 --- a/common/iso14443crc.h +++ b/common/iso14443crc.h @@ -8,7 +8,7 @@ #ifndef __ISO14443CRC_H #define __ISO14443CRC_H -#include "../include/common.h" +#include "common.h" //----------------------------------------------------------------------------- // Routines to compute the CRCs (two different flavours, just for confusion) diff --git a/common/iso15693tools.c b/common/iso15693tools.c index 0ec5492b..26e636ca 100644 --- a/common/iso15693tools.c +++ b/common/iso15693tools.c @@ -7,7 +7,7 @@ //----------------------------------------------------------------------------- -#include "../include/proxmark3.h" +#include "proxmark3.h" #include #include //#include "iso15693tools.h" diff --git a/common/legic_prng.c b/common/legic_prng.c index 322429ad..4f3b1ffe 100644 --- a/common/legic_prng.c +++ b/common/legic_prng.c @@ -6,7 +6,7 @@ // LEFIC's obfuscation function //----------------------------------------------------------------------------- -#include "../include/legic_prng.h" +#include "legic_prng.h" struct lfsr { uint8_t a; diff --git a/common/lfdemod.c b/common/lfdemod.c index eb5a4d95..79c99f73 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -8,656 +8,626 @@ // Low frequency commands //----------------------------------------------------------------------------- -#include #include #include #include "lfdemod.h" //by marshmellow //takes 1s and 0s and searches for EM410x format - output EM ID -uint64_t Em410xDecode(uint8_t *BitStream, uint32_t BitLen) +uint64_t Em410xDecode(uint8_t *BitStream,uint32_t BitLen) { - //no arguments needed - built this way in case we want this to be a direct call from "data " cmds in the future - // otherwise could be a void with no arguments - //set defaults - int high = 0, low = 128; - uint64_t lo = 0; - uint32_t i = 0; - uint32_t initLoopMax = 65; + //no arguments needed - built this way in case we want this to be a direct call from "data " cmds in the future + // otherwise could be a void with no arguments + //set defaults + int high=0, low=128; + uint64_t lo=0; //hi=0, - if (initLoopMax > BitLen) - initLoopMax = BitLen; + uint32_t i = 0; + uint32_t initLoopMax = 65; + if (initLoopMax>BitLen) initLoopMax=BitLen; - for (; i < initLoopMax; ++i) //65 samples should be plenty to find high and low values - { - if (BitStream[i] > high) - high = BitStream[i]; - else if (BitStream[i] < low) - low = BitStream[i]; - } - - if (((high !=1)||(low !=0))){ //allow only 1s and 0s - return 0; - } - - uint8_t parityTest = 0; - // 111111111 bit pattern represent start of frame - uint8_t frame_marker_mask[] = {1,1,1,1,1,1,1,1,1}; - uint32_t idx = 0; - uint32_t j = 0; - uint8_t resetCnt = 0; - while( (idx + 64) < BitLen) { - - restart: - - // search for a start of frame marker - if ( memcmp(BitStream+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) { - // frame marker found - idx += 9;//sizeof(frame_marker_mask); - for ( i = 0; i < 10; ++i){ - for( j = 0; j < 5; ++j){ - parityTest += BitStream[(i*5) + j + idx]; - } - if (parityTest == ( (parityTest >> 1) << 1)){ - parityTest = 0; - for (j = 0; j < 4; ++j){ - lo = ( lo << 1LL)|( BitStream[( i * 5 ) + j + idx]); - } - } else { - //parity failed - parityTest = 0; - idx -= 8; - if (resetCnt > 5) return 0; - resetCnt++; - goto restart;//continue; - } - } - //skip last 5 bit parity test for simplicity. - return lo; - } else { - idx++; - } - } - return 0; + for (;i < initLoopMax; ++i) //65 samples should be plenty to find high and low values + { + if (BitStream[i] > high) + high = BitStream[i]; + else if (BitStream[i] < low) + low = BitStream[i]; + } + if (((high !=1)||(low !=0))){ //allow only 1s and 0s + // PrintAndLog("no data found"); + return 0; + } + uint8_t parityTest=0; + // 111111111 bit pattern represent start of frame + uint8_t frame_marker_mask[] = {1,1,1,1,1,1,1,1,1}; + uint32_t idx = 0; + uint32_t ii=0; + uint8_t resetCnt = 0; + while( (idx + 64) < BitLen) { +restart: + // search for a start of frame marker + if ( memcmp(BitStream+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { // frame marker found + idx+=9;//sizeof(frame_marker_mask); + for (i=0; i<10;i++){ + for(ii=0; ii<5; ++ii){ + parityTest += BitStream[(i*5)+ii+idx]; + } + if (parityTest== ((parityTest>>1)<<1)){ + parityTest=0; + for (ii=0; ii<4;++ii){ + //hi = (hi<<1)|(lo>>31); + lo=(lo<<1LL)|(BitStream[(i*5)+ii+idx]); + } + //PrintAndLog("DEBUG: EM parity passed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d,lo: %d",parityTest,i,ii,idx,BitStream[idx+ii+(i*5)-5],BitStream[idx+ii+(i*5)-4],BitStream[idx+ii+(i*5)-3],BitStream[idx+ii+(i*5)-2],BitStream[idx+ii+(i*5)-1],lo); + }else {//parity failed + //PrintAndLog("DEBUG: EM parity failed parity val: %d, i:%d, ii:%d,idx:%d, Buffer: %d%d%d%d%d",parityTest,i,ii,idx,BitStream[idx+ii+(i*5)-5],BitStream[idx+ii+(i*5)-4],BitStream[idx+ii+(i*5)-3],BitStream[idx+ii+(i*5)-2],BitStream[idx+ii+(i*5)-1]); + parityTest=0; + idx-=8; + if (resetCnt>5)return 0; + resetCnt++; + goto restart;//continue; + } + } + //skip last 5 bit parity test for simplicity. + return lo; + }else{ + idx++; + } + } + return 0; } //by marshmellow //takes 2 arguments - clock and invert both as integers //attempts to demodulate ask while decoding manchester //prints binary found and saves in graphbuffer for further commands -int askmandemod(uint8_t *BinStream, uint32_t *BitLen, int *clk, int *invert) +int askmandemod(uint8_t * BinStream,uint32_t *BitLen,int *clk, int *invert) { - int i; - int high = 0, low = 128; - *clk = DetectASKClock(BinStream, (size_t)*BitLen, *clk); //clock default - - if (*clk < 8 ) *clk = 64; - if (*clk < 32 ) *clk = 32; - if (*invert != 1) *invert = 0; - - uint32_t initLoopMax = 200; - if (initLoopMax > *BitLen) - initLoopMax = *BitLen; - - // Detect high and lows - // 200 samples should be enough to find high and low values - for (i = 0; i < initLoopMax; ++i) { - if (BinStream[i] > high) - high = BinStream[i]; - else if (BinStream[i] < low) - low = BinStream[i]; - } - - //throw away static - if ((high < 158) ) - return -2; + int i; + int high = 0, low = 128; + *clk=DetectASKClock(BinStream,(size_t)*BitLen,*clk); //clock default - //25% fuzz in case highs and lows aren't clipped [marshmellow] - high = (int)(high * .75); - low = (int)(low+128 * .25); - - int lastBit = 0; // set first clock check - uint32_t bitnum = 0; // output counter - - // clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave - //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely - int tol = ( *clk == 32 ) ? 1 : 0; - - int j = 0; - uint32_t gLen = *BitLen; - - if (gLen > 3000) gLen = 3000; - - uint8_t errCnt = 0; - uint32_t bestStart = *BitLen; - uint32_t bestErrCnt = (*BitLen/1000); - uint32_t maxErr = bestErrCnt; - - //loop to find first wave that works - for (j=0; j < gLen; ++j){ - - if ((BinStream[j] >= high)||(BinStream[j] <= low)){ - lastBit = j - *clk; - errCnt = 0; - - //loop through to see if this start location works - for (i = j; i < *BitLen; ++i) { - if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ - lastBit += *clk; - } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ - //low found and we are expecting a bar - lastBit += *clk; - } else { - //mid value found or no bar supposed to be here - if ((i-lastBit) > (*clk + tol)){ - //should have hit a high or low based on clock!! - - errCnt++; - lastBit += *clk;//skip over until hit too many errors - if (errCnt > maxErr) break; //allow 1 error for every 1000 samples else start over - } - } - if ((i-j) >(400 * *clk)) break; //got plenty of bits - } - //we got more than 64 good bits and not all errors - if ((((i-j)/ *clk) > (64 + errCnt)) && (errCnt < maxErr)) { - //possible good read - if (errCnt == 0){ - bestStart = j; - bestErrCnt = errCnt; - break; //great read - finish - } - if (errCnt < bestErrCnt){ //set this as new best run - bestErrCnt = errCnt; - bestStart = j; - } - } + if (*clk<8) *clk =64; + if (*clk<32) *clk=32; + if (*invert != 0 && *invert != 1) *invert=0; + uint32_t initLoopMax = 200; + if (initLoopMax>*BitLen) initLoopMax=*BitLen; + // Detect high and lows + for (i = 0; i < initLoopMax; ++i) //200 samples should be enough to find high and low values + { + if (BinStream[i] > high) + high = BinStream[i]; + else if (BinStream[i] < low) + low = BinStream[i]; } - } - if (bestErrCnt < maxErr){ - //best run is good enough set to best run and set overwrite BinStream - j = bestStart; - lastBit = bestStart - *clk; - bitnum = 0; - for (i = j; i < *BitLen; ++i) { - if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ - lastBit += *clk; - BinStream[bitnum] = *invert; - bitnum++; - } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ - //low found and we are expecting a bar - lastBit += *clk; - BinStream[bitnum] = 1 - *invert; - bitnum++; - } else { - //mid value found or no bar supposed to be here - if ((i-lastBit) > (*clk+tol)){ - //should have hit a high or low based on clock!! - if (bitnum > 0){ - BinStream[bitnum] = 77; - bitnum++; - } - lastBit += *clk;//skip over error - } - } - if (bitnum >= 400) break; - } - *BitLen = bitnum; - } else { - *invert = bestStart; - *clk = j; - return -1; - } - return bestErrCnt; + if ((high < 158) ){ //throw away static + //PrintAndLog("no data found"); + return -2; + } + //25% fuzz in case highs and lows aren't clipped [marshmellow] + high=(int)((high-128)*.75)+128; + low= (int)((low-128)*.75)+128; + + //PrintAndLog("DEBUG - valid high: %d - valid low: %d",high,low); + int lastBit = 0; //set first clock check + uint32_t bitnum = 0; //output counter + int tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave + if (*clk==32)tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely + int iii = 0; + uint32_t gLen = *BitLen; + if (gLen > 3000) gLen=3000; + uint8_t errCnt =0; + uint32_t bestStart = *BitLen; + uint32_t bestErrCnt = (*BitLen/1000); + uint32_t maxErr = (*BitLen/1000); + //PrintAndLog("DEBUG - lastbit - %d",lastBit); + //loop to find first wave that works + for (iii=0; iii < gLen; ++iii){ + if ((BinStream[iii]>=high)||(BinStream[iii]<=low)){ + lastBit=iii-*clk; + errCnt=0; + //loop through to see if this start location works + for (i = iii; i < *BitLen; ++i) { + if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ + lastBit+=*clk; + } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ + //low found and we are expecting a bar + lastBit+=*clk; + } else { + //mid value found or no bar supposed to be here + if ((i-lastBit)>(*clk+tol)){ + //should have hit a high or low based on clock!! + + //debug + //PrintAndLog("DEBUG - no wave in expected area - location: %d, expected: %d-%d, lastBit: %d - resetting search",i,(lastBit+(clk-((int)(tol)))),(lastBit+(clk+((int)(tol)))),lastBit); + + errCnt++; + lastBit+=*clk;//skip over until hit too many errors + if (errCnt>(maxErr)) break; //allow 1 error for every 1000 samples else start over + } + } + if ((i-iii) >(400 * *clk)) break; //got plenty of bits + } + //we got more than 64 good bits and not all errors + if ((((i-iii)/ *clk) > (64+errCnt)) && (errCnt= high) && ((i-lastBit)>(*clk-tol))){ + lastBit+=*clk; + BinStream[bitnum] = *invert; + bitnum++; + } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ + //low found and we are expecting a bar + lastBit+=*clk; + BinStream[bitnum] = 1-*invert; + bitnum++; + } else { + //mid value found or no bar supposed to be here + if ((i-lastBit)>(*clk+tol)){ + //should have hit a high or low based on clock!! + + //debug + //PrintAndLog("DEBUG - no wave in expected area - location: %d, expected: %d-%d, lastBit: %d - resetting search",i,(lastBit+(clk-((int)(tol)))),(lastBit+(clk+((int)(tol)))),lastBit); + if (bitnum > 0){ + BinStream[bitnum]=77; + bitnum++; + } + + lastBit+=*clk;//skip over error + } + } + if (bitnum >=400) break; + } + *BitLen=bitnum; + } else{ + *invert=bestStart; + *clk=iii; + return -1; + } + return bestErrCnt; } //by marshmellow //take 10 and 01 and manchester decode //run through 2 times and take least errCnt -int manrawdecode(uint8_t * bits, int *bitlen) +int manrawdecode(uint8_t * BitStream, int *bitLen) { - int bitnum = 0; - int errCnt = 0; - int bestErr = 1000; - int bestRun = 0; - int i = 1; - int j = 1; - - for (; j < 3; ++j){ - i = 1; - for ( i = i + j; i < *bitlen-2; i += 2){ - if ( bits[i]==1 && (bits[i+1]==0)){ - } else if ((bits[i]==0)&& bits[i+1]==1){ - } else { - errCnt++; - } - if(bitnum > 300) break; - } - if (bestErr > errCnt){ - bestErr = errCnt; - bestRun = j; - } - errCnt = 0; - } - errCnt = bestErr; - if (errCnt < 20){ - j = bestRun; - i = 1; - for ( i = i+j; i < *bitlen-2; i += 2){ - if ( bits[i] == 1 && bits[i + 1] == 0 ){ - bits[bitnum++] = 0; - } else if ( bits[i] == 0 && bits[i + 1] == 1 ){ - bits[bitnum++] = 1; - } else { - bits[bitnum++] = 77; - } - if ( bitnum > 300 ) break; - } - *bitlen = bitnum; - } - return errCnt; + int bitnum=0; + int errCnt =0; + int i=1; + int bestErr = 1000; + int bestRun = 0; + int ii=1; + for (ii=1;ii<3;++ii){ + i=1; + for (i=i+ii;i<*bitLen-2;i+=2){ + if(BitStream[i]==1 && (BitStream[i+1]==0)){ + } else if((BitStream[i]==0)&& BitStream[i+1]==1){ + } else { + errCnt++; + } + if(bitnum>300) break; + } + if (bestErr>errCnt){ + bestErr=errCnt; + bestRun=ii; + } + errCnt=0; + } + errCnt=bestErr; + if (errCnt<20){ + ii=bestRun; + i=1; + for (i=i+ii;i<*bitLen-2;i+=2){ + if(BitStream[i]==1 && (BitStream[i+1]==0)){ + BitStream[bitnum++]=0; + } else if((BitStream[i]==0)&& BitStream[i+1]==1){ + BitStream[bitnum++]=1; + } else { + BitStream[bitnum++]=77; + //errCnt++; + } + if(bitnum>300) break; + } + *bitLen=bitnum; + } + return errCnt; } //by marshmellow //take 01 or 10 = 0 and 11 or 00 = 1 -int BiphaseRawDecode(uint8_t * bits, int *bitlen, int offset) +int BiphaseRawDecode(uint8_t * BitStream, int *bitLen, int offset) { - uint8_t bitnum = 0; - uint32_t errCnt = 0; - uint32_t i = offset; - - for (; i < *bitlen-2; i += 2 ){ - if ( (bits[i]==1 && bits[i+1]==0)|| - (bits[i]==0 && bits[i+1]==1)){ - bits[bitnum++] = 1; - } else if ( (bits[i]==0 && bits[i+1]==0)|| - (bits[i]==1 && bits[i+1]==1)){ - bits[bitnum++] = 0; - } else { - bits[bitnum++] = 77; - errCnt++; - } - if ( bitnum > 250) break; - } - *bitlen = bitnum; - return errCnt; + uint8_t bitnum=0; + uint32_t errCnt =0; + uint32_t i=1; + i=offset; + for (;i<*bitLen-2;i+=2){ + if((BitStream[i]==1 && BitStream[i+1]==0)||(BitStream[i]==0 && BitStream[i+1]==1)){ + BitStream[bitnum++]=1; + } else if((BitStream[i]==0 && BitStream[i+1]==0)||(BitStream[i]==1 && BitStream[i+1]==1)){ + BitStream[bitnum++]=0; + } else { + BitStream[bitnum++]=77; + errCnt++; + } + if(bitnum>250) break; + } + *bitLen=bitnum; + return errCnt; } //by marshmellow //takes 2 arguments - clock and invert both as integers //attempts to demodulate ask only //prints binary found and saves in graphbuffer for further commands -int askrawdemod(uint8_t *BinStream, int *bitLen, int *clk, int *invert) +int askrawdemod(uint8_t *BinStream, int *bitLen,int *clk, int *invert) { - uint32_t i; - uint32_t initLoopMax = 200; - int high = 0, low = 128; - uint8_t BitStream[502] = {0x00}; - - *clk = DetectASKClock(BinStream, *bitLen, *clk); //clock default - - if (*clk < 8) *clk = 64; - if (*clk < 32) *clk = 32; - if (*invert != 1) *invert = 0; + uint32_t i; + // int invert=0; //invert default + int high = 0, low = 128; + *clk=DetectASKClock(BinStream,*bitLen,*clk); //clock default + uint8_t BitStream[502] = {0}; - if (initLoopMax > *bitLen) - initLoopMax = *bitLen; - - // Detect high and lows - for (i = 0; i < initLoopMax; ++i) //200 samples should be plenty to find high and low values - { - if (BinStream[i] > high) - high = BinStream[i]; - else if (BinStream[i] < low) - low = BinStream[i]; - } - - //throw away static - if ((high < 158)){ - return -2; - } - - //25% fuzz in case highs and lows aren't clipped [marshmellow] - high = (int)(high * .75); - low = (int)(low+128 * .25); - - int lastBit = 0; //set first clock check - uint32_t bitnum = 0; //output counter - - uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave - if (*clk==32) tol = 1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely - - uint32_t gLen = *bitLen; - if (gLen > 500) gLen = 500; - - uint32_t j = 0; - uint8_t errCnt = 0; - uint32_t bestStart = *bitLen; - uint32_t bestErrCnt = (*bitLen / 1000); - uint32_t errCntLimit = bestErrCnt; - uint8_t midBit = 0; - - //loop to find first wave that works - for (j = 0; j < gLen; ++j){ - - if ((BinStream[j] >= high)||(BinStream[j] <= low)){ - lastBit = j - *clk; - //loop through to see if this start location works - for (i = j; i < *bitLen; ++i) { - if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ - lastBit += *clk; - BitStream[bitnum] = *invert; - bitnum++; - midBit = 0; - } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ - //low found and we are expecting a bar - lastBit += *clk; - BitStream[bitnum] = 1-*invert; - bitnum++; - midBit=0; - } else if ((BinStream[i]<=low) && (midBit==0) && ((i-lastBit)>((*clk/2)-tol))){ - //mid bar? - midBit = 1; - BitStream[bitnum] = 1 - *invert; - bitnum++; - } else if ((BinStream[i]>=high)&&(midBit==0) && ((i-lastBit)>((*clk/2)-tol))){ - //mid bar? - midBit = 1; - BitStream[bitnum] = *invert; - bitnum++; - } else if ((i-lastBit)>((*clk/2)+tol)&&(midBit==0)){ - //no mid bar found - midBit = 1; - BitStream[bitnum] = BitStream[bitnum-1]; - bitnum++; - } else { - //mid value found or no bar supposed to be here - - if (( i - lastBit) > ( *clk + tol)){ - //should have hit a high or low based on clock!! - - if (bitnum > 0){ - BitStream[bitnum] = 77; - bitnum++; - } - - errCnt++; - lastBit += *clk;//skip over until hit too many errors - if (errCnt > errCntLimit){ //allow 1 error for every 1000 samples else start over - errCnt = 0; - bitnum = 0;//start over - break; - } - } - } - if (bitnum > 500) break; - } - //we got more than 64 good bits and not all errors - //possible good read - if ((bitnum > (64 + errCnt)) && (errCnt < errCntLimit)) { - - //great read - finish - if (errCnt == 0) break; - - //if current run == bestErrCnt run (after exhausted testing) then finish - if (bestStart == j) break; - - //set this as new best run - if (errCnt < bestErrCnt){ - bestErrCnt = errCnt; - bestStart = j; - } - } + if (*clk<8) *clk =64; + if (*clk<32) *clk=32; + if (*invert != 0 && *invert != 1) *invert =0; + uint32_t initLoopMax = 200; + if (initLoopMax>*bitLen) initLoopMax=*bitLen; + // Detect high and lows + for (i = 0; i < initLoopMax; ++i) //200 samples should be plenty to find high and low values + { + if (BinStream[i] > high) + high = BinStream[i]; + else if (BinStream[i] < low) + low = BinStream[i]; } - if (j >= gLen){ //exhausted test - //if there was a ok test go back to that one and re-run the best run (then dump after that run) - if (bestErrCnt < errCntLimit) - j = bestStart; + if ((high < 158)){ //throw away static + // PrintAndLog("no data found"); + return -2; } - } - if (bitnum > 16){ + //25% fuzz in case highs and lows aren't clipped [marshmellow] + high=(int)((high-128)*.75)+128; + low= (int)((low-128)*.75)+128; - for (i = 0; i < bitnum; ++i){ - BinStream[i] = BitStream[i]; - } - *bitLen = bitnum; - } else { - return -1; - } - return errCnt; + //PrintAndLog("DEBUG - valid high: %d - valid low: %d",high,low); + int lastBit = 0; //set first clock check + uint32_t bitnum = 0; //output counter + uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave + if (*clk==32)tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely + uint32_t iii = 0; + uint32_t gLen = *bitLen; + if (gLen > 500) gLen=500; + uint8_t errCnt =0; + uint32_t bestStart = *bitLen; + uint32_t bestErrCnt = (*bitLen/1000); + uint8_t midBit=0; + //PrintAndLog("DEBUG - lastbit - %d",lastBit); + //loop to find first wave that works + for (iii=0; iii < gLen; ++iii){ + if ((BinStream[iii]>=high)||(BinStream[iii]<=low)){ + lastBit=iii-*clk; + //loop through to see if this start location works + for (i = iii; i < *bitLen; ++i) { + if ((BinStream[i] >= high) && ((i-lastBit)>(*clk-tol))){ + lastBit+=*clk; + BitStream[bitnum] = *invert; + bitnum++; + midBit=0; + } else if ((BinStream[i] <= low) && ((i-lastBit)>(*clk-tol))){ + //low found and we are expecting a bar + lastBit+=*clk; + BitStream[bitnum] = 1-*invert; + bitnum++; + midBit=0; + } else if ((BinStream[i]<=low) && (midBit==0) && ((i-lastBit)>((*clk/2)-tol))){ + //mid bar? + midBit=1; + BitStream[bitnum]= 1-*invert; + bitnum++; + } else if ((BinStream[i]>=high)&&(midBit==0) && ((i-lastBit)>((*clk/2)-tol))){ + //mid bar? + midBit=1; + BitStream[bitnum]= *invert; + bitnum++; + } else if ((i-lastBit)>((*clk/2)+tol)&&(midBit==0)){ + //no mid bar found + midBit=1; + BitStream[bitnum]= BitStream[bitnum-1]; + bitnum++; + } else { + //mid value found or no bar supposed to be here + + if ((i-lastBit)>(*clk+tol)){ + //should have hit a high or low based on clock!! + //debug + //PrintAndLog("DEBUG - no wave in expected area - location: %d, expected: %d-%d, lastBit: %d - resetting search",i,(lastBit+(clk-((int)(tol)))),(lastBit+(clk+((int)(tol)))),lastBit); + if (bitnum > 0){ + BitStream[bitnum]=77; + bitnum++; + } + + + errCnt++; + lastBit+=*clk;//skip over until hit too many errors + if (errCnt>((*bitLen/1000))){ //allow 1 error for every 1000 samples else start over + errCnt=0; + bitnum=0;//start over + break; + } + } + } + if (bitnum>500) break; + } + //we got more than 64 good bits and not all errors + if ((bitnum > (64+errCnt)) && (errCnt<(*bitLen/1000))) { + //possible good read + if (errCnt==0) break; //great read - finish + if (bestStart == iii) break; //if current run == bestErrCnt run (after exhausted testing) then finish + if (errCnt=gLen){ //exhausted test + //if there was a ok test go back to that one and re-run the best run (then dump after that run) + if (bestErrCnt < (*bitLen/1000)) iii=bestStart; + } + } + if (bitnum>16){ + + // PrintAndLog("Data start pos:%d, lastBit:%d, stop pos:%d, numBits:%d",iii,lastBit,i,bitnum); + //move BitStream back to BinStream + // ClearGraph(0); + for (i=0; i < bitnum; ++i){ + BinStream[i]=BitStream[i]; + } + *bitLen=bitnum; + // RepaintGraphWindow(); + //output + // if (errCnt>0){ + // PrintAndLog("# Errors during Demoding (shown as 77 in bit stream): %d",errCnt); + // } + // PrintAndLog("ASK decoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + // printBitStream2(BitStream,bitnum); + //int errCnt=0; + //errCnt=manrawdemod(BitStream,bitnum); + + // Em410xDecode(Cmd); + } else return -1; + return errCnt; } //translate wave to 11111100000 (1 for each short wave 0 for each long wave) size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow) { - uint32_t last_transition = 0; - uint32_t idx = 1; - uint32_t maxVal = 0; - - if (fchigh == 0) fchigh = 10; - if (fclow == 0) fclow = 8; - - // we do care about the actual theshold value as sometimes near the center of the - // wave we may get static that changes direction of wave for one value - // if our value is too low it might affect the read. and if our tag or - // antenna is weak a setting too high might not see anything. [marshmellow] - if ( size < 100) - return 0; - - // Find high from first 100 samples - for ( idx = 1; idx < 100; idx++ ){ - if ( maxVal < dest[idx]) - maxVal = dest[idx]; - } - + uint32_t last_transition = 0; + uint32_t idx = 1; + uint32_t maxVal=0; + if (fchigh==0) fchigh=10; + if (fclow==0) fclow=8; + // we do care about the actual theshold value as sometimes near the center of the + // wave we may get static that changes direction of wave for one value + // if our value is too low it might affect the read. and if our tag or + // antenna is weak a setting too high might not see anything. [marshmellow] + if (size<100) return 0; + for(idx=1; idx<100; idx++){ + if(maxVal1 transition - if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition - if ( ( idx - last_transition ) <( fclow - 2 ) ) { //0-5 = garbage noise - //do nothing with extra garbage - } else if ((idx - last_transition) < ( fchigh - 1 )) { //6-8 = 8 waves - dest[numBits]=1; - } else { //9+ = 10 waves - dest[numBits]=0; - } - last_transition = idx; - numBits++; - } - } - //it returns the number of bytes, but each byte represents a bit: 1 or 0 - return numBits; + if(dest[0] < threshold_value) dest[0] = 0; + else dest[0] = 1; + + size_t numBits = 0; + // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8) + // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere + // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10 + for(idx = 1; idx < size; idx++) { + // threshold current value + + if (dest[idx] < threshold_value) dest[idx] = 0; + else dest[idx] = 1; + + // Check for 0->1 transition + if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition + if ((idx-last_transition)<(fclow-2)){ //0-5 = garbage noise + //do nothing with extra garbage + } else if ((idx-last_transition) < (fchigh-1)) { //6-8 = 8 waves + dest[numBits]=1; + } else { //9+ = 10 waves + dest[numBits]=0; + } + last_transition = idx; + numBits++; + } + } + return numBits; //Actually, it returns the number of bytes, but each byte represents a bit: 1 or 0 } uint32_t myround2(float f) { - if (f >= 2000) return 2000;//something bad happened - return (uint32_t) (f + (float)0.5); + if (f >= 2000) return 2000;//something bad happened + return (uint32_t) (f + (float)0.5); } //translate 11111100000 to 10 -size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert, uint8_t fchigh, uint8_t fclow ) +size_t aggregate_bits(uint8_t *dest,size_t size, uint8_t rfLen, uint8_t maxConsequtiveBits, uint8_t invert,uint8_t fchigh,uint8_t fclow )// uint8_t h2l_crossing_value,uint8_t l2h_crossing_value, { - uint8_t lastval = dest[0]; - uint32_t idx = 0; - uint32_t n = 1; - size_t numBits = 0; + uint8_t lastval=dest[0]; + uint32_t idx=0; + size_t numBits=0; + uint32_t n=1; - for( idx = 1; idx < size; idx++) { + for( idx=1; idx < size; idx++) { - if (dest[idx] == lastval) { - n++; - continue; - } - //if lastval was 1, we have a 1->0 crossing - if ( dest[idx-1] == 1 ) { - n = myround2( (float)( n + 1 ) / ((float)(rfLen)/(float)fclow)); - } else { // 0->1 crossing - n = myround2( (float)( n + 1 ) / ((float)(rfLen-2)/(float)fchigh)); //-2 for fudge factor - } - if (n == 0) n = 1; + if (dest[idx]==lastval) { + n++; + continue; + } + //if lastval was 1, we have a 1->0 crossing + if ( dest[idx-1]==1 ) { + n=myround2((float)(n+1)/((float)(rfLen)/(float)fclow)); + //n=(n+1) / h2l_crossing_value; + } else {// 0->1 crossing + n=myround2((float)(n+1)/((float)(rfLen-2)/(float)fchigh)); //-2 for fudge factor + //n=(n+1) / l2h_crossing_value; + } + if (n == 0) n = 1; - if(n < maxConsequtiveBits) //Consecutive - { - if(invert == 0){ //invert bits - memset(dest+numBits, dest[idx-1] , n); - }else{ - memset(dest+numBits, dest[idx-1]^1 , n); - } - numBits += n; - } - n = 0; - lastval = dest[idx]; - }//end for - return numBits; + if(n < maxConsequtiveBits) //Consecutive + { + if(invert==0){ //invert bits + memset(dest+numBits, dest[idx-1] , n); + }else{ + memset(dest+numBits, dest[idx-1]^1 , n); + } + numBits += n; + } + n=0; + lastval=dest[idx]; + }//end for + return numBits; } - //by marshmellow (from holiman's base) // full fsk demod from GraphBuffer wave to decoded 1s and 0s (no mandemod) int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow) { - // FSK demodulator - size = fsk_wave_demod(dest, size, fchigh, fclow); - if ( size > 0 ) - size = aggregate_bits(dest, size, rfLen, 192, invert, fchigh, fclow); - return size; + // FSK demodulator + size = fsk_wave_demod(dest, size, fchigh, fclow); + size = aggregate_bits(dest, size,rfLen,192,invert,fchigh,fclow); + return size; } - // loop to get raw HID waveform then FSK demodulate the TAG ID from it int HIDdemodFSK(uint8_t *dest, size_t size, uint32_t *hi2, uint32_t *hi, uint32_t *lo) { - size_t idx = 0; - int numshifts = 0; - // FSK demodulator - size = fskdemod(dest, size, 50, 0, 10, 8); + size_t idx=0; //, found=0; //size=0, + // FSK demodulator + size = fskdemod(dest, size,50,0,10,8); - // final loop, go over previously decoded manchester data and decode into usable tag ID - // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 - uint8_t frame_marker_mask[] = {1,1,1,0,0,0}; - - uint8_t mask_len = sizeof frame_marker_mask / sizeof frame_marker_mask[0]; - - //one scan - while( idx + mask_len < size) { - // search for a start of frame marker - if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { // frame marker found - idx += mask_len; - while(dest[idx] != dest[idx+1] && idx < size-2) - { - // Keep going until next frame marker (or error) - // Shift in a bit. Start by shifting high registers - *hi2 = ( *hi2 << 1 ) | ( *hi >> 31 ); - *hi = ( *hi << 1 ) | ( *lo >> 31 ); - //Then, shift in a 0 or one into low - if (dest[idx] && !dest[idx+1]) // 1 0 - *lo = ( *lo << 1 ) | 0; - else // 0 1 - *lo = ( *lo << 1 ) | 1; - numshifts++; - idx += 2; - } - // Hopefully, we read a tag and hit upon the next frame marker - if(idx + mask_len < size) - { - if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) - { - //good return - return idx; - } - } - // reset - *hi2 = *hi = *lo = 0; - numshifts = 0; - }else { - idx++; - } - } - return -1; + // final loop, go over previously decoded manchester data and decode into usable tag ID + // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 + uint8_t frame_marker_mask[] = {1,1,1,0,0,0}; + int numshifts = 0; + idx = 0; + //one scan + while( idx + sizeof(frame_marker_mask) < size) { + // search for a start of frame marker + if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { // frame marker found + idx+=sizeof(frame_marker_mask); + while(dest[idx] != dest[idx+1] && idx < size-2) + { + // Keep going until next frame marker (or error) + // Shift in a bit. Start by shifting high registers + *hi2 = (*hi2<<1)|(*hi>>31); + *hi = (*hi<<1)|(*lo>>31); + //Then, shift in a 0 or one into low + if (dest[idx] && !dest[idx+1]) // 1 0 + *lo=(*lo<<1)|0; + else // 0 1 + *lo=(*lo<<1)|1; + numshifts++; + idx += 2; + } + // Hopefully, we read a tag and hit upon the next frame marker + if(idx + sizeof(frame_marker_mask) < size) + { + if ( memcmp(dest+idx, frame_marker_mask, sizeof(frame_marker_mask)) == 0) + { + //good return + return idx; + } + } + // reset + *hi2 = *hi = *lo = 0; + numshifts = 0; + }else { + idx++; + } + } + return -1; } -uint32_t bytebits_to_byte(uint8_t *src, int numbits) +uint32_t bytebits_to_byte(uint8_t* src, int numbits) { - //HACK: potential overflow in numbits is larger then uint32 bits. - - uint32_t num = 0; - for(int i = 0 ; i < numbits ; ++i) { - num = (num << 1) | (*src); - src++; - } - return num; + uint32_t num = 0; + for(int i = 0 ; i < numbits ; i++) + { + num = (num << 1) | (*src); + src++; + } + return num; } int IOdemodFSK(uint8_t *dest, size_t size) { - //make sure buffer has data - if (size < 100) return -1; - - uint32_t idx = 0; - uint8_t testMax = 0; - - //test samples are not just noise - for (; idx < 65; ++idx ){ - if (testMax < dest[idx]) - testMax = dest[idx]; - } - - //if not, just noise - if (testMax < 20) return -2; - - // FSK demodulator - size = fskdemod(dest, size, 64, 1, 10, 8); // RF/64 and invert - - //did we get a good demod? - if (size < 65) return -3; - - //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 - - uint8_t mask[] = {0,0,0,0,0,0,0,0,0,1}; - - for( idx = 0; idx < (size - 65); ++idx) { - if ( memcmp(dest + idx, mask, sizeof(mask))==0) { - //frame marker found - if (!dest[idx+8] && - dest[idx+17] == 1 && - dest[idx+26] == 1 && - dest[idx+35] == 1 && - dest[idx+44] == 1 && - dest[idx+53] == 1){ - //confirmed proper separator bits found - //return start position - return (int) idx; - } - } - } - return 0; + uint32_t idx=0; + //make sure buffer has data + if (size < 66) return -1; + //test samples are not just noise + uint8_t testMax=0; + for(idx=0;idx<65;idx++){ + if (testMax20){ + // FSK demodulator + size = fskdemod(dest, size,64,1,10,8); // RF/64 and invert + if (size < 65) return -1; //did we get a good demod? + //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 + uint8_t mask[] = {0,0,0,0,0,0,0,0,0,1}; + for( idx=0; idx < (size - 65); idx++) { + if ( memcmp(dest + idx, mask, sizeof(mask))==0) { + //frame marker found + if (!dest[idx+8] && dest[idx+17]==1 && dest[idx+26]==1 && dest[idx+35]==1 && dest[idx+44]==1 && dest[idx+53]==1){ + //confirmed proper separator bits found + //return start position + return (int) idx; + } + } + } + } + return 0; } // by marshmellow @@ -665,86 +635,67 @@ int IOdemodFSK(uint8_t *dest, size_t size) // maybe somehow adjust peak trimming value based on samples to fix? int DetectASKClock(uint8_t dest[], size_t size, int clock) { - int i = 0; - int clk[] = {16,32,40,50,64,100,128,256}; - uint8_t clkLen = sizeof clk / sizeof clk[0]; - - //if we already have a valid clock quit - for (; i < clkLen; ++i) - if (clk[i] == clock) - return clock; - - int peak = 0; - int low = 128; - int loopCnt = 256; - if (size < loopCnt) - loopCnt = size; - - //get high and low peak - for ( i = 0; i < loopCnt; ++i ){ - if(dest[i] > peak) - peak = dest[i]; - if(dest[i] < low) - low = dest[i]; - } + int i=0; + int peak=0; + int low=128; + int clk[]={16,32,40,50,64,100,128,256}; + int loopCnt = 256; //don't need to loop through entire array... + if (size low)) - continue; - - errCnt[cnt] = 0; - - // now that we have the first one lined up test rest of wave array - for ( i = 0; i < ((int)(size / clk[cnt]) - 1); ++i){ - - tmpIndex = ii + (i * clk[cnt] ); - tmplow = dest[ tmpIndex - tol]; - tmphigh = dest[ tmpIndex + tol]; - - if ( dest[tmpIndex] >= peak || dest[tmpIndex] <= low ) { - } - else if ( tmplow >= peak || tmplow <= low){ - } - else if ( tmphigh >= peak || tmphigh <= low){ - } - else - errCnt[cnt]++; //error no peak detected - } - - //if we found no errors this is correct one - return this clock - if ( errCnt[cnt] == 0 ) - return clk[cnt]; - - if ( errCnt[cnt] < bestErr) - bestErr = errCnt[cnt]; - } - // save the least error. - errCnt[cnt] = bestErr; - } - // find best clock which has lowest number of errors - int j = 0, bestIndex = 0; - for (; j < clkLen; ++j){ - if ( errCnt[j] < errCnt[bestIndex] ) - bestIndex = j; - } - return clk[bestIndex]; + //get high and low peak + for (i=0;ipeak){ + peak = dest[i]; + } + if(dest[i]=peak) || (dest[ii]<=low)){ + errCnt[clkCnt]=0; + // now that we have the first one lined up test rest of wave array + for (i=0; i<((int)(size/clk[clkCnt])-1); ++i){ + if (dest[ii+(i*clk[clkCnt])]>=peak || dest[ii+(i*clk[clkCnt])]<=low){ + }else if(dest[ii+(i*clk[clkCnt])-tol]>=peak || dest[ii+(i*clk[clkCnt])-tol]<=low){ + }else if(dest[ii+(i*clk[clkCnt])+tol]>=peak || dest[ii+(i*clk[clkCnt])+tol]<=low){ + }else{ //error no peak detected + errCnt[clkCnt]++; + } + } + //if we found no errors this is correct one - return this clock + if(errCnt[clkCnt]==0) return clk[clkCnt]; + //if we found errors see if it is lowest so far and save it as best run + if(errCnt[clkCnt] (b)) ? (a) : (b)) @@ -223,6 +223,7 @@ byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0; void usb_disable() { // Disconnect the USB device AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU; +// SpinDelay(100); // Clear all lingering interrupts if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) { @@ -235,31 +236,32 @@ void usb_disable() { //* \brief This function Activates the USB device //*---------------------------------------------------------------------------- void usb_enable() { - // Set the PLL USB Divider - AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ; - - // Specific Chip USB Initialisation - // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock - AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); - - // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO - // Set in PIO mode and Configure in Output - AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode + // Set the PLL USB Divider + AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ; + + // Specific Chip USB Initialisation + // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock + AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); + + // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO + // Set in PIO mode and Configure in Output + AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output - - // Clear for set the Pullup resistor + + // Clear for set the Pullup resistor AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU; + + // Disconnect and reconnect USB controller for 100ms + usb_disable(); + + // Wait for a short while + for (volatile size_t i=0; i<0x100000; i++); +// SpinDelay(100); - // Disconnect and reconnect USB controller for 100ms - usb_disable(); - - // Wait for a short while - for (volatile size_t i=0; i<0x100000; i++); - - // Reconnect USB reconnect - AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU; - AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; + // Reconnect USB reconnect + AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU; + AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; } //*---------------------------------------------------------------------------- @@ -298,26 +300,28 @@ bool usb_poll() //* \brief Read available data from Endpoint OUT //*---------------------------------------------------------------------------- uint32_t usb_read(byte_t* data, size_t len) { - byte_t bank = btReceiveBank; + byte_t bank = btReceiveBank; uint32_t packetSize, nbBytesRcv = 0; - uint32_t time_out = 0; + uint32_t time_out = 0; - while (len) { + while (len) + { if (!usb_check()) break; if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) { packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len); - len -= packetSize; + len -= packetSize; while(packetSize--) data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT]; pUdp->UDP_CSR[AT91C_EP_OUT] &= ~(bank); - if (bank == AT91C_UDP_RX_DATA_BK0) { + if (bank == AT91C_UDP_RX_DATA_BK0) + { bank = AT91C_UDP_RX_DATA_BK1; - } else { + } else { bank = AT91C_UDP_RX_DATA_BK0; - } + } } - if (time_out++ == 0x1fff) break; + if (time_out++ == 0x1fff) break; } btReceiveBank = bank; @@ -349,7 +353,7 @@ uint32_t usb_write(const byte_t* data, const size_t len) { // Wait for the the first bank to be sent while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) { if (!usb_check()) return length; - } + } pUdp->UDP_CSR[AT91C_EP_IN] &= ~(AT91C_UDP_TXCOMP); while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP); pUdp->UDP_CSR[AT91C_EP_IN] |= AT91C_UDP_TXPKTRDY; diff --git a/common/usb_cdc.h b/common/usb_cdc.h index b6489937..d7b9c2e5 100644 --- a/common/usb_cdc.h +++ b/common/usb_cdc.h @@ -35,7 +35,7 @@ #ifndef _USB_CDC_H_ #define _USB_CDC_H_ -#include "../include/common.h" +#include void usb_disable(); void usb_enable(); diff --git a/cp2tau b/cp2tau deleted file mode 100644 index 8b6ee4b4..00000000 --- a/cp2tau +++ /dev/null @@ -1,4 +0,0 @@ -cp armsrc/obj/*.elf /z -cp armsrc/obj/*.s19 /z -cp bootrom/obj/*.elf /z -cp bootrom/obj/*.s19 /z diff --git a/iceman.txt b/iceman.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/include/at91sam7s512.h b/include/at91sam7s512.h index 2cdcbce3..5be13622 100644 --- a/include/at91sam7s512.h +++ b/include/at91sam7s512.h @@ -428,7 +428,7 @@ typedef struct _AT91S_PIO { #define PIO_PDR (AT91_CAST(AT91_REG *) 0x00000004) // (PIO_PDR) PIO Disable Register #define PIO_PSR (AT91_CAST(AT91_REG *) 0x00000008) // (PIO_PSR) PIO Status Register #define PIO_OER (AT91_CAST(AT91_REG *) 0x00000010) // (PIO_OER) Output Enable Register -#define PIO_ODR (AT91_CAST(AT91_REG *) 0x00000014) // (PIO_ODR) Output Disable Register +#define PIO_ODR (AT91_CAST(AT91_REG *) 0x00000014) // (PIO_ODR) Output Disable Registerr #define PIO_OSR (AT91_CAST(AT91_REG *) 0x00000018) // (PIO_OSR) Output Status Register #define PIO_IFER (AT91_CAST(AT91_REG *) 0x00000020) // (PIO_IFER) Input Filter Enable Register #define PIO_IFDR (AT91_CAST(AT91_REG *) 0x00000024) // (PIO_IFDR) Input Filter Disable Register diff --git a/include/crc.h.old b/include/crc.h.old deleted file mode 100644 index 8e68f3b3..00000000 --- a/include/crc.h.old +++ /dev/null @@ -1,48 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// Generic CRC calculation code. -//----------------------------------------------------------------------------- - -#ifndef __CRC_H -#define __CRC_H - -#include - -typedef struct crc { - uint32_t state; - int order; - uint32_t polynom; - uint32_t initial_value; - uint32_t final_xor; - uint32_t mask; -} crc_t; - -/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32 - * polynom is the CRC polynom. initial_value is the initial value of a clean state. - * final_xor is XORed onto the state before returning it from crc_result(). */ -extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor); - -/* Update the crc state. data is the data of length data_width bits (only the the - * data_width lower-most bits are used). - */ -extern void crc_update(crc_t *crc, uint32_t data, int data_width); - -/* Clean the crc state, e.g. reset it to initial_value */ -extern void crc_clear(crc_t *crc); - -/* Get the result of the crc calculation */ -extern uint32_t crc_finish(crc_t *crc); - -/* Static initialization of a crc structure */ -#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \ - .state = ((_initial_value) & ((1L<<(_order))-1)), \ - .order = (_order), \ - .polynom = (_polynom), \ - .initial_value = (_initial_value), \ - .final_xor = (_final_xor), \ - .mask = ((1L<<(_order))-1) } - -#endif /* __CRC_H */ diff --git a/include/mifare.h b/include/mifare.h index 403132ac..e2b7a7c5 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -11,7 +11,7 @@ #ifndef _MIFARE_H_ #define _MIFARE_H_ -#include "../include/common.h" +#include "common.h" //----------------------------------------------------------------------------- // ISO 14443A diff --git a/include/proxmark3.h b/include/proxmark3.h index b3530c64..8c9417da 100644 --- a/include/proxmark3.h +++ b/include/proxmark3.h @@ -14,7 +14,6 @@ // Might as well have the hardware-specific defines everywhere. #include "at91sam7s512.h" #include "config_gpio.h" -#include "usb_cmd.h" #define WDT_HIT() AT91C_BASE_WDTC->WDTC_WDCR = 0xa5000001 @@ -68,6 +67,8 @@ #define TRUE 1 #define FALSE 0 +#include + //#define PACKED __attribute__((__packed__)) #define LED_A_ON() HIGH(GPIO_LED_A) diff --git a/include/usb_cmd.h b/include/usb_cmd.h index ecdf8ac1..69c3c1b6 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -115,12 +115,11 @@ 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_READER_ICLASS_REPLAY 0x0395 #define CMD_ICLASS_ISO14443A_WRITE 0x0397 // For measurements of the antenna tuning @@ -150,11 +149,9 @@ typedef struct { #define CMD_MIFARE_NESTED 0x0612 #define CMD_MIFARE_READBL 0x0620 -#define CMD_MIFAREU_READBL 0x0720 - +#define CMD_MIFAREU_READBL 0x0720 #define CMD_MIFARE_READSC 0x0621 -#define CMD_MIFAREU_READCARD 0x0721 - +#define CMD_MIFAREU_READCARD 0x0721 #define CMD_MIFARE_WRITEBL 0x0622 #define CMD_MIFAREU_WRITEBL 0x0722 #define CMD_MIFAREU_WRITEBL_COMPAT 0x0723 @@ -187,7 +184,7 @@ typedef struct { //Iclass reader flags -#define FLAG_ICLASS_READER_ONLY_ONCE 0x01 +#define FLAG_ICLASS_READER_ONLY_ONCE 0x01 #define FLAG_ICLASS_READER_GET_CC 0x02 // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: diff --git a/tools/mkversion.pl b/tools/mkversion.pl index e12dd447..19616441 100644 --- a/tools/mkversion.pl +++ b/tools/mkversion.pl @@ -16,7 +16,7 @@ my $gitbranch = `git rev-parse --abbrev-ref HEAD`; my $clean = 2; my @compiletime = gmtime(); -my $fullgitinfo = 'iceman' . $gitbranch . '/' . $gitversion; +my $fullgitinfo = $gitbranch . '/' . $gitversion; $fullgitinfo =~ s/(\s)//g; From 5db97566769f5eb13b8b71c628c1a408d61ba98d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 5 Jan 2015 19:12:59 +0100 Subject: [PATCH 75/78] CHG: corrections for the detection of chinese backdoor commands in cmdhf14a.c --- client/cmdhf14a.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 673737e2..120d914a 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -98,13 +98,6 @@ int CmdHF14AReader(const char *Cmd) card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes } - // disconnect - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes bool ta1 = 0, tb1 = 0, tc1 = 0; int pos; @@ -243,6 +236,24 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog("proprietary non iso14443-4 card found, RATS not supported"); } + + // try to see if card responses to "chinese magic backdoor" commands. + c.cmd = CMD_MIFARE_CIDENT; + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); + WaitForResponse(CMD_ACK,&resp); + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog(" Answers to chinese magic backdoor commands: %s", (isOK ? "YES" : "NO") ); + + // disconnect + c.cmd = CMD_READER_ISO_14443a; + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); + return select_status; } From 26c8035142d564fe74da714b15048f60ed1747f3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 5 Jan 2015 19:50:00 +0100 Subject: [PATCH 76/78] Minor code clean ups ADD: tnp3xx support in lua scripts FIX: hf 14a reader and identificate chinese backdoor, forgot to add the code. --- armsrc/Makefile | 2 +- armsrc/appmain.c | 1 - armsrc/crapto1.c | 4 +- armsrc/iso14443a.c | 2 +- armsrc/mifarecmd.c | 1 - armsrc/string.c | 5 ++ armsrc/string.h | 8 +- client/cmddata.c | 51 ++++++++--- client/cmdhw.c | 5 +- client/cmdlf.c | 18 ++-- client/cmdlfem4x.c | 14 ++- client/cmdmain.c | 7 +- client/data.h | 3 + client/graph.c | 2 + client/loclass/elite_crack.c | 1 - client/loclass/ikeys.c | 2 - client/lualibs/commands.lua | 33 ++++++- client/lualibs/html_dumplib.lua | 14 +++ client/lualibs/htmlskel.lua | 1 + client/lualibs/mf_default_keys.lua | 18 ++++ client/lualibs/read14a.lua | 1 + client/nonce2key/crapto1.c | 1 - client/scripts/formatMifare.lua | 4 +- client/scripts/mifare_autopwn.lua | 2 + client/util.c | 135 +++++++++++++++++++++++++++++ client/util.h | 14 +++ common/Makefile.common | 4 +- common/cmd.c | 2 - common/crc16.c | 23 +++++ common/crc16.h | 5 +- common/usb_cdc.c | 8 +- include/at91sam7s512.h | 2 +- include/proxmark3.h | 3 +- include/usb_cmd.h | 2 + 34 files changed, 339 insertions(+), 59 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index f87cf0a1..3869029d 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -10,7 +10,7 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line #in the next section to remove that particular feature from compilation -APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG +APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -fno-strict-aliasing #-DWITH_LCD #SRC_LCD = fonts.c LCD.c diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 3c92a7fd..d52ed94a 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -18,7 +18,6 @@ #include "util.h" #include "printf.h" #include "string.h" - #include #include "legicrf.h" diff --git a/armsrc/crapto1.c b/armsrc/crapto1.c index 9d491d12..df0834b8 100644 --- a/armsrc/crapto1.c +++ b/armsrc/crapto1.c @@ -44,12 +44,12 @@ static void quicksort(uint32_t* const start, uint32_t* const stop) else if(*rit > *start) --rit; else - *it ^= (*it ^= *rit, *rit ^= *it); + *it ^= ( (*it ^= *rit ), *rit ^= *it); if(*rit >= *start) --rit; if(rit != start) - *rit ^= (*rit ^= *start, *start ^= *rit); + *rit ^= ( (*rit ^= *start), *start ^= *rit); quicksort(start, rit - 1); quicksort(rit + 1, stop); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index c2f809fe..cf55e606 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1812,7 +1812,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u if (!ReaderReceive(resp, resp_par)) return 0; sak = resp[0]; - // Test if more parts of the uid are comming + // Test if more parts of the uid are coming if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: // http://www.nxp.com/documents/application_note/AN10927.pdf diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 8541553b..a52ee4c9 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -214,7 +214,6 @@ void MifareUReadCard(uint8_t arg0, uint8_t *datain) // clear trace iso14a_clear_trace(); -// iso14a_set_tracing(false); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); diff --git a/armsrc/string.c b/armsrc/string.c index cc71276c..945a4cf6 100644 --- a/armsrc/string.c +++ b/armsrc/string.c @@ -48,6 +48,11 @@ int memcmp(const void *av, const void *bv, int len) return 0; } +void memxor(uint8_t * dest, uint8_t * src, size_t len) { + for( ; len > 0; len--,dest++,src++) + *dest ^= *src; +} + int strlen(const char *str) { int l = 0; diff --git a/armsrc/string.h b/armsrc/string.h index 46ee218d..a9dbd826 100644 --- a/armsrc/string.h +++ b/armsrc/string.h @@ -12,10 +12,14 @@ #ifndef __STRING_H #define __STRING_H +#include +#include + int strlen(const char *str); -void *memcpy(void *dest, const void *src, int len); +RAMFUNC void *memcpy(void *dest, const void *src, int len); void *memset(void *dest, int c, int len); -int memcmp(const void *av, const void *bv, int len); +RAMFUNC int memcmp(const void *av, const void *bv, int len); +void memxor(uint8_t * dest, uint8_t * src, size_t len); char *strncat(char *dest, const char *src, unsigned int n); char *strcat(char *dest, const char *src); void strreverse(char s[]); diff --git a/client/cmddata.c b/client/cmddata.c index 38917a33..3ac8db25 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -891,21 +891,52 @@ int CmdSamples(const char *Cmd) int CmdTuneSamples(const char *Cmd) { - int cnt = 0; - int n = 255; - uint8_t got[255]; + int timeout = 0; + printf("\nMeasuring antenna characteristics, please wait..."); - PrintAndLog("Reading %d samples\n", n); - GetFromBigBuf(got,n,7256); // armsrc/apps.h: #define FREE_BUFFER_OFFSET 7256 - WaitForResponse(CMD_ACK,NULL); - for (int j = 0; j < n; j++) { - GraphBuffer[cnt++] = ((int)got[j]) - 128; + UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING}; + SendCommand(&c); + + UsbCommand resp; + while(!WaitForResponseTimeout(CMD_MEASURED_ANTENNA_TUNING,&resp,1000)) { + timeout++; + printf("."); + if (timeout > 7) { + PrintAndLog("\nNo response from Proxmark. Aborting..."); + return 1; + } + } + + int peakv, peakf; + int vLf125, vLf134, vHf; + vLf125 = resp.arg[0] & 0xffff; + vLf134 = resp.arg[0] >> 16; + vHf = resp.arg[1] & 0xffff;; + peakf = resp.arg[2] & 0xffff; + peakv = resp.arg[2] >> 16; + PrintAndLog(""); + PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0); + PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0); + PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1)); + PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0); + if (peakv<2000) + PrintAndLog("# Your LF antenna is unusable."); + else if (peakv<10000) + PrintAndLog("# Your LF antenna is marginal."); + if (vHf<2000) + PrintAndLog("# Your HF antenna is unusable."); + else if (vHf<5000) + PrintAndLog("# Your HF antenna is marginal."); + + for (int i = 0; i < 256; i++) { + GraphBuffer[i] = resp.d.asBytes[i] - 128; } PrintAndLog("Done! Divisor 89 is 134khz, 95 is 125khz.\n"); PrintAndLog("\n"); - GraphTraceLen = n; - RepaintGraphWindow(); + GraphTraceLen = 256; + ShowGraphWindow(); + return 0; } diff --git a/client/cmdhw.c b/client/cmdhw.c index 443973b8..642f63c5 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -13,12 +13,11 @@ #include #include #include "ui.h" -//#include "proxusb.h" #include "proxmark3.h" #include "cmdparser.h" +#include "cmddata.h" #include "cmdhw.h" #include "cmdmain.h" -#include "cmddata.h" /* low-level hardware control */ @@ -418,7 +417,7 @@ static command_t CommandTable[] = {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"}, {"setmux", CmdSetMux, 0, " -- Set the ADC mux to a specific value"}, {"tune", CmdTune, 0, "Measure antenna tuning"}, - {"version", CmdVersion, 0, "Show version inforation about the connected Proxmark"}, + {"version", CmdVersion, 0, "Show version information about the connected Proxmark"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlf.c b/client/cmdlf.c index 18bcf747..4bb683ee 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -70,7 +70,7 @@ int CmdFlexdemod(const char *Cmd) } } if (start == GraphTraceLen - LONG_WAIT) { - PrintAndLog("nothing to wait for"); + //PrintAndLog("nothing to wait for"); return 0; } @@ -200,7 +200,7 @@ int CmdIndalaDemod(const char *Cmd) } if (start == rawbit - uidlen + 1) { - PrintAndLog("nothing to wait for"); + //PrintAndLog("nothing to wait for"); return 0; } @@ -392,7 +392,7 @@ static void ChkBitstream(const char *str) int CmdLFSim(const char *Cmd) { - int i; + int i,j; static int gap; sscanf(Cmd, "%i", &gap); @@ -400,18 +400,20 @@ int CmdLFSim(const char *Cmd) /* convert to bitstream if necessary */ ChkBitstream(Cmd); - PrintAndLog("Sending data, please wait..."); - for (i = 0; i < GraphTraceLen; i += 48) { + 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}}; - int j; - for (j = 0; j < 48; j++) { + + for (j = 0; j < USB_CMD_DATA_SIZE; j++) { c.d.asBytes[j] = GraphBuffer[i+j]; } SendCommand(&c); WaitForResponse(CMD_ACK,NULL); + printf("."); } - PrintAndLog("Starting simulator..."); + printf("\n"); + PrintAndLog("Starting to simulate"); UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}}; SendCommand(&c); return 0; diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 32a0ff7c..d2026452 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -13,12 +13,16 @@ #include #include "proxmark3.h" #include "ui.h" -#include "util.h" #include "graph.h" +#include "cmdmain.h" #include "cmdparser.h" #include "cmddata.h" #include "cmdlf.h" #include "cmdlfem4x.h" +#include "util.h" +#include "data.h" +#define LF_TRACE_BUFF_SIZE 12000 +#define LF_BITSSTREAM_LEN 1000 static int CmdHelp(const char *Cmd); @@ -77,9 +81,9 @@ int CmdEM410xRead(const char *Cmd) /* Find out if we hit both high and low peaks */ for (j = 0; j < clock; j++) { - if (GraphBuffer[(i * clock) + j] == high) + if (GraphBuffer[(i * clock) + j] >= high) hithigh = 1; - else if (GraphBuffer[(i * clock) + j] == low) + else if (GraphBuffer[(i * clock) + j] <= low) hitlow = 1; /* it doesn't count if it's the first part of our read @@ -177,8 +181,10 @@ retest: } /* if we've already retested after flipping bits, return */ - if (retested++) + if (retested++){ + PrintAndLog("Failed to decode"); return 0; + } /* if this didn't work, try flipping bits */ for (i = 0; i < bit2idx; i++) diff --git a/client/cmdmain.c b/client/cmdmain.c index df3d4b2e..f041b24f 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -133,15 +133,14 @@ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeou UsbCommand resp; - if (response == NULL) { + if (response == NULL) response = &resp; - } + // Wait until the command is received for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { - while(getCommand(response)) - { + while(getCommand(response)) { if(response->cmd == cmd){ return true; } diff --git a/client/data.h b/client/data.h index 33ee9d04..41bd9a41 100644 --- a/client/data.h +++ b/client/data.h @@ -13,6 +13,9 @@ #include +//trace buffer size as defined in armsrc/apps.h TRACE_SIZE +#define TRACE_BUFFER_SIZE 4096 +#define FILE_PATH_SIZE 1000 #define SAMPLE_BUFFER_SIZE 64 extern uint8_t* sample_buf; diff --git a/client/graph.c b/client/graph.c index a0e85ffd..a2753af7 100644 --- a/client/graph.c +++ b/client/graph.c @@ -36,6 +36,8 @@ void AppendGraph(int redraw, int clock, int bit) int ClearGraph(int redraw) { int gtl = GraphTraceLen; + memset(GraphBuffer, 0x00, GraphTraceLen); + GraphTraceLen = 0; if (redraw) diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index f0eb964b..adedba85 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -514,7 +514,6 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) */ int bruteforceFile(const char *filename, uint16_t keytable[]) { - FILE *f = fopen(filename, "rb"); if(!f) { prnlog("Failed to read from file '%s'", filename); diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index 4749181e..f7115b19 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -725,7 +725,6 @@ int doTestsWithKnownInputs() int readKeyFile(uint8_t key[8]) { - FILE *f; int retval = 1; f = fopen("iclass_key.bin", "rb"); @@ -738,7 +737,6 @@ int readKeyFile(uint8_t key[8]) fclose(f); } return retval; - } diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index aeba31a7..13b9c8e7 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -64,6 +64,7 @@ local _commands = { CMD_ISO_15693_COMMAND_DONE = 0x0314, CMD_ISO_15693_FIND_AFI = 0x0315, CMD_ISO_15693_DEBUG = 0x0316, + CMD_LF_SNOOP_RAW_ADC_SAMPLES = 0x0317, --// For Hitag2 transponders CMD_SNOOP_HITAG = 0x0370, @@ -80,10 +81,13 @@ local _commands = { CMD_READER_LEGIC_RF = 0x0388, CMD_WRITER_LEGIC_RF = 0x0389, CMD_EPA_PACE_COLLECT_NONCE = 0x038A, + --//CMD_EPA_ = 0x038B, CMD_SNOOP_ICLASS = 0x0392, CMD_SIMULATE_TAG_ICLASS = 0x0393, CMD_READER_ICLASS = 0x0394, + CMD_READER_ICLASS_REPLAY = 0x0395, + CMD_ICLASS_ISO14443A_WRITE = 0x0397, --// For measurements of the antenna tuning CMD_MEASURE_ANTENNA_TUNING = 0x0400, @@ -100,8 +104,11 @@ local _commands = { CMD_MIFARE_EML_MEMSET = 0x0602, CMD_MIFARE_EML_MEMGET = 0x0603, CMD_MIFARE_EML_CARDLOAD = 0x0604, - CMD_MIFARE_EML_CSETBLOCK = 0x0605, - CMD_MIFARE_EML_CGETBLOCK = 0x0606, + + --// magic chinese card commands + CMD_MIFARE_CSETBLOCK = 0x0605, + CMD_MIFARE_CGETBLOCK = 0x0606, + CMD_MIFARE_CIDENT = 0x0607, CMD_SIMULATE_MIFARE_CARD = 0x0610, @@ -109,12 +116,33 @@ local _commands = { CMD_MIFARE_NESTED = 0x0612, CMD_MIFARE_READBL = 0x0620, + CMD_MIFAREU_READBL = 0x0720, + CMD_MIFARE_READSC = 0x0621, + CMD_MIFAREU_READCARD = 0x0721, + CMD_MIFARE_WRITEBL = 0x0622, + CMD_MIFAREU_WRITEBL = 0x0722, + CMD_MIFAREU_WRITEBL_COMPAT = 0x0723, + CMD_MIFARE_CHKKEYS = 0x0623, CMD_MIFARE_SNIFFER = 0x0630, + --//ultralightC + CMD_MIFAREUC_AUTH1 = 0x0724, + CMD_MIFAREUC_AUTH2 = 0x0725, + CMD_MIFAREUC_READCARD = 0x0726, + + --// mifare desfire + CMD_MIFARE_DESFIRE_READBL = 0x0728, + CMD_MIFARE_DESFIRE_WRITEBL = 0x0729, + CMD_MIFARE_DESFIRE_AUTH1 = 0x072a, + CMD_MIFARE_DESFIRE_AUTH2 = 0x072b, + CMD_MIFARE_DES_READER = 0x072c, + CMD_MIFARE_DESFIRE_INFO = 0x072d, + CMD_MIFARE_DESFIRE = 0x072e, + CMD_UNKNOWN = 0xFFFF, } @@ -184,7 +212,6 @@ function Command:getBytes() local data = self.data local cmd = self.cmd local arg1, arg2, arg3 = self.arg1, self.arg2, self.arg3 - return bin.pack("LLLLH",cmd, arg1, arg2, arg3,data); end diff --git a/client/lualibs/html_dumplib.lua b/client/lualibs/html_dumplib.lua index b8c7ccaa..44b6b352 100644 --- a/client/lualibs/html_dumplib.lua +++ b/client/lualibs/html_dumplib.lua @@ -47,6 +47,18 @@ local function save_HTML(javascript, filename) end +local function save_TEXT(data,filename) + -- Open the output file + local outfile = io.open(filename, "wb") + if outfile == nil then + return oops(string.format("Could not write to file %s",tostring(filename))) + end + + outfile:write(data) + io.close(outfile) + return filename +end + local function save_BIN(data, filename) -- Open the output file @@ -181,4 +193,6 @@ 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, + SaveAsText = save_TEXT, } diff --git a/client/lualibs/htmlskel.lua b/client/lualibs/htmlskel.lua index a52abdef..b468eb2d 100644 --- a/client/lualibs/htmlskel.lua +++ b/client/lualibs/htmlskel.lua @@ -55,6 +55,7 @@ local skel_1 = [[ return "UNKNOWN" } + add("04,,,Mifare TNP3xxx Activision 1K,0f01,01"); add("04,,,Mifare Mini,0004,09"); add("04,,,Mifare Classic 1k/Mifare Plus(4 byte UID) 2K SL1,0004,08"); add("04,,,Mifare Plus (4 byte UID) 2K SL2,0004,10"); diff --git a/client/lualibs/mf_default_keys.lua b/client/lualibs/mf_default_keys.lua index 4859ff0c..757112c6 100644 --- a/client/lualibs/mf_default_keys.lua +++ b/client/lualibs/mf_default_keys.lua @@ -141,6 +141,24 @@ local _keys = { '200000000000', 'a00000000000', 'b00000000000', + + --[[ + Should be for Mifare TNP3xxx tags A KEY. + --]] + '4b0b20107ccb', + + --[[ + Kiev metro cards + --]] + '8fe644038790', + 'f14ee7cae863', + '632193be1c3c', + '569369c5a0e5', + '9de89e070277', + 'eff603e1efe9', + '644672bd4afe', + + 'b5ff67cba951', } --- diff --git a/client/lualibs/read14a.lua b/client/lualibs/read14a.lua index 24021a1d..10e7c2d4 100644 --- a/client/lualibs/read14a.lua +++ b/client/lualibs/read14a.lua @@ -25,6 +25,7 @@ local ISO14A_COMMAND = { local ISO14443a_TYPES = {} ISO14443a_TYPES[0x00] = "NXP MIFARE Ultralight | Ultralight C" +ISO14443a_TYPES[0x01] = "NXP MIFARE TNP3xxx Activision Game Appliance" ISO14443a_TYPES[0x04] = "NXP MIFARE (various !DESFire !DESFire EV1)" ISO14443a_TYPES[0x08] = "NXP MIFARE CLASSIC 1k | Plus 2k" ISO14443a_TYPES[0x09] = "NXP MIFARE Mini 0.3k" diff --git a/client/nonce2key/crapto1.c b/client/nonce2key/crapto1.c index 61215420..6c0fcafa 100644 --- a/client/nonce2key/crapto1.c +++ b/client/nonce2key/crapto1.c @@ -549,7 +549,6 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], free(odd); free(even); return 0; - } s = statelist; diff --git a/client/scripts/formatMifare.lua b/client/scripts/formatMifare.lua index 1ced0c28..0d735e98 100644 --- a/client/scripts/formatMifare.lua +++ b/client/scripts/formatMifare.lua @@ -90,8 +90,10 @@ function GetCardInfo() elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k -- MIFARE Classic mini offers 320 bytes split into five sectors. numSectors = 5 - elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k" + elseif 0x10 == result.sak then -- NXP MIFARE Plus 2k numSectors = 32 + elseif 0x01 == sak then -- NXP MIFARE TNP3xxx 1K + numSectors = 16 else print("I don't know how many sectors there are on this type of card, defaulting to 16") end diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index 8d0d358f..eb98ffbf 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -133,6 +133,8 @@ function nested(key,sak) typ = 0 elseif 0x10 == sak then-- "NXP MIFARE Plus 2k" typ = 2 + elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K" + typ = 1 else print("I don't know how many sectors there are on this type of card, defaulting to 16") end diff --git a/client/util.c b/client/util.c index 15e911a1..a077aae9 100644 --- a/client/util.c +++ b/client/util.c @@ -13,6 +13,7 @@ #ifndef _WIN32 #include #include + int ukbhit(void) { int cnt = 0; @@ -112,6 +113,19 @@ char * sprint_hex(const uint8_t * data, const size_t len) { return buf; } +char * sprint_bin(const uint8_t * data, const size_t len) { + + int maxLen = ( len > 1024) ? 1024 : len; + static char buf[1024]; + char * tmp = buf; + size_t i; + + for (i=0; i < maxLen; ++i, ++tmp) + sprintf(tmp, "%u", data[i]); + + return buf; +} + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { @@ -131,6 +145,28 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } +//assumes little endian +char * printBits(size_t const size, void const * const ptr) +{ + unsigned char *b = (unsigned char*) ptr; + unsigned char byte; + static char buf[1024]; + char * tmp = buf; + int i, j; + + for (i=size-1;i>=0;i--) + { + for (j=7;j>=0;j--) + { + byte = b[i] & (1<>= j; + sprintf(tmp, "%u", byte); + tmp++; + } + } + return buf; +} + // ------------------------------------------------------------------------- // string parameters lib // ------------------------------------------------------------------------- @@ -248,3 +284,102 @@ int param_getstr(const char *line, int paramnum, char * str) return en - bg + 1; } + +/* +The following methods comes from Rfidler sourcecode. +https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/ +*/ + +// convert hex to sequence of 0/1 bit values +// returns number of bits converted +int hextobinarray(char *target, char *source) +{ + int length, i, count= 0; + char x; + + length = strlen(source); + // process 4 bits (1 hex digit) at a time + while(length--) + { + x= *(source++); + // capitalize + if (x >= 'a' && x <= 'f') + x -= 32; + // convert to numeric value + if (x >= '0' && x <= '9') + x -= '0'; + else if (x >= 'A' && x <= 'F') + x -= 'A' - 10; + else + return 0; + // output + for(i= 0 ; i < 4 ; ++i, ++count) + *(target++)= (x >> (3 - i)) & 1; + } + + return count; +} + +// convert hex to human readable binary string +int hextobinstring(char *target, char *source) +{ + int length; + + if(!(length= hextobinarray(target, source))) + return 0; + binarraytobinstring(target, target, length); + return length; +} + +// 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) +{ + unsigned char i, x; + int j = length; + + if(j % 4) + return 0; + + while(j) + { + for(i= x= 0 ; i < 4 ; ++i) + x += ( source[i] << (3 - i)); + sprintf(target,"%X", x); + ++target; + source += 4; + j -= 4; + } + return length; +} + +// convert binary array to human readable binary +void binarraytobinstring(char *target, char *source, int length) +{ + int i; + + for(i= 0 ; i < length ; ++i) + *(target++)= *(source++) + '0'; + *target= '\0'; +} + +// return parity bit required to match type +uint8_t GetParity( char *bits, uint8_t type, int length) +{ + int x; + + for(x= 0 ; length > 0 ; --length) + x += bits[length - 1]; + x %= 2; + + return x ^ type; +} + +// add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half +void wiegand_add_parity(char *target, char *source, char length) +{ + *(target++)= GetParity(source, EVEN, length / 2); + memcpy(target, source, length); + target += length; + *(target)= GetParity(source + length / 2, ODD, length / 2); +} diff --git a/client/util.h b/client/util.h index ce8876ed..22d41e0c 100644 --- a/client/util.h +++ b/client/util.h @@ -15,6 +15,7 @@ #include #include #include +#include "data.h" #ifndef MIN # define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -22,6 +23,10 @@ #ifndef MAX # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#define TRUE 1 +#define FALSE 0 +#define EVEN 0 +#define ODD 1 int ukbhit(void); @@ -33,9 +38,11 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount); void print_hex(const uint8_t * data, const size_t len); char * sprint_hex(const uint8_t * data, const size_t len); +char * sprint_bin(const uint8_t * data, const size_t len); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); +char * printBits(size_t const size, void const * const ptr); char param_getchar(const char *line, int paramnum); uint8_t param_get8(const char *line, int paramnum); @@ -45,3 +52,10 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base); int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt); int param_getstr(const char *line, int paramnum, char * str); + int hextobinarray( char *target, char *source); + int hextobinstring( char *target, char *source); + int binarraytohex( char *target, char *source, int length); +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); + diff --git a/common/Makefile.common b/common/Makefile.common index 2befd456..2b2bb2fb 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -54,7 +54,8 @@ DELETE=del /q MOVE=ren COPY=copy PATHSEP=\\# -FLASH_TOOL=winsrc\\prox.exe +#FLASH_TOOL=winsrc\\prox.exe +FLASH_TOOL=winsrc\\flash.exe DETECTED_OS=Windows endif @@ -67,6 +68,7 @@ INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gp CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 $(APP_CFLAGS) -Os LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n + LIBS = -lgcc THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(THUMBSRC)) diff --git a/common/cmd.c b/common/cmd.c index 49d9d942..0c3ecc1f 100644 --- a/common/cmd.c +++ b/common/cmd.c @@ -34,8 +34,6 @@ #include "string.h" #include "proxmark3.h" -//static UsbCommand txcmd; - bool cmd_receive(UsbCommand* cmd) { // Check if there is a usb packet available diff --git a/common/crc16.c b/common/crc16.c index d181bb2a..973cd103 100644 --- a/common/crc16.c +++ b/common/crc16.c @@ -8,6 +8,7 @@ #include "crc16.h" + unsigned short update_crc16( unsigned short crc, unsigned char c ) { unsigned short i, v, tcrc = 0; @@ -20,3 +21,25 @@ unsigned short update_crc16( unsigned short crc, unsigned char c ) 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; +} + +uint16_t crc16_ccitt(uint8_t const *message, int length) { + return crc16(message, length, 0xffff, 0x1021); +} diff --git a/common/crc16.h b/common/crc16.h index 055a60bc..d16d83b5 100644 --- a/common/crc16.h +++ b/common/crc16.h @@ -5,10 +5,11 @@ //----------------------------------------------------------------------------- // CRC16 //----------------------------------------------------------------------------- +#include #ifndef __CRC16_H #define __CRC16_H - unsigned short update_crc16(unsigned short crc, unsigned char c); - +uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial); +uint16_t crc16_ccitt(uint8_t const *message, int length); #endif diff --git a/common/usb_cdc.c b/common/usb_cdc.c index e2787fb6..54f6a8e8 100644 --- a/common/usb_cdc.c +++ b/common/usb_cdc.c @@ -223,7 +223,6 @@ byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0; void usb_disable() { // Disconnect the USB device AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU; -// SpinDelay(100); // Clear all lingering interrupts if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) { @@ -257,7 +256,6 @@ void usb_enable() { // Wait for a short while for (volatile size_t i=0; i<0x100000; i++); -// SpinDelay(100); // Reconnect USB reconnect AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU; @@ -304,8 +302,7 @@ uint32_t usb_read(byte_t* data, size_t len) { uint32_t packetSize, nbBytesRcv = 0; uint32_t time_out = 0; - while (len) - { + while (len) { if (!usb_check()) break; if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) { @@ -314,8 +311,7 @@ uint32_t usb_read(byte_t* data, size_t len) { while(packetSize--) data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT]; pUdp->UDP_CSR[AT91C_EP_OUT] &= ~(bank); - if (bank == AT91C_UDP_RX_DATA_BK0) - { + if (bank == AT91C_UDP_RX_DATA_BK0) { bank = AT91C_UDP_RX_DATA_BK1; } else { bank = AT91C_UDP_RX_DATA_BK0; diff --git a/include/at91sam7s512.h b/include/at91sam7s512.h index 5be13622..2cdcbce3 100644 --- a/include/at91sam7s512.h +++ b/include/at91sam7s512.h @@ -428,7 +428,7 @@ typedef struct _AT91S_PIO { #define PIO_PDR (AT91_CAST(AT91_REG *) 0x00000004) // (PIO_PDR) PIO Disable Register #define PIO_PSR (AT91_CAST(AT91_REG *) 0x00000008) // (PIO_PSR) PIO Status Register #define PIO_OER (AT91_CAST(AT91_REG *) 0x00000010) // (PIO_OER) Output Enable Register -#define PIO_ODR (AT91_CAST(AT91_REG *) 0x00000014) // (PIO_ODR) Output Disable Registerr +#define PIO_ODR (AT91_CAST(AT91_REG *) 0x00000014) // (PIO_ODR) Output Disable Register #define PIO_OSR (AT91_CAST(AT91_REG *) 0x00000018) // (PIO_OSR) Output Status Register #define PIO_IFER (AT91_CAST(AT91_REG *) 0x00000020) // (PIO_IFER) Input Filter Enable Register #define PIO_IFDR (AT91_CAST(AT91_REG *) 0x00000024) // (PIO_IFDR) Input Filter Disable Register diff --git a/include/proxmark3.h b/include/proxmark3.h index 8c9417da..b3530c64 100644 --- a/include/proxmark3.h +++ b/include/proxmark3.h @@ -14,6 +14,7 @@ // Might as well have the hardware-specific defines everywhere. #include "at91sam7s512.h" #include "config_gpio.h" +#include "usb_cmd.h" #define WDT_HIT() AT91C_BASE_WDTC->WDTC_WDCR = 0xa5000001 @@ -67,8 +68,6 @@ #define TRUE 1 #define FALSE 0 -#include - //#define PACKED __attribute__((__packed__)) #define LED_A_ON() HIGH(GPIO_LED_A) diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 69c3c1b6..c2e0b95b 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -150,8 +150,10 @@ typedef struct { #define CMD_MIFARE_READBL 0x0620 #define CMD_MIFAREU_READBL 0x0720 + #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 From 8472e72affb9b0e6166ab4871bbb6ea8e087e049 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 6 Jan 2015 11:20:48 +0100 Subject: [PATCH 77/78] ADD: added a lot of ic ids to cmdhf15.c Thanks to Asper for the list. ADD: added a manufacturer list for hf 14a reader, only viable when UID is double or triple size. Thanks to Asper for the list. --- client/Makefile | 4 +- client/cmdhf14a.c | 108 ++++++++++++++++++++++++++++++++++++- client/cmdhf14a.h | 1 + client/cmdhf15.c | 133 +++++++++++++++++++++++++++++++++++++++------- 4 files changed, 225 insertions(+), 21 deletions(-) diff --git a/client/Makefile b/client/Makefile index b2b215e1..ea8bd8a7 100644 --- a/client/Makefile +++ b/client/Makefile @@ -13,9 +13,9 @@ CXX=g++ VPATH = ../common OBJDIR = obj -LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a +LDLIBS = -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lm -lreadline -lpthread -lcrypto LDFLAGS = $(COMMON_FLAGS) -CFLAGS = -std=c99 -lcrypto -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/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 LUAPLATFORM = generic ifneq (,$(findstring MINGW,$(platform))) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 120d914a..2c3502cf 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -27,6 +27,108 @@ static int CmdHelp(const char *Cmd); static void waitCmd(uint8_t iLen); + +// structure and database for uid -> tagtype lookups +typedef struct { + uint8_t uid; + char* desc; +} manufactureName; + +const manufactureName manufactureMapping[] = { + // ID, "Vendor Country" + { 0x01, "Motorola UK" }, + { 0x02, "ST Microelectronics SA France" }, + { 0x03, "Hitachi, Ltd Japan" }, + { 0x04, "NXP Semiconductors Germany" }, + { 0x05, "Infineon Technologies AG Germany" }, + { 0x06, "Cylink USA" }, + { 0x07, "Texas Instrument France" }, + { 0x08, "Fujitsu Limited Japan" }, + { 0x09, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, + { 0x0A, "NEC Japan" }, + { 0x0B, "Oki Electric Industry Co. Ltd Japan" }, + { 0x0C, "Toshiba Corp. Japan" }, + { 0x0D, "Mitsubishi Electric Corp. Japan" }, + { 0x0E, "Samsung Electronics Co. Ltd Korea" }, + { 0x0F, "Hynix / Hyundai, Korea" }, + { 0x10, "LG-Semiconductors Co. Ltd Korea" }, + { 0x11, "Emosyn-EM Microelectronics USA" }, + { 0x12, "INSIDE Technology France" }, + { 0x13, "ORGA Kartensysteme GmbH Germany" }, + { 0x14, "SHARP Corporation Japan" }, + { 0x15, "ATMEL France" }, + { 0x16, "EM Microelectronic-Marin SA Switzerland" }, + { 0x17, "KSW Microtec GmbH Germany" }, + { 0x18, "ZMD AG Germany" }, + { 0x19, "XICOR, Inc. USA" }, + { 0x1A, "Sony Corporation Japan Identifier Company Country" }, + { 0x1B, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, + { 0x1C, "Emosyn USA" }, + { 0x1D, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, + { 0x1E, "Magellan Technology Pty Limited Australia" }, + { 0x1F, "Melexis NV BO Switzerland" }, + { 0x20, "Renesas Technology Corp. Japan" }, + { 0x21, "TAGSYS France" }, + { 0x22, "Transcore USA" }, + { 0x23, "Shanghai belling corp., ltd. China" }, + { 0x24, "Masktech Germany Gmbh Germany" }, + { 0x25, "Innovision Research and Technology Plc UK" }, + { 0x26, "Hitachi ULSI Systems Co., Ltd. Japan" }, + { 0x27, "Cypak AB Sweden" }, + { 0x28, "Ricoh Japan" }, + { 0x29, "ASK France" }, + { 0x2A, "Unicore Microsystems, LLC Russian Federation" }, + { 0x2B, "Dallas Semiconductor/Maxim USA" }, + { 0x2C, "Impinj, Inc. USA" }, + { 0x2D, "RightPlug Alliance USA" }, + { 0x2E, "Broadcom Corporation USA" }, + { 0x2F, "MStar Semiconductor, Inc Taiwan, ROC" }, + { 0x30, "BeeDar Technology Inc. USA" }, + { 0x31, "RFIDsec Denmark" }, + { 0x32, "Schweizer Electronic AG Germany" }, + { 0x33, "AMIC Technology Corp Taiwan" }, + { 0x34, "Mikron JSC Russia" }, + { 0x35, "Fraunhofer Institute for Photonic Microsystems Germany" }, + { 0x36, "IDS Microchip AG Switzerland" }, + { 0x37, "Kovio USA" }, + { 0x38, "HMT Microelectronic Ltd Switzerland Identifier Company Country" }, + { 0x39, "Silicon Craft Technology Thailand" }, + { 0x3A, "Advanced Film Device Inc. Japan" }, + { 0x3B, "Nitecrest Ltd UK" }, + { 0x3C, "Verayo Inc. USA" }, + { 0x3D, "HID Global USA" }, + { 0x3E, "Productivity Engineering Gmbh Germany" }, + { 0x3F, "Austriamicrosystems AG (reserved) Austria" }, + { 0x40, "Gemalto SA France" }, + { 0x41, "Renesas Electronics Corporation Japan" }, + { 0x42, "3Alogics Inc Korea" }, + { 0x43, "Top TroniQ Asia Limited Hong Kong" }, + { 0x44, "Gentag Inc (USA) USA" }, + { 0x00, "no tag-info available" } // must be the last entry +}; + + +// get a product description based on the UID +// uid[8] tag uid +// returns description of the best match +static char* getTagInfo(uint8_t uid) { + + int i, best = -1; + int len = sizeof(manufactureMapping) / sizeof(manufactureName); + + for ( i = 0; i < len; ++i ) { + if ( uid == manufactureMapping[i].uid) { + if (best == -1) { + best = i; + } + } + } + + if (best>=0) return manufactureMapping[best].desc; + + return manufactureMapping[i].desc; +} + int CmdHF14AList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list 14a' instead"); @@ -65,6 +167,11 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); + // Double & triple sized UID, can be mapped to a manufacturer. + if ( card.uidlen > 4 ) { + PrintAndLog("MANUFACTURER : %s", getTagInfo(card.uid[0])); + } + switch (card.sak) { case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break; case 0x01: PrintAndLog("TYPE : NXP TNP3xxx Activision Game Appliance"); break; @@ -83,7 +190,6 @@ int CmdHF14AReader(const char *Cmd) default: ; } - // 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 diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index 56329bed..163b6af2 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -20,4 +20,5 @@ int CmdHF14AReader(const char *Cmd); int CmdHF14ASim(const char *Cmd); int CmdHF14ASnoop(const char *Cmd); +static char* getTagInfo(uint8_t uid); #endif diff --git a/client/cmdhf15.c b/client/cmdhf15.c index b1e04e9a..d6ab2000 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -55,38 +55,135 @@ typedef struct { const productName uidmapping[] = { + // UID, #significant Bits, "Vendor(+Product)" - { 0xE001000000000000LL, 16, "Motorola" }, - { 0xE002000000000000LL, 16, "ST Microelectronics" }, - { 0xE003000000000000LL, 16, "Hitachi" }, - { 0xE004000000000000LL, 16, "NXP(Philips)" }, + { 0xE001000000000000LL, 16, "Motorola UK" }, + + // E0 02 xx + // 02 = ST Microelectronics + // XX = IC id (Chip ID Family) + { 0xE002000000000000LL, 16, "ST Microelectronics SA France" }, + { 0xE002050000000000LL, 24, "ST Microelectronics; LRI64 [IC id = 05]"}, + { 0xE002080000000000LL, 24, "ST Microelectronics; LRI2K [IC id = 08]"}, + { 0xE0020A0000000000LL, 24, "ST Microelectronics; LRIS2K [IC id = 10]"}, + { 0xE002440000000000LL, 24, "ST Microelectronics; LRIS64K [IC id = 68]"}, + + { 0xE003000000000000LL, 16, "Hitachi, Ltd Japan" }, + + // E0 04 xx + // 04 = Manufacturer code (Philips/NXP) + // XX = IC id (Chip ID Family) + //I-Code SLI SL2 ICS20 [IC id = 01] + //I-Code SLI-S [IC id = 02] + //I-Code SLI-L [IC id = 03] + //I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)] + //I-Code SLIX-S [IC id = 02 + bit36 set to 1] + //I-Code SLIX-L [IC id = 03 + bit36 set to 1] + { 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" }, { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)" }, { 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" }, { 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" }, - { 0xE005000000000000LL, 16, "Infineon" }, - { 0xE005400000000000LL, 24, "Infineon; 56x32bit" }, - { 0xE006000000000000LL, 16, "Cylinc" }, - { 0xE007000000000000LL, 16, "Texas Instrument; " }, + + // E0 05 XX .. .. .. + // 05 = Manufacturer code (Infineon) + // XX = IC id (Chip ID Family) + { 0xE005000000000000LL, 16, "Infineon Technologies AG Germany" }, + { 0xE005A10000000000LL, 24, "Infineon; SRF55V01P [IC id = 161] plain mode 1kBit"}, + { 0xE005A80000000000LL, 24, "Infineon; SRF55V01P [IC id = 168] pilot series 1kBit"}, + { 0xE005400000000000LL, 24, "Infineon; SRF55V02P [IC id = 64] plain mode 2kBit"}, + { 0xE005000000000000LL, 24, "Infineon; SRF55V10P [IC id = 00] plain mode 10KBit"}, + { 0xE005500000000000LL, 24, "Infineon; SRF55V02S [IC id = 80] secure mode 2kBit"}, + { 0xE005100000000000LL, 24, "Infineon; SRF55V10S [IC id = 16] secure mode 10KBit"}, + { 0xE0051E0000000000LL, 23, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, + { 0xE005200000000000LL, 21, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, + + { 0xE006000000000000LL, 16, "Cylink USA" }, + + + // E0 07 xx + // 07 = Texas Instruments + // XX = from bit 41 to bit 43 = product configuration - from bit 44 to bit 47 IC id (Chip ID Family) + //Tag IT RFIDType-I Plus, 2kBit, TI Inlay + //Tag-it HF-I Plus Inlay [IC id = 00] -> b'0000 000 2kBit + //Tag-it HF-I Plus Chip [IC id = 64] -> b'1000 000 2kBit + //Tag-it HF-I Standard Chip / Inlays [IC id = 96] -> b'1100 000 256Bit + //Tag-it HF-I Pro Chip / Inlays [IC id = 98] -> b'1100 010 256Bit, Password protection + { 0xE007000000000000LL, 16, "Texas Instrument France" }, { 0xE007000000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Inlay; 64x32bit" }, { 0xE007100000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Chip; 64x32bit" }, { 0xE007800000000000LL, 23, "Texas Instrument; Tag-it HF-I Plus (RF-HDT-DVBB tag or Third Party Products)" }, { 0xE007C00000000000LL, 23, "Texas Instrument; Tag-it HF-I Standard; 8x32bit" }, { 0xE007C40000000000LL, 23, "Texas Instrument; Tag-it HF-I Pro; 8x23bit; password" }, - { 0xE008000000000000LL, 16, "Fujitsu" }, - { 0xE009000000000000LL, 16, "Matsushita" }, - { 0xE00A000000000000LL, 16, "NEC" }, - { 0xE00B000000000000LL, 16, "Oki Electric" }, - { 0xE00C000000000000LL, 16, "Toshiba" }, - { 0xE00D000000000000LL, 16, "Mitsubishi" }, - { 0xE00E000000000000LL, 16, "Samsung" }, - { 0xE00F000000000000LL, 16, "Hyundai" }, - { 0xE010000000000000LL, 16, "LG-Semiconductors" }, + + { 0xE008000000000000LL, 16, "Fujitsu Limited Japan" }, + { 0xE009000000000000LL, 16, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, + { 0xE00A000000000000LL, 16, "NEC Japan" }, + { 0xE00B000000000000LL, 16, "Oki Electric Industry Co. Ltd Japan" }, + { 0xE00C000000000000LL, 16, "Toshiba Corp. Japan" }, + { 0xE00D000000000000LL, 16, "Mitsubishi Electric Corp. Japan" }, + { 0xE00E000000000000LL, 16, "Samsung Electronics Co. Ltd Korea" }, + { 0xE00F000000000000LL, 16, "Hynix / Hyundai, Korea" }, + { 0xE010000000000000LL, 16, "LG-Semiconductors Co. Ltd Korea" }, + { 0xE011000000000000LL, 16, "Emosyn-EM Microelectronics USA" }, + { 0xE012000000000000LL, 16, "HID Corporation" }, - { 0xE016000000000000LL, 16, "EM-Marin SA (Skidata)" }, + { 0xE012000000000000LL, 16, "INSIDE Technology France" }, + { 0xE013000000000000LL, 16, "ORGA Kartensysteme GmbH Germany" }, + { 0xE014000000000000LL, 16, "SHARP Corporation Japan" }, + { 0xE015000000000000LL, 16, "ATMEL France" }, + + { 0xE016000000000000LL, 16, "EM Microelectronic-Marin SA Switzerland (Skidata)" }, { 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); EM4034? no 'read', just 'readmulti'" }, { 0xE0160c0000000000LL, 24, "EM-Marin SA; EM4035?" }, { 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135; 36x64bit start page 13" }, { 0xE016940000000000LL, 24, "EM-Marin SA (Skidata); 51x64bit" }, + + { 0xE017000000000000LL, 16, "KSW Microtec GmbH Germany" }, + { 0xE018000000000000LL, 16, "ZMD AG Germany" }, + { 0xE019000000000000LL, 16, "XICOR, Inc. USA" }, + { 0xE01A000000000000LL, 16, "Sony Corporation Japan Identifier Company Country" }, + { 0xE01B000000000000LL, 16, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, + { 0xE01C000000000000LL, 16, "Emosyn USA" }, + { 0xE01D000000000000LL, 16, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, + { 0xE01E000000000000LL, 16, "Magellan Technology Pty Limited Australia" }, + { 0xE01F000000000000LL, 16, "Melexis NV BO Switzerland" }, + { 0xE020000000000000LL, 16, "Renesas Technology Corp. Japan" }, + { 0xE021000000000000LL, 16, "TAGSYS France" }, + { 0xE022000000000000LL, 16, "Transcore USA" }, + { 0xE023000000000000LL, 16, "Shanghai belling corp., ltd. China" }, + { 0xE024000000000000LL, 16, "Masktech Germany Gmbh Germany" }, + { 0xE025000000000000LL, 16, "Innovision Research and Technology Plc UK" }, + { 0xE026000000000000LL, 16, "Hitachi ULSI Systems Co., Ltd. Japan" }, + { 0xE027000000000000LL, 16, "Cypak AB Sweden" }, + { 0xE028000000000000LL, 16, "Ricoh Japan" }, + { 0xE029000000000000LL, 16, "ASK France" }, + { 0xE02A000000000000LL, 16, "Unicore Microsystems, LLC Russian Federation" }, + { 0xE02B000000000000LL, 16, "Dallas Semiconductor/Maxim USA" }, + { 0xE02C000000000000LL, 16, "Impinj, Inc. USA" }, + { 0xE02D000000000000LL, 16, "RightPlug Alliance USA" }, + { 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" }, + { 0xE034000000000000LL, 16, "Mikron JSC Russia" }, + { 0xE035000000000000LL, 16, "Fraunhofer Institute for Photonic Microsystems Germany" }, + { 0xE036000000000000LL, 16, "IDS Microchip AG Switzerland" }, + { 0xE037000000000000LL, 16, "Kovio USA" }, + { 0xE038000000000000LL, 16, "HMT Microelectronic Ltd Switzerland Identifier Company Country" }, + { 0xE039000000000000LL, 16, "Silicon Craft Technology Thailand" }, + { 0xE03A000000000000LL, 16, "Advanced Film Device Inc. Japan" }, + { 0xE03B000000000000LL, 16, "Nitecrest Ltd UK" }, + { 0xE03C000000000000LL, 16, "Verayo Inc. USA" }, + { 0xE03D000000000000LL, 16, "HID Global USA" }, + { 0xE03E000000000000LL, 16, "Productivity Engineering Gmbh Germany" }, + { 0xE03F000000000000LL, 16, "Austriamicrosystems AG (reserved) Austria" }, + { 0xE040000000000000LL, 16, "Gemalto SA France" }, + { 0xE041000000000000LL, 16, "Renesas Electronics Corporation Japan" }, + { 0xE042000000000000LL, 16, "3Alogics Inc Korea" }, + { 0xE043000000000000LL, 16, "Top TroniQ Asia Limited Hong Kong" }, + { 0xE044000000000000LL, 16, "Gentag Inc (USA) USA" }, { 0,0,"no tag-info available" } // must be the last entry }; From 1365b3a35fb1151c0cda22965959591317e2b80c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 6 Jan 2015 12:26:15 +0100 Subject: [PATCH 78/78] fixed: some minor bugs from the previous merge with master. It compiles clean now. --- client/cmdhf14a.h | 2 +- client/cmdmain.c | 9 ++++----- client/nonce2key/crapto1.c | 2 -- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index 163b6af2..d2e203a1 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -20,5 +20,5 @@ int CmdHF14AReader(const char *Cmd); int CmdHF14ASim(const char *Cmd); int CmdHF14ASnoop(const char *Cmd); -static char* getTagInfo(uint8_t uid); + #endif diff --git a/client/cmdmain.c b/client/cmdmain.c index ee39acc0..82d0d740 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -131,13 +131,12 @@ int getCommand(UsbCommand* response) */ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) { - + UsbCommand resp; if (response == NULL) - response = &resp; + response = &resp; - - // Wait until the command is received - for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { + // Wait until the command is received + for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { while(getCommand(response)) { if(response->cmd == cmd){ diff --git a/client/nonce2key/crapto1.c b/client/nonce2key/crapto1.c index fafbd426..6c0fcafa 100644 --- a/client/nonce2key/crapto1.c +++ b/client/nonce2key/crapto1.c @@ -551,8 +551,6 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], return 0; } - } - s = statelist; for(o = odd; *o != -1; ++o) for(e = even; *e != -1; ++e)