From f087591d5921b64f2c589ea9c608cfea61decd31 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 26 Feb 2016 21:11:56 +0100 Subject: [PATCH 01/16] FIX: calcs wiegand correct, adds wiegand parity correct, adds checksum correct, add even parity to blocks correct. - when ran it clones nice, the "lf search" finds a pyramid och checksom is ok. However, the wiegand decode is wrong. Something about where in bitarray to put the startformat bit and wiegand bits... --- client/cmdlfpyramid.c | 69 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 23c44059..c1c23729 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -48,29 +48,35 @@ int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { uint8_t pre[128]; memset(pre, 0x00, sizeof(pre)); - // add preamble - pyramidBits[7]=1; - num_to_bytebits(26, 8, pre); - - // get wiegand - uint8_t wiegand[24]; + // format start bit + + // Get 26 wiegand from FacilityCode, CardNumber + uint8_t wiegand[26]; num_to_bytebits(fc, 8, wiegand); num_to_bytebits(cn, 16, wiegand+8); - // add wiegand parity bits - wiegand_add_parity(pre+8, wiegand, 24); + // add wiegand parity bits (dest, source, len) + wiegand_add_parity(pre+71, wiegand, 26); - // add paritybits - addParity(pre, pyramidBits+8, 66, 4, 1); + // add paritybits (bitsource, dest, sourcelen, paritylen, parityType (odd, even,) + addParity(pre+8, pyramidBits+8, 112, 8, 1); // add checksum - // this is wrong. - uint32_t crc = CRC8Maxim(wiegand, 13); - num_to_bytebits(crc, 8, pre+120); - + uint8_t csBuff[13]; + for (uint8_t i = 0; i < 13; i++) + csBuff[i] = bytebits_to_byte(pyramidBits + 16 + (i*8), 8); + + uint32_t crc = CRC8Maxim(csBuff, 13); + num_to_bytebits(crc, 8, pyramidBits+120); return 1; } +/* +9 - 00001001 +33278 - 1000000111111110 + 10000100110000001 +000101010101010101010101082602 +*/ int CmdPyramidRead(const char *Cmd) { // read lf silently CmdLFRead("s"); @@ -85,28 +91,25 @@ int CmdPyramidClone(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_pyramid_clone(); - uint32_t facilitycode=0, cardnumber=0; + uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; + uint8_t bits[128]; uint8_t *bs = bits; - memset(bs,0,sizeof(bits)); + memset(bs, 0x00, sizeof(bits)); + //Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks uint32_t blocks[5] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4< Date: Fri, 26 Feb 2016 22:10:27 +0100 Subject: [PATCH 02/16] FIX: "LF PYRAMID CLONE" now works. --- client/cmdlfpyramid.c | 20 ++++++++------------ client/util.c | 12 +++++++----- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index c1c23729..06790012 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -49,15 +49,17 @@ int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { memset(pre, 0x00, sizeof(pre)); // format start bit + pre[79] = 1; // Get 26 wiegand from FacilityCode, CardNumber - uint8_t wiegand[26]; + uint8_t wiegand[24]; + memset(wiegand, 0x00, sizeof(wiegand)); num_to_bytebits(fc, 8, wiegand); num_to_bytebits(cn, 16, wiegand+8); // add wiegand parity bits (dest, source, len) - wiegand_add_parity(pre+71, wiegand, 26); - + wiegand_add_parity(pre+80, wiegand, 24); + // add paritybits (bitsource, dest, sourcelen, paritylen, parityType (odd, even,) addParity(pre+8, pyramidBits+8, 112, 8, 1); @@ -68,15 +70,10 @@ int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { uint32_t crc = CRC8Maxim(csBuff, 13); num_to_bytebits(crc, 8, pyramidBits+120); + return 1; } -/* -9 - 00001001 -33278 - 1000000111111110 - 10000100110000001 -000101010101010101010101082602 -*/ int CmdPyramidRead(const char *Cmd) { // read lf silently CmdLFRead("s"); @@ -93,9 +90,8 @@ int CmdPyramidClone(const char *Cmd) { uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; - uint8_t bits[128]; - uint8_t *bs = bits; - memset(bs, 0x00, sizeof(bits)); + uint8_t bs[129]; + memset(bs, 0x00, sizeof(bs)); //Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks uint32_t blocks[5] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4< MAX_BIN_BREAK_LENGTH ) ? MAX_BIN_BREAK_LENGTH : len; else @@ -147,9 +149,8 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea memset(buf, 0x00, sizeof(buf)); char *tmp = buf; - size_t in_index = 0; // loop through the out_index to make sure we don't go too far - for (size_t out_index=0; out_index < max_len-2; out_index++) { + for (out_index=0; out_index < max_len-2; out_index++) { // set character sprintf(tmp++, "%u", (unsigned int) data[in_index]); // check if a line break is needed and we have room to print it in our array @@ -157,10 +158,11 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea // increment and print line break out_index++; sprintf(tmp++, "%s","\n"); - } + } in_index++; } - + // last char. + sprintf(tmp++, "%u", (unsigned int) data[in_index]); return buf; } -- 2.39.5 From ce9a7cbf33ff29722d7e7f6adec4fe149f55ce87 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 26 Feb 2016 22:40:13 +0100 Subject: [PATCH 03/16] ADD: "LF PYRAMID SIM" --- client/cmdlfpyramid.c | 48 +++++++++++++++++++++---------------------- client/cmdlfpyramid.h | 2 -- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 06790012..0b6fe4dc 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -38,11 +38,6 @@ int usage_lf_pyramid_sim(void) { return 0; } -// calc checksum -int GetWiegandFromPyramid(const char *id, uint32_t *fc, uint32_t *cn) { - return 0; -} - int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { uint8_t pre[128]; @@ -90,7 +85,7 @@ int CmdPyramidClone(const char *Cmd) { uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; - uint8_t bs[129]; + uint8_t bs[128]; memset(bs, 0x00, sizeof(bs)); //Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks @@ -104,9 +99,6 @@ int CmdPyramidClone(const char *Cmd) { facilitycode = (fc & 0x000000FF); cardnumber = (cn & 0x0000FFFF); - // get wiegand from printed number. - //GetWiegandFromPyramid(Cmd, &facilitycode, &cardnumber); - if ( !GetPyramidBits(facilitycode, cardnumber, bs)) { PrintAndLog("Error with tag bitstream generation."); return 1; @@ -140,29 +132,37 @@ int CmdPyramidClone(const char *Cmd) { } int CmdPyramidSim(const char *Cmd) { - // uint32_t id = 0; - // uint64_t rawID = 0; - // uint8_t clk = 50, encoding = 1, separator = 0, invert = 0; char cmdp = param_getchar(Cmd, 0); if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_pyramid_sim(); - // id = param_get32ex(Cmd, 0, 0, 16); - // if (id == 0) return usage_lf_pyramid_sim(); + uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0; + + uint8_t bs[128]; + size_t size = sizeof(bs); + memset(bs, 0x00, size); + + // Pyramid uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 0 + uint64_t arg1, arg2; + arg1 = (10 << 8) + 8; + arg2 = 50 | 0; - //rawID = getPyramidBits(id); + if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_pyramid_sim(); - // uint16_t arg1, arg2; - // size_t size = 64; - // arg1 = clk << 8 | encoding; - // arg2 = invert << 8 | separator; + facilitycode = (fc & 0x000000FF); + cardnumber = (cn & 0x0000FFFF); + + if ( !GetPyramidBits(facilitycode, cardnumber, bs)) { + PrintAndLog("Error with tag bitstream generation."); + return 1; + } - // PrintAndLog("Simulating - ID: %08X, Raw: %08X%08X",id,(uint32_t)(rawID >> 32),(uint32_t) (rawID & 0xFFFFFFFF)); + PrintAndLog("Simulating - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); - // UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}}; - // num_to_bytebits(rawID, size, c.d.asBytes); - // clearCommandBuffer(); - // SendCommand(&c); + UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}}; + memcpy(c.d.asBytes, bs, size); + clearCommandBuffer(); + SendCommand(&c); return 0; } diff --git a/client/cmdlfpyramid.h b/client/cmdlfpyramid.h index 75d3fe69..d00b7d06 100644 --- a/client/cmdlfpyramid.h +++ b/client/cmdlfpyramid.h @@ -26,7 +26,5 @@ int CmdPyramidSim(const char *Cmd); int usage_lf_pyramid_clone(void); int usage_lf_pyramid_sim(void); - -int GetWiegandFromPyramid(const char *id, uint32_t *sitecode, uint32_t *usercode); #endif -- 2.39.5 From 4b3655e7f4dbb40b049d550612b1d03cc0900d3b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 27 Feb 2016 09:21:19 +0100 Subject: [PATCH 04/16] FIX: spelling misstakes. FIX: output of block number should be two digits for nicer layout FIX: strange branching in the pyramid demod in cmddata.c, it will now always print the unknown length message FIX: another go at the coverity scan bug in proxmark3.c. (resource leak for cmd) --- client/cmddata.c | 5 +---- client/cmdlf.c | 2 +- client/cmdlfpyramid.c | 16 ++++++++-------- client/proxmark3.c | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index 9b893328..8e0668f7 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -1483,10 +1483,7 @@ int CmdFSKdemodPyramid(const char *Cmd) PrintAndLog("Pyramid ID Found - BitLength: %d, FC: %d, Card: %d - Raw: %08x%08x%08x%08x", fmtLen, fc, cardnum, rawHi3, rawHi2, rawHi, rawLo); } else { cardnum = bytebits_to_byte(BitStream+81, 16); - if (fmtLen > 32) - PrintAndLog("Pyramid ID Found - BitLength: %d -unknown BitLength- (%d), Raw: %08x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo); - else - PrintAndLog("Pyramid ID Found - BitLength: %d -unknown BitLength- (%d), Raw: %08x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo); + PrintAndLog("Pyramid ID Found - BitLength: %d -unknown BitLength- (%d), Raw: %08x%08x%08x%08x", fmtLen, cardnum, rawHi3, rawHi2, rawHi, rawLo); } if (checksum == checkCS) PrintAndLog("Checksum %02x passed", checksum); diff --git a/client/cmdlf.c b/client/cmdlf.c index 8363d253..8469d80d 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -1218,7 +1218,7 @@ static command_t CommandTable[] = {"io", CmdLFIO, 1, "{ IOPROX RFIDs... }"}, {"pcf7931", CmdLFPCF7931, 1, "{ PCF7931 RFIDs... }"}, {"presco", CmdLFPresco, 1, "{ Presco RFIDs... }"}, - {"pyramid", CmdLFPyramid, 1, "{ Farepointe/Pyramid RFIDs... }"}, + {"pyramid", CmdLFPyramid, 1, "{ Farpointe/Pyramid RFIDs... }"}, {"ti", CmdLFTI, 1, "{ TI RFIDs... }"}, {"t55xx", CmdLFT55XX, 1, "{ T55xx RFIDs... }"}, {"viking", CmdLFViking, 1, "{ Viking RFIDs... }"}, diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 0b6fe4dc..3e94ce44 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -12,7 +12,7 @@ static int CmdHelp(const char *Cmd); int usage_lf_pyramid_clone(void){ - PrintAndLog("clone a Farepointe/Pyramid tag to a T55x7 tag."); + PrintAndLog("clone a Farpointe/Pyramid tag to a T55x7 tag."); PrintAndLog("Per pyramid format, the facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); PrintAndLog(""); PrintAndLog("Usage: lf pyramid clone "); @@ -25,7 +25,7 @@ int usage_lf_pyramid_clone(void){ } int usage_lf_pyramid_sim(void) { - PrintAndLog("Enables simulation of Farepointe/Pyramid card with specified card number."); + PrintAndLog("Enables simulation of Farpointe/Pyramid card with specified card number."); PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); PrintAndLog("Per pyramid format, the facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); PrintAndLog(""); @@ -84,7 +84,7 @@ int CmdPyramidClone(const char *Cmd) { if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_pyramid_clone(); uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; - + uint8_t i; uint8_t bs[128]; memset(bs, 0x00, sizeof(bs)); @@ -109,16 +109,16 @@ int CmdPyramidClone(const char *Cmd) { blocks[3] = bytebits_to_byte(bs+64,32); blocks[4] = bytebits_to_byte(bs+96,32); - PrintAndLog("Preparing to clone Farepointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); + PrintAndLog("Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); PrintAndLog("Blk | Data "); PrintAndLog("----+------------"); - for ( uint8_t i=0; i<5; ++i ) - PrintAndLog(" %d | %08x",i , blocks[i]); + for ( i = 0; i<5; ++i ) + PrintAndLog(" %02d | %08x", i, blocks[i]); UsbCommand resp; UsbCommand c = {CMD_T55XX_WRITE_BLOCK, {0,0,0}}; - for ( uint8_t i=0; i<5; ++i ) { + for ( i = 0; i<5; ++i ) { c.arg[0] = blocks[i]; c.arg[1] = i; clearCommandBuffer(); @@ -157,7 +157,7 @@ int CmdPyramidSim(const char *Cmd) { return 1; } - PrintAndLog("Simulating - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); + PrintAndLog("Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); UsbCommand c = {CMD_FSK_SIM_TAG, {arg1, arg2, size}}; memcpy(c.d.asBytes, bs, size); diff --git a/client/proxmark3.c b/client/proxmark3.c index edad9521..0fa55425 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -168,9 +168,9 @@ static void *main_loop(void *targ) { // exit or quit if (ret == 99) break; + } free(cmd); cmd = 0; - } } else { printf("\n"); break; -- 2.39.5 From 220d638d926dfa239e136c470a853f612b5ee1d1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 27 Feb 2016 09:24:40 +0100 Subject: [PATCH 05/16] ADD: started to add a lua script for reading 14b tags, will help when making scripts against iso 14443b tags. --- client/lualibs/read14b.lua | 238 +++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 client/lualibs/read14b.lua diff --git a/client/lualibs/read14b.lua b/client/lualibs/read14b.lua new file mode 100644 index 00000000..dd720fea --- /dev/null +++ b/client/lualibs/read14b.lua @@ -0,0 +1,238 @@ + +--[[ + This is a library to read 14443b tags. It can be used something like this + + local reader = require('read14b') + result, err = reader.select1443b() + if not result then + print(err) + return + end + print(result.name) + +--]] +-- Loads the commands-library +local cmds = require('commands') +local utils = require('utils') +local TIMEOUT = 10000 -- Shouldn't take longer than 2 seconds + +local function parse1443b_reqb(data) + --[[ + --]] + local pcb = data:sub(1,2) + local uid = data:sub(3,10) + local pps = data:sub(11,18) + local ats = data:sub(19,24) + local crc = data:sub(25,29) + return { pcb = pcb, uid = uid, pps = pps, ats = ats, crc = crc, cid = '' } +end + +local function parse1443b_attrib(data) + --[[ + --]] + local attrib = data:sub(1,2) + local crc = data:sub(3,7) + return { attrib = attrib, crc = crc } +end + + +--- Sends a USBpacket to the device +-- @param command - the usb packet to send +-- @param readresponse - if set to true, we read the device answer packet +-- which is usually recipe for fail. If not sent, the host will wait 2s for a +-- response of type CMD_ACK +-- @return packet,nil if successfull +-- nil, errormessage if unsuccessfull +local function sendToDevice(cmd, readresponse) + core.clearCommandBuffer() + local err = core.SendCommand(cmd:getBytes()) + if err then + print(err) + return nil, err + end + if readresponse == 0 then return '',nil end + local response = core.WaitForResponseTimeout(cmds.CMD_ACK, TIMEOUT) + if response == nil then return nil, nil end + return response,nil +end +--- Picks out and displays the data read from a tag +-- Specifically, takes a usb packet, converts to a Command +-- (as in commands.lua), takes the data-array and +-- reads the number of bytes specified in arg1 (arg0 in c-struct) +-- and displays the data +-- @param usbpacket the data received from the device +local function showData(usbpacket) + local response = Command.parse(usbpacket) + local len = tonumber(response.arg1) * 2 + local data = string.sub(response.data, 0, len); + print("<< ",data) +end + +--- +-- Sends a usbpackage , "hf 14b raw" and the 14bCrc is added to the rawdata before sending +local function sendRaw(rawdata, readresponse, addcrc) + -- add crc first + local rawdata_crc = rawdata + if ( addcrc == 1) then + rawdata_crc = utils.Crc14b(rawdata) + end + print(">> ", rawdata_crc) + + local command = Command:new{cmd = cmds.CMD_ISO_14443B_COMMAND, + arg1 = #rawdata_crc/2, -- LEN of data, which is half the length of the ASCII-string rawdata + arg2 = readresponse, -- read response + arg3 = 1, -- leave power on + data = rawdata_crc} -- raw data bytes + return sendToDevice(command, readresponse) +end + +-- This function does a connect and retrieves some info +-- @return if successfull: an table containing card info +-- @return if unsuccessfull : nil, error + +-- void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, uint8_t data[]) +local function select1443b() + + local result, infoReqb, infoAttrib, infoPong, err, resp, len, data + local goodReqbResponse = false + --REQB + local p = 5 + while p > 0 do + -- 05 00 08 + -- 05 + -- command (REQB/WUPB) + -- 00 + -- AFI application family identifier ( 00 == all sorts) + -- 08 (ie WUPB) + -- bit 0-1-2 | N slots ( 0 = 1, 1 = 2, 2 = 4, 3 = 8, 4 == 16) + -- bit 3 | (1== WUPB, 0 == REQB) + -- bit 4-5-6-7 | AFI application family identifier + local result, err = sendRaw('050000', 1, 1) + if result then + resp = Command.parse( result ) + len = tonumber(resp.arg1) * 2 + local data = string.sub(resp.data, 0, len) + if ( resp.arg1 == 14 ) then + --print ('DATA ::', data) + infoReqb, err = parse1443b_reqb(data) + --print(infoReqb.pcb, infoReqb.uid, infoReqb.pps, infoReqb.ats, infoReqb.crc) + goodReqbResponse = true + break -- break while loop. REQB got a good response + end + end + + -- send some strange 0A/0C + if ( p < 3) then + sendRaw('0A', 0, 0) + sendRaw('0C', 0, 0) + end + + p = p - 1 + print('retrying') + end + + if goodReqbResponse == false then + err = "No response from card" + print(err) + return nil, err + end + --SLOT MARKER + -- result, err = sendRaw('05', 1, 1) + -- if result then + -- showData(result) + -- resp = Command.parse( result ) + -- if arg1 == 0 then + -- return nil, "iso14443b card - SLOT MARKER failed" + -- end + -- len = tonumber(resp.arg1) * 2 + -- data = string.sub(resp.data, 0, len) + -- infoAttrib, err = parse1443b_attrib(data) + -- print( infoAttrib.attrib, infoAttrib.crc) + -- else + -- err ="No response from card" + -- print(err) + -- return nil, err + -- end + + --ATTRIB + local cid = '00' + result, err = sendRaw('1D'..infoReqb.uid..'000801'..cid, 1, 1) + if result then + showData(result) + resp = Command.parse( result ) + if resp.arg1 == 0 then + return nil, "iso14443b card - ATTRIB failed" + end + len = tonumber(resp.arg1) * 2 + data = string.sub(resp.data, 0, len) + infoAttrib, err = parse1443b_attrib(data) + infoReqb.cid = infoAttrib.attrib:sub(2,2) + else + err ="No response from card" + print(err) + return nil, err + end + + --PING / PONG - Custom Anticollison for Navigo. + local ping = ('BA00') + result, err = sendRaw(ping, 1, 1) + if result then + resp = Command.parse( result ) + if arg1 == 0 then + return nil, "iso14443b card - PING/PONG failed" + end + showData(result) + else + err = "No response from card" + print(err) + return nil, err + end + + return infoReqb +end + +--- +-- Waits for a mifare card to be placed within the vicinity of the reader. +-- @return if successfull: an table containing card info +-- @return if unsuccessfull : nil, error +local function waitFor14443b() + print("Waiting for card... press any key to quit") + while not core.ukbhit() do + res, err = select1443b() + if res then return res end + -- err means that there was no response from card + end + return nil, "Aborted by user" +end + +local function disconnect(uid) + + local halt = ('50'..uid) -- 50 UID0 UID1 UID2 UID3 CRC1 CRC2 + result, err = sendRaw(halt, 1, 1) + if result then + resp = Command.parse( result ) + showData(result) -- expected answer is 00 CRC1 CRC2 + else + err = "No response from card" + print(err) + return nil, err + end + + -- shutdown raw command / pm3 device. + local command = Command:new{ cmd = cmds.CMD_ISO_14443B_COMMAND, arg1 = 0, arg2 = 0, arg3 = 0 } + -- We can ignore the response here, no ACK is returned for this command + -- Check /armsrc/iso14443b.c, SendRawCommand14443B() for details + return sendToDevice(command, 0) +end + +local library = { + select1443b = select1443b, + select = select1443b, + waitFor14443b = waitFor14443b, + sendToDevice = sendToDevice, + disconnect = disconnect, + sendRaw = sendRaw, + showData = showData, +} + +return library \ No newline at end of file -- 2.39.5 From 69c4516d32bdd01a5220d7e25dc41b3922a46bb4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 27 Feb 2016 12:12:05 +0100 Subject: [PATCH 06/16] chg: minor changes to text, explaining current implementation for "lf pyramid clone/sim" only works for 26bits. --- armsrc/lfops.c | 1 - client/cmdlfpyramid.c | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 2e2cfd57..7f61c78d 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1259,7 +1259,6 @@ void T55xxWakeUp(uint32_t Pwd){ } /*-------------- Cloning routines -----------*/ - void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { // write last block first and config block last (if included) for (uint8_t i = numblocks+startblock; i > startblock; i--) diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 3e94ce44..d1b8f6b8 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -13,7 +13,8 @@ static int CmdHelp(const char *Cmd); int usage_lf_pyramid_clone(void){ PrintAndLog("clone a Farpointe/Pyramid tag to a T55x7 tag."); - PrintAndLog("Per pyramid format, the facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); + PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. "); + PrintAndLog("Currently work only on 26bit"); PrintAndLog(""); PrintAndLog("Usage: lf pyramid clone "); PrintAndLog("Options :"); @@ -27,7 +28,8 @@ int usage_lf_pyramid_clone(void){ int usage_lf_pyramid_sim(void) { PrintAndLog("Enables simulation of Farpointe/Pyramid card with specified card number."); PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLog("Per pyramid format, the facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); + PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); + PrintAndLog("Currently work only on 26bit"); PrintAndLog(""); PrintAndLog("Usage: lf pyramid sim "); PrintAndLog("Options :"); @@ -38,6 +40,8 @@ int usage_lf_pyramid_sim(void) { return 0; } + +// Works for 26bits. int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { uint8_t pre[128]; @@ -70,11 +74,8 @@ int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { } int CmdPyramidRead(const char *Cmd) { - // read lf silently CmdLFRead("s"); - // get samples silently getSamples("30000",false); - // demod and output Pyramid ID return CmdFSKdemodPyramid(""); } -- 2.39.5 From 90639dd1cc7d812f21dd20710916de9478ebefe4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 27 Feb 2016 18:57:49 +0100 Subject: [PATCH 07/16] FIX: lets see if this fixes the pyramid clone crash on OSX --- client/cmdlfpyramid.c | 14 +++++++------- client/proxmark3.h | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index d1b8f6b8..8a48516c 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -85,15 +85,10 @@ int CmdPyramidClone(const char *Cmd) { if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_pyramid_clone(); uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; + uint32_t blocks[5]; uint8_t i; uint8_t bs[128]; memset(bs, 0x00, sizeof(bs)); - - //Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks - uint32_t blocks[5] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4< +#define lx PRIx32 #define llx PRIx64 #define lli PRIi64 #define llu PRIu64 -- 2.39.5 From 98c799ba499b81a02bef8f04ccb5149394c4d4d5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 27 Feb 2016 19:21:49 +0100 Subject: [PATCH 08/16] BUG: smash stack in addParity call. Didn't take in consideration that it adds bits per parity to the array.. --- client/cmdlfpyramid.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 8a48516c..0f992cc2 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -60,7 +60,9 @@ int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { wiegand_add_parity(pre+80, wiegand, 24); // add paritybits (bitsource, dest, sourcelen, paritylen, parityType (odd, even,) - addParity(pre+8, pyramidBits+8, 112, 8, 1); + size_t s = addParity(pre+8, pyramidBits+8, 102, 8, 1); + + //printf(" %d |", s); // add checksum uint8_t csBuff[13]; @@ -69,7 +71,6 @@ int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { uint32_t crc = CRC8Maxim(csBuff, 13); num_to_bytebits(crc, 8, pyramidBits+120); - return 1; } -- 2.39.5 From 50564be0f809e61f3148fb2f27db035b6362321f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 27 Feb 2016 19:47:10 +0100 Subject: [PATCH 09/16] ADD: Started to add a "LF GUARD CLONE/SIM" functionality. *not working* all thats needed now is fixing the transformation from FacilityCode/CardNumber -> raw data for t55x7. --- client/Makefile | 3 +- client/cmdlf.c | 26 +---- client/cmdlf.h | 25 +++++ client/cmdlfguard.c | 224 ++++++++++++++++++++++++++++++++++++++++++ client/cmdlfguard.h | 30 ++++++ client/cmdlfpyramid.c | 7 +- 6 files changed, 284 insertions(+), 31 deletions(-) create mode 100644 client/cmdlfguard.c create mode 100644 client/cmdlfguard.h diff --git a/client/Makefile b/client/Makefile index eabe0d38..3345aa8b 100644 --- a/client/Makefile +++ b/client/Makefile @@ -135,7 +135,8 @@ CMDSRCS = nonce2key/crapto1.c\ radixsort.c\ bucketsort.c\ cmdlfpresco.c\ - cmdlfpyramid.c + cmdlfpyramid.c\ + cmdlfguard.c ZLIBSRCS = deflate.c adler32.c trees.c zutil.c inflate.c inffast.c inftrees.c ZLIB_FLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED diff --git a/client/cmdlf.c b/client/cmdlf.c index 8469d80d..0f5d0dc0 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -7,32 +7,7 @@ //----------------------------------------------------------------------------- // Low frequency commands //----------------------------------------------------------------------------- - -#include -#include -#include -#include -#include "proxmark3.h" -#include "data.h" -#include "graph.h" -#include "ui.h" -#include "cmdparser.h" -#include "cmdmain.h" -#include "cmddata.h" -#include "util.h" #include "cmdlf.h" -#include "cmdlfhid.h" -#include "cmdlfawid.h" -#include "cmdlfti.h" -#include "cmdlfem4x.h" -#include "cmdlfhitag.h" -#include "cmdlft55xx.h" -#include "cmdlfpcf7931.h" -#include "cmdlfio.h" -#include "lfdemod.h" -#include "cmdlfviking.h" -#include "cmdlfpresco.h" -#include "cmdlfpyramid.h" static int CmdHelp(const char *Cmd); int usage_lf_cmdread(void) { @@ -1213,6 +1188,7 @@ static command_t CommandTable[] = {"help", CmdHelp, 1, "This help"}, {"awid", CmdLFAWID, 1, "{ AWID RFIDs... }"}, {"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"}, + {"guard", CmdLFGuard, 1, "{ Guardall RFIDs... }"}, {"hid", CmdLFHID, 1, "{ HID RFIDs... }"}, {"hitag", CmdLFHitag, 1, "{ HITAG RFIDs... }"}, {"io", CmdLFIO, 1, "{ IOPROX RFIDs... }"}, diff --git a/client/cmdlf.h b/client/cmdlf.h index 5dbb9b6e..21c79b42 100644 --- a/client/cmdlf.h +++ b/client/cmdlf.h @@ -10,6 +10,31 @@ #ifndef CMDLF_H__ #define CMDLF_H__ +#include +#include +#include +#include +#include "proxmark3.h" +#include "data.h" +#include "graph.h" +#include "ui.h" +#include "cmdparser.h" +#include "cmdmain.h" +#include "cmddata.h" +#include "util.h" +#include "cmdlfhid.h" +#include "cmdlfawid.h" +#include "cmdlfti.h" +#include "cmdlfem4x.h" +#include "cmdlfhitag.h" +#include "cmdlft55xx.h" +#include "cmdlfpcf7931.h" +#include "cmdlfio.h" +#include "lfdemod.h" +#include "cmdlfviking.h" +#include "cmdlfpresco.h" +#include "cmdlfpyramid.h" +#include "cmdlfguard.h" int CmdLF(const char *Cmd); diff --git a/client/cmdlfguard.c b/client/cmdlfguard.c new file mode 100644 index 00000000..b2079d83 --- /dev/null +++ b/client/cmdlfguard.c @@ -0,0 +1,224 @@ +//----------------------------------------------------------------------------- +// +// 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 Farpoint / Pyramid tag commands +//----------------------------------------------------------------------------- +#include +#include +#include "cmdlfguard.h" +static int CmdHelp(const char *Cmd); + +int usage_lf_guard_clone(void){ + PrintAndLog("clone a Guardall tag to a T55x7 tag."); + PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. "); + PrintAndLog("Currently work only on 26bit"); + PrintAndLog(""); + PrintAndLog("Usage: lf guard clone "); + PrintAndLog("Options :"); + PrintAndLog(" : 8-bit value facility code"); + PrintAndLog(" : 16-bit value card number"); + PrintAndLog(""); + PrintAndLog("Sample : lf guard clone 123 11223"); + return 0; +} + +int usage_lf_guard_sim(void) { + PrintAndLog("Enables simulation of Guardall card with specified card number."); + PrintAndLog("Simulation runs until the button is pressed or another USB command is issued."); + PrintAndLog("The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); + PrintAndLog("Currently work only on 26bit"); + PrintAndLog(""); + PrintAndLog("Usage: lf guard sim "); + PrintAndLog("Options :"); + PrintAndLog(" : 8-bit value facility code"); + PrintAndLog(" : 16-bit value card number"); + PrintAndLog(""); + PrintAndLog("Sample : lf guard sim 123 11223"); + return 0; +} + + +// Works for 26bits. +int GetGuardBits(uint32_t fc, uint32_t cn, uint8_t *guardBits) { + + // Intializes random number generator + time_t t; + srand((unsigned) time(&t)); + + uint8_t pre[96]; + memset(pre, 0x00, sizeof(pre)); + + uint8_t index = 8; + + // preamble 6bits + pre[0] = 1; + pre[1] = 1; + pre[2] = 1; + pre[3] = 1; + pre[4] = 1; + //pre[5] = 0; + + // add xor key + uint8_t xorKey = rand() % 0xFF; + num_to_bytebits(xorKey, 8, pre+index); + index += 8; + + // add format length + // len | hex | bin wiegand pos fc/cn + // 26 | 1A | 0001 1010 + num_to_bytebits(26, 8, pre+index); + // 36 | 24 | 0010 0100 + //num_to_bytebits(36, 8, pre+index); + // 40 | 28 | 0010 1000 + //num_to_bytebits(40, 8, pre+index); + + index += 8; + + // 2bit checksum + // unknown today. + index += 2; + + // Get 26 wiegand from FacilityCode, CardNumber + uint8_t wiegand[24]; + memset(wiegand, 0x00, sizeof(wiegand)); + num_to_bytebits(fc, 8, wiegand); + num_to_bytebits(cn, 16, wiegand+8); + + // add wiegand parity bits (dest, source, len) + wiegand_add_parity(pre+index, wiegand, 24); + + uint8_t tmp = 0, i = 0; + for (i = 2; i < 12; ++i) { + // // xor all bytes + // tmp = xorKey ^ bytebits_to_byte(pre + (i*8), 8); + + // // copy to out.. + // num_to_bytebits(tmp, 8, pre + (i*8) ); + } + + // add spacer bit 0 every 5 + + // swap nibbles + + + // copy to outarray + memcpy(guardBits, pre, sizeof(pre)); + + printf(" | %s\n", sprint_bin(guardBits, 96) ); + return 1; +} + +int CmdGuardRead(const char *Cmd) { + CmdLFRead("s"); + getSamples("30000",false); + return CmdG_Prox_II_Demod(""); +} + +int CmdGuardClone(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_guard_clone(); + + uint32_t facilitycode=0, cardnumber=0, fc = 0, cn = 0; + uint8_t i; + uint8_t bs[96]; + memset(bs, 0x00, sizeof(bs)); + + //GuardProxII - compat mode, ASK/Biphase, data rate 64, 3 data blocks + uint32_t blocks[5] = {T55x7_MODULATION_BIPHASE | T55x7_BITRATE_RF_64 | 3< clone Guardall tag"}, + {"sim", CmdGuardSim, 0, " simulate Guardall tag"}, + {NULL, NULL, 0, NULL} +}; + +int CmdLFGuard(const char *Cmd) { + clearCommandBuffer(); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdlfguard.h b/client/cmdlfguard.h new file mode 100644 index 00000000..68ab8f2b --- /dev/null +++ b/client/cmdlfguard.h @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// +// 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 T55xx commands +//----------------------------------------------------------------------------- +#ifndef CMDLFGUARD_H__ +#define CMDLFGUARD_H__ +#include "proxmark3.h" +#include "ui.h" +#include "util.h" +#include "graph.h" +#include "cmdparser.h" +#include "cmddata.h" +#include "cmdmain.h" +#include "cmdlf.h" +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest +#include "crc.h" + +int CmdLFGuard(const char *Cmd); +int CmdGuardClone(const char *Cmd); +int CmdGuardSim(const char *Cmd); + +int usage_lf_guard_clone(void); +int usage_lf_quard_sim(void); +#endif + diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 0f992cc2..990dccbb 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -40,7 +40,6 @@ int usage_lf_pyramid_sim(void) { return 0; } - // Works for 26bits. int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { @@ -60,10 +59,8 @@ int GetPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { wiegand_add_parity(pre+80, wiegand, 24); // add paritybits (bitsource, dest, sourcelen, paritylen, parityType (odd, even,) - size_t s = addParity(pre+8, pyramidBits+8, 102, 8, 1); - - //printf(" %d |", s); - + addParity(pre+8, pyramidBits+8, 102, 8, 1); + // add checksum uint8_t csBuff[13]; for (uint8_t i = 0; i < 13; i++) -- 2.39.5 From 2453ca6529057d9dc060a00c45058e0b7090e5b7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 27 Feb 2016 19:48:19 +0100 Subject: [PATCH 10/16] CHG: better not to show the unfinished commands.. --- client/cmdlfguard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmdlfguard.c b/client/cmdlfguard.c index b2079d83..7f58e994 100644 --- a/client/cmdlfguard.c +++ b/client/cmdlfguard.c @@ -207,8 +207,8 @@ int CmdGuardSim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"read", CmdGuardRead, 0, "Attempt to read and extract tag data"}, - {"clone", CmdGuardClone, 0, " clone Guardall tag"}, - {"sim", CmdGuardSim, 0, " simulate Guardall tag"}, +// {"clone", CmdGuardClone, 0, " clone Guardall tag"}, +// {"sim", CmdGuardSim, 0, " simulate Guardall tag"}, {NULL, NULL, 0, NULL} }; -- 2.39.5 From 733eb42022728f5b22028d4e8860e4efe6f18a5c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 28 Feb 2016 14:50:49 +0100 Subject: [PATCH 11/16] ADD: Added three legic luascript from @iscom (Mosic) Great work! --- client/scripts/Legic_clone.lua | 541 ++++++++++++++ client/scripts/legic.lua | 1039 ++++++++++++++++++++++++++ client/scripts/legic_buffer2card.lua | 54 ++ 3 files changed, 1634 insertions(+) create mode 100644 client/scripts/Legic_clone.lua create mode 100644 client/scripts/legic.lua create mode 100644 client/scripts/legic_buffer2card.lua diff --git a/client/scripts/Legic_clone.lua b/client/scripts/Legic_clone.lua new file mode 100644 index 00000000..2c8a84f4 --- /dev/null +++ b/client/scripts/Legic_clone.lua @@ -0,0 +1,541 @@ +--[[ + script to create a clone-dump with new crc + Author: mosci + my Fork: https://github.com/icsom/proxmark3.git + Upstream: https://github.com/Proxmark/proxmark3.git + + 1. read tag-dump, xor byte 22..end with byte 0x05 of the inputfile + 2. write to outfile + 3. set byte 0x05 to newcrc + 4. until byte 0x21 plain like in inputfile + 5. from 0x22..end xored with newcrc + 6. calculate new crc on each segment (needs to know the new MCD & MSN0..2) + + simplest usage: + read a valid legic tag with 'hf legic reader' + save the dump with 'hf legic save orig.hex' + place your 'empty' tag on the reader and run 'script run Legic_clone -i orig.hex -w' + you will see some output like: + read 1024 bytes from legic_dumps/j_0000.hex + + place your empty tag onto the PM3 to read and display the MCD & MSN0..2 + the values will be shown below + confirm whnen ready [y/n] ?y + #db# setting up legic card + #db# MIM 256 card found, reading card ... + #db# Card read, use 'hf legic decode' or + #db# 'data hexsamples 8' to view results + 0b ad c0 de <- !! here you'll see the MCD & MSN of your empty tag, which has to be typed in manually as seen below !! + type in MCD as 2-digit value - e.g.: 00 (default: 79 ) + > 0b + type in MSN0 as 2-digit value - e.g.: 01 (default: 28 ) + > ad + type in MSN1 as 2-digit value - e.g.: 02 (default: d1 ) + > c0 + type in MSN2 as 2-digit value - e.g.: 03 (default: 43 ) + > de + MCD:0b, MSN:ad c0 de, MCC:79 <- this crc is calculated from the MCD & MSN and must match the one on yout empty tag + + wrote 1024 bytes to myLegicClone.hex + enter number of bytes to write? (default: 86 ) + + loaded 1024 samples + #db# setting up legic card + #db# MIM 256 card found, writing 0x00 - 0x01 ... + #db# write successful + ... + #db# setting up legic card + #db# MIM 256 card found, writing 0x56 - 0x01 ... + #db# write successful + proxmark3> + + the default value (number of bytes to write) is calculated over all valid segments and should be ok - just hit enter, wait until write has finished + and your clone should be ready (except there has to be a additional KGH-CRC to be calculated - which credentials are unknown until yet) + + the '-w' switch will only work with my fork - it needs the binary legic_crc8 which is not part of the proxmark3-master-branch + also the ability to write DCF is not possible with the proxmark3-master-branch + but creating dumpfile-clone files will be possible (without valid segment-crc - this has to done manually with) + + + (example) Legic-Prime Layout with 'Kaba Group Header' + +----+----+----+----+----+----+----+----+ + 0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 9f | + +----+----+----+----+----+----+----+----+ + 0x08| ff | 00 | 00 | 00 | 11 |Bck0|Bck1|Bck2| + +----+----+----+----+----+----+----+----+ + 0x10|Bck3|Bck4|Bck5|BCC | 00 | 00 |Seg0|Seg1| + +----+----+----+----+----+----+----+----+ + 0x18|Seg2|Seg3|SegC|Stp0|Stp1|Stp2|Stp3|UID0| + +----+----+----+----+----+----+----+----+ + 0x20|UID1|UID2|kghC| + +----+----+----+ + + MCD= ManufacturerID (1 Byte) + MSN0..2= ManufactureSerialNumber (3 Byte) + MCC= CRC (1 Byte) calculated over MCD,MSN0..2 + DCF= DecrementalField (2 Byte) 'credential' (enduser-Tag) seems to have always DCF-low=0x60 DCF-high=0xea + Bck0..5= Backup (6 Byte) Bck0 'dirty-flag', Bck1..5 SegmentHeader-Backup + BCC= BackupCRC (1 Byte) CRC calculated over Bck1..5 + Seg0..3= SegmentHeader (on MIM 4 Byte ) + SegC= SegmentCRC (1 Byte) calculated over MCD,MSN0..2,Seg0..3 + Stp0..n= Stamp0... (variable length) length = Segment-Len - UserData - 1 + UID0..n= UserDater (variable length - with KGH hex 0x00-0x63 / dec 0-99) length = Segment-Len - WRP - WRC - 1 + kghC= KabaGroupHeader (1 Byte + addr 0x0c must be 0x11) + as seen on ths example: addr 0x05..0x08 & 0x0c must have been set to this values - otherwise kghCRC will not be created by a official reader (not accepted) +--]] + +example = "Script create a clone-dump of a dump from a Legic Prime Tag" +author = "Mosci" +desc = +[[ +This is a script which create a clone-dump of a dump from a Legic Prime Tag (MIM256 or MIM1024) +(created with 'hf legic save my_dump.hex') +requiered arguments: + -i (file to read data from) + +optional arguments : + -h - Help text + -o - requieres option -c to be given + -c - requieres option -o to be given + -d - Display content of found Segments + -s - Display summary at the end + -w - write directly to Tag - a file myLegicClone.hex wille be generated also + + e.g.: + hint: using the CRC '00' will result in a plain dump ( -c 00 ) + +Examples : + script run legic_clone -i my_dump.hex -o my_clone.hex -c f8 + script run legic_clone -i my_dump.hex -d -s +]] + +local utils = require('utils') +local getopt = require('getopt') +local bxor = bit32.bxor + +-- we need always 2 digits +function prepend_zero(s) + if (string.len(s)==1) then return "0" .. s + else + if (string.len(s)==0) then return "00" + else return s + end + end +end + +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) + return nil, err +end + +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end + +-- Check availability of file +function file_check(file_name) + local file_found=io.open(file_name, "r") + if file_found==nil then + file_found=false + else + file_found=true + end + return file_found +end + +--- xor-wrapper +-- xor all from addr 0x22 (start counting from 1 => 23) +function xorme(hex, xor, index) + if ( index >= 23 ) then + return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) )) + else + return hex + end +end + +-- read input-file into array +function getInputBytes(infile) + local line + local bytes = {} + + local fhi,err = io.open(infile) + if err then print("OOps ... faild to read from file ".. infile); return false; end + + while true do + line = fhi:read() + if line == nil then break end + + for byte in line:gmatch("%w+") do + table.insert(bytes, byte) + end + end + + fhi:close() + + print("\nread ".. #bytes .." bytes from ".. infile) + return bytes +end + +-- write to file +function writeOutputBytes(bytes, outfile) + local line + local bcnt=0 + local fho,err = io.open(outfile,"w") + if err then print("OOps ... faild to open output-file ".. outfile); return false; end + + for i = 1, #bytes do + if (bcnt == 0) then + line=bytes[i] + elseif (bcnt <= 7) then + line=line.." "..bytes[i] + end + if (bcnt == 7) then + -- write line to new file + fho:write(line.."\n") + -- reset counter & line + bcnt=-1 + line="" + end + bcnt=bcnt+1 + end + fho:close() + print("\nwrote ".. #bytes .." bytes to " .. outfile) + return true +end + +-- xore certain bytes +function xorBytes(inBytes, crc) + local bytes = {} + for index = 1, #inBytes do + bytes[index] = xorme(inBytes[index], crc, index) + end + if (#inBytes == #bytes) then + -- replace crc + bytes[5] = string.sub(crc,-2) + return bytes + else + print("error: byte-count missmatch") + return false + end +end + +-- get raw segment-data +function getSegmentData(bytes, start, index) + local raw, len, valid, last, wrp, wrc, rd, crc + local segment = {} + segment[0] = bytes[start].." "..bytes[start+1].." "..bytes[start+2].." "..bytes[start+3] + -- flag = high nibble of byte 1 + segment[1] = string.sub(bytes[start+1],0,1) + + -- valid = bit 6 of byte 1 + segment[2] = tonumber(bit32.extract("0x"..bytes[start+1],6,1),16) + + -- last = bit 7 of byte 1 + segment[3] = tonumber(bit32.extract("0x"..bytes[start+1],7,1),16) + + -- len = (byte 0)+(bit0-3 of byte 1) + segment[4] = tonumber(("%03x"):format(tonumber(bit32.extract("0x"..bytes[start+1],0,3),16)..tonumber(bytes[start],16)),16) + + -- wrp (write proteted) = byte 2 + segment[5] = tonumber(bytes[start+2]) + + -- wrc (write control) - bit 4-6 of byte 3 + segment[6] = tonumber(bit32.extract("0x"..bytes[start+3],4,3),16) + + -- rd (read disabled) - bit 7 of byte 3 + segment[7] = tonumber(bit32.extract("0x"..bytes[start+3],7,1),16) + + -- crc byte 4 + segment[8] = bytes[start+4] + + -- segment index + segment[9] = index + + -- # crc-byte + segment[10] = start+4 + return segment +end + +--- Kaba Group Header +-- checks if a segment does have a kghCRC +-- returns boolean false if no kgh has being detected or the kghCRC if a kgh was detected +function CheckKgh(bytes, segStart, segEnd) + if (bytes[8]=='9f' and bytes[9]=='ff' and bytes[13]=='11') then + local i + local data = {} + segStart=tonumber(segStart,10) + segEnd=tonumber(segEnd,10) + local dataLen = segEnd-segStart-5 + --- gather creadentials for verify + local WRP = bytes[(segStart+2)] + local WRC = ("%02x"):format(tonumber(bit32.extract("0x"..bytes[segStart+3],4,3),16)) + local RD = ("%02x"):format(tonumber(bit32.extract("0x"..bytes[segStart+3],7,1),16)) + local XX = "00" + cmd = bytes[1]..bytes[2]..bytes[3]..bytes[4]..WRP..WRC..RD..XX + for i=(segStart+5), (segStart+5+dataLen-2) do + cmd = cmd..bytes[i] + end + local KGH=("%02x"):format(utils.Crc8Legic(cmd)) + if (KGH==bytes[segEnd-1]) then + return KGH + else + return false + end + else + return false + end +end + +-- get only the addresses of segemnt-crc's and the length of bytes +function getSegmentCrcBytes(bytes) + local start=23 + local index=0 + local crcbytes = {} + repeat + seg = getSegmentData(bytes,start,index) + crcbytes[index]= seg[10] + start = start + seg[4] + index = index + 1 + until (seg[3] == 1 or tonumber(seg[9]) == 126 ) + crcbytes[index] = start + return crcbytes +end + +-- print segment-data (hf legic decode like) +function displaySegments(bytes) + --display segment header(s) + start=23 + index="00" + + --repeat until last-flag ist set to 1 or segment-index has reached 126 + repeat + wrc="" + wrp="" + pld="" + Seg = getSegmentData(bytes,start,index) + KGH = CheckKgh(bytes,start,(start+tonumber(Seg[4],10))) + printSegment(Seg) + + -- wrc + if(Seg[6]>0) then + print("WRC protected area:") + -- length of wrc = wrc + for i=1, Seg[6] do + -- starts at (segment-start + segment-header + segment-crc)-1 + wrc = wrc..bytes[(start+4+1+i)-1].." " + end + print(wrc) + elseif(Seg[5]>0) then + print("Remaining write protected area:") + -- length of wrp = (wrp-wrc) + for i=1, (Seg[5]-Seg[6]) do + -- starts at (segment-start + segment-header + segment-crc + wrc)-1 + wrp = wrp..bytes[(start+4+1+Seg[6]+i)-1].." " + end + print(wrp) + end + + -- payload + print("Remaining segment payload:") + --length of payload = segment-len - segment-header - segment-crc - wrp -wrc + for i=1, (Seg[4]-4-1-Seg[5]-Seg[6]) do + -- starts at (segment-start + segment-header + segment-crc + segment-wrp + segemnt-wrc)-1 + pld = pld..bytes[(start+4+1+Seg[5]+Seg[6]+i)-1].." " + end + print(pld) + if (KGH) then print("'Kaba Group Header' detected"); end + start = start+Seg[4] + index = prepend_zero(tonumber(Seg[9])+1) + + until (Seg[3] == 1 or tonumber(Seg[9]) == 126 ) +end + +-- print Segment values +function printSegment(SegmentData) + res = "\nSegment "..SegmentData[9]..": " + res = res.. "raw header="..SegmentData[0]..", " + res = res.. "flag="..SegmentData[1].." (valid="..SegmentData[2].." last="..SegmentData[3].."), " + res = res.. "len="..("%04d"):format(SegmentData[4])..", " + res = res.. "WRP="..prepend_zero(SegmentData[5])..", " + res = res.. "WRC="..prepend_zero(SegmentData[6])..", " + res = res.. "RD="..SegmentData[7]..", " + res = res.. "crc="..SegmentData[8] + print(res) +end + +-- write clone-data to tag +function writeToTag(plainBytes) + local SegCrcs = {} + if(utils.confirm("\nplace your empty tag onto the PM3 to read and display the MCD & MSN0..2\nthe values will be shown below\n confirm when ready") == false) then + return + end + + -- gather MCD & MSN from new Tag - this must be enterd manually + cmd = 'hf legic read 0x00 0x04' + core.console(cmd) + print("\nthese are the MCD MSN0 MSN1 MSN2 from the Tag that has being read:") + cmd = 'data hexsamples 4' + core.console(cmd) + print("^^ use this values as input for the following answers (one 2-digit-value per question/answer):") + -- enter MCD & MSN (in hex) + MCD = utils.input("type in MCD as 2-digit value - e.g.: 00", plainBytes[1]) + MSN0 = utils.input("type in MSN0 as 2-digit value - e.g.: 01", plainBytes[2]) + MSN1 = utils.input("type in MSN1 as 2-digit value - e.g.: 02", plainBytes[3]) + MSN2 = utils.input("type in MSN2 as 2-digit value - e.g.: 03", plainBytes[4]) + + -- calculate crc8 over MCD & MSN + cmd = MCD..MSN0..MSN1..MSN2 + MCC = ("%02x"):format(utils.Crc8Legic(cmd)) + print("MCD:"..MCD..", MSN:"..MSN0.." "..MSN1.." "..MSN2..", MCC:"..MCC) + + -- calculate new Segment-CRC for each valid segment + SegCrcs = getSegmentCrcBytes(plainBytes) + for i=0, (#SegCrcs-1) do + -- SegCrcs[i]-4 = address of first byte of segmentHeader (low byte segment-length) + segLen=tonumber(("%1x"):format(tonumber(bit32.extract("0x"..plainBytes[(SegCrcs[i]-3)],0,3),16))..("%02x"):format(tonumber(plainBytes[SegCrcs[i]-4],16)),16) + segStart=(SegCrcs[i]-4) + segEnd=(SegCrcs[i]-4+segLen) + KGH=CheckKgh(plainBytes,segStart,segEnd) + if (KGH) then + print("'Kaba Group Header' detected - re-calculate...") + end + cmd = MCD..MSN0..MSN1..MSN2..plainBytes[SegCrcs[i]-4]..plainBytes[SegCrcs[i]-3]..plainBytes[SegCrcs[i]-2]..plainBytes[SegCrcs[i]-1] + plainBytes[SegCrcs[i]] = ("%02x"):format(utils.Crc8Legic(cmd)) + end + + -- apply MCD & MSN to plain data + plainBytes[1] = MCD + plainBytes[2] = MSN0 + plainBytes[3] = MSN1 + plainBytes[4] = MSN2 + plainBytes[5] = MCC + + -- prepare plainBytes for writing (xor plain data with new MCC) + bytes = xorBytes(plainBytes, MCC) + + -- write data to file + if (writeOutputBytes(bytes, "myLegicClone.hex")) then + WriteBytes = utils.input("enter number of bytes to write?", SegCrcs[#SegCrcs]) + + -- load file into pm3-buffer + cmd = 'hf legic load myLegicClone.hex' + core.console(cmd) + + -- write pm3-buffer to Tag + for i=0, WriteBytes do + if ( i<5 or i>6) then + cmd = ('hf legic write 0x%02x 0x01'):format(i) + core.console(cmd) + elseif (i == 6) then + -- write DCF in reverse order (requires 'mosci-patch') + cmd = 'hf legic write 0x05 0x02' + core.console(cmd) + else + print("skipping byte 0x05 - will be written next step") + end + utils.Sleep(0.2) + end + end +end + +-- main function +function main(args) + -- some variables + local i=0 + local oldcrc, newcrc, infile, outfile + local bytes = {} + local segments = {} + + -- parse arguments for the script + for o, a in getopt.getopt(args, 'hwsdc:i::o:') do + -- output file + if o == "o" then + outfile = a + ofs = true + if (file_check(a)) then + local answer = utils.confirm("\nthe output-file "..a.." alredy exists!\nthis will delete the previous content!\ncontinue?") + if (answer==false) then return oops("quiting") end + end + end + -- input file + if o == "i" then + infile = a + if (file_check(infile)==false) then + return oops("input file: "..infile.." not found") + else + bytes = getInputBytes(infile) + oldcrc = bytes[5] + ifs = true + if (bytes == false) then return oops('couldnt get input bytes') end + end + i = i+1 + end + -- new crc + if o == "c" then + newcrc = a + ncs = true + end + -- display segments switch + if o == "d" then ds = true; end + -- display summary switch + if o == "s" then ss = true; end + -- write to tag switch + if o == "w" then ws = true; end + -- help + if o == "h" then return help() end + end + + if (not ifs) then return oops("option -i is required but missing") end + + -- bytes to plain + bytes = xorBytes(bytes, oldcrc) + + -- show segments (works only on plain bytes) + if (ds) then + print("+------------------------------------------- Segments -------------------------------------------+") + displaySegments(bytes); + end + + if (ofs and ncs) then + -- xor bytes with new crc + newBytes = xorBytes(bytes, newcrc) + -- write output + if (writeOutputBytes(newBytes, outfile)) then + -- show summary if requested + if (ss) then + -- information + res = "\n+-------------------------------------------- Summary -------------------------------------------+" + res = res .."\ncreated clone_dump from\n\t"..infile.." crc: "..oldcrc.."\ndump_file:" + res = res .."\n\t"..outfile.." crc: "..string.sub(newcrc,-2) + res = res .."\nyou may load the new file with: hf legic load "..outfile + res = res .."\n\nif you don't write to tag immediately ('-w' switch) you will need to recalculate each segmentCRC" + res = res .."\nafter writing this dump to a tag!" + res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3,Segment-Header0..3" + res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):" + res = res .."\nhf legic crc8 "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26] + -- this can not be calculated without knowing the new MCD, MSN0..2 + print(res) + end + end + else + if (ss) then + -- show why the output-file was not written + print("\nnew file not written - some arguments are missing ..") + print("output file: ".. (ofs and outfile or "not given")) + print("new crc: ".. (ncs and newcrc or "not given")) + end + end + -- write to tag + if (ws and #bytes == 1024) then + writeToTag(bytes) + end +end + +-- call main with arguments +main(args) \ No newline at end of file diff --git a/client/scripts/legic.lua b/client/scripts/legic.lua new file mode 100644 index 00000000..dd119b03 --- /dev/null +++ b/client/scripts/legic.lua @@ -0,0 +1,1039 @@ +--[[ +(example) Legic-Prime Layout with 'Kaba Group Header' + +----+----+----+----+----+----+----+----+ + 0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 9f | + +----+----+----+----+----+----+----+----+ + 0x08| ff | 00 | 00 | 00 | 11 |Bck0|Bck1|Bck2| + +----+----+----+----+----+----+----+----+ + 0x10|Bck3|Bck4|Bck5|BCC | 00 | 00 |Seg0|Seg1| + +----+----+----+----+----+----+----+----+ + 0x18|Seg2|Seg3|SegC|Stp0|Stp1|Stp2|Stp3|UID0| + +----+----+----+----+----+----+----+----+ + 0x20|UID1|UID2|kghC| + +----+----+----+ +--]] + +example = "script run legic" +author = "Mosci" +desc = +[[ + +This script helps you to read, create and modify Legic Prime Tags (MIM22, MIM256, MIM1024) +it's kinda interactive with following commands in three categories: + + Data I/O Segment Manipulation File I/O +------------------ -------------------- --------------- + rt => read Tag ds => dump Segments lf => load File + wt => write Tag as => add Segment sf => save File + ct => copy io Tag es => edit Segment xf => xor File + tc => copy oi Tag ed => edit Data + di => dump inTag rs => remove Segment + do => dump outTag cc => check Segment-CRC + ck => check KGH + tk => toggle KGH-Flag + q => quit xc => get KGH-Str h => this Help + + Data I/O + rt: 'read tag' - reads a tag placed near to the PM3 + wt: 'write tag' - writes the content of the 'virtual inTag' to a tag placed near to th PM3 + without the need of changing anything - MCD,MSN,MCC will be read from the tag + before and applied to the output. + ct: 'copy tag' - copy the 'virtual Tag' to a second 'virtual TAG' - not usefull yet, but inernally needed + tc: 'copy tag' - copy the 'second virtual Tag' to 'virtual TAG' - not usefull yet, but inernally needed + di: 'dump inTag' - shows the current content of the 'virtual Tag' + do: 'dump outTag' - shows the current content of the 'virtual outTag' + + Segment Manipulation + (all manipulations happens only in the 'virtual inTAG' - they need to be written with 'wt' to take effect) + ds: 'dump Segments' - will show the content of a selected Segment + as: 'add Segment' - will add a 'empty' Segment to the inTag + es: 'edit Segment' - edit the Segment-Header of a selected Segment (len, WRP, WRC, RD, valid) + all other Segment-Header-Values are either calculated or not needed to edit (yet) + ed: 'edit data' - edit the Data of a Segment (Stamp & Payload) + rs: 'remove segment' - removes a Segment (except Segment 00, but this can be set to valid=0 for Master-Token) + cc: 'check Segment-CRC'- checks & calculates (if check failed) the Segment-CRC of all Segments + ck: 'check KGH-CRC' - checks the and calculates a 'Kaba Group Header' if one was detected + 'Kaba Group Header CRC calculation' + tk: 'toggle KGH' - toglle the (script-internal) flag for kgh-calculation for a segment + xc: 'etra c' - show string that was used to calculate the kgh-crc of a segment + + Input/Output + lf: 'load file' - load a (xored) file from the local Filesystem into the 'virtual inTag' + sf: 'save file' - saves the 'virtual inTag' to the local Filesystem (xored with Tag-MCC) + xf: 'xor file' - saves the 'virtual inTag' to the local Filesystem (xored with choosen MCC - use '00' for plain values) + +]] + +--- requirements +local utils = require('utils') +local getopt = require('getopt') + +--- global variables / defines +local bxor = bit32.bxor +local bbit = bit32.extract +local input = utils.input +local confirm = utils.confirm + +--- Error-Handling & Helper +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) + return nil, err +end + +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end + +--- +-- table check helper +function istable(t) + return type(t) == 'table' +end + +--- +-- put certain bytes into a new table +function bytesToTable(bytes, bstart, bend) + local t={} + for i=0, (bend-bstart) do + t[i]=bytes[bstart+i] + end + return t +end + +--- +-- xor byte (if addr >= 0x22 - start counting from 1 => 23) +function xorme(hex, xor, index) + if ( index >= 23 ) then + return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) )) + else + return hex + end +end + +--- +-- (de)obfuscate bytes +function xorBytes(inBytes, crc) + local bytes = {} + for index = 1, #inBytes do + bytes[index] = xorme(inBytes[index], crc, index) + end + if (#inBytes == #bytes) then + -- replace crc + bytes[5] = string.sub(crc,-2) + return bytes + else + print("error: byte-count missmatch") + return false + end +end + +--- +-- check availability of file +function file_check(file_name) + local file_found=io.open(file_name, "r") + if file_found==nil then + return false + else + return true + end +end + +--- +-- read file into virtual-tag +function readFile(filename) + local bytes = {} + local tag = {} + if (file_check(filename)==false) then + return oops("input file: "..filename.." not found") + else + bytes = getInputBytes(filename) + if (bytes == false) then return oops('couldnt get input bytes') + else + -- make plain bytes + bytes = xorBytes(bytes,bytes[5]) + -- create Tag for plain bytes + tag=createTagTable() + -- load plain bytes to tag-table + tag=bytesToTag(bytes, tag) + end + end + return tag +end + +--- +-- write bytes to file +-- write to file +function writeFile(bytes, filename) + if (filename~='MylegicClone.hex') then + if (file_check(filename)) then + local answer = confirm("\nthe output-file "..filename.." alredy exists!\nthis will delete the previous content!\ncontinue?") + if (answer==false) then return print("user abort") end + end + end + local line + local bcnt=0 + local fho,err = io.open(filename, "w") + if err then oops("OOps ... faild to open output-file ".. filename) end + bytes=xorBytes(bytes, bytes[5]) + for i = 1, #bytes do + if (bcnt == 0) then + line=bytes[i] + elseif (bcnt <= 7) then + line=line.." "..bytes[i] + end + if (bcnt == 7) then + -- write line to new file + fho:write(line.."\n") + -- reset counter & line + bcnt=-1 + line="" + end + bcnt=bcnt+1 + end + fho:close() + print("\nwrote ".. #bytes .." bytes to " .. filename) + return true +end + +--- +-- read from pm3 into virtual-tag +function readFromPM3() + local tag, bytes, infile + --if (confirm("is the Tag placed onto the Proxmak3 and ready for reading?")) then + --print("reading Tag ...") + --infile=input("input a name for the temp-file:", "legic.temp") + --if (file_check(infile)) then + -- local answer = confirm("\nthe output-file "..infile.." alredy exists!\nthis will delete the previous content!\ncontinue?") + -- if (answer==false) then return print("user abort") end + --end + infile="legic.temp" + core.console("hf legic reader") + core.console("hf legic save "..infile) + --print("read temp-file into virtual Tag ...") + tag=readFile(infile) + return tag + --else return print("user abort"); end +end + +--- +-- read file into table +function getInputBytes(infile) + local line + local bytes = {} + local fhi,err = io.open(infile) + if err then oops("faild to read from file ".. infile); return false; end + while true do + line = fhi:read() + if line == nil then break end + for byte in line:gmatch("%w+") do + table.insert(bytes, byte) + end + end + fhi:close() + print(#bytes .. " bytes from "..infile.." loaded") + return bytes +end + +--- +-- read Tag-Table in bytes-table +function tagToBytes(tag) + if (istable(tag)) then + local bytes = {} + local i, i2 + -- main token-data + table.insert(bytes, tag.MCD) + table.insert(bytes, tag.MSN0) + table.insert(bytes, tag.MSN1) + table.insert(bytes, tag.MSN2) + table.insert(bytes, tag.MCC) + table.insert(bytes, tag.DCFl) + table.insert(bytes, tag.DCFh) + table.insert(bytes, tag.raw) + table.insert(bytes, tag.SSC) + -- raw token data + for i=0, #tag.data do + table.insert(bytes, tag.data[i]) + end + -- backup data + for i=0, #tag.Bck do + table.insert(bytes, tag.Bck[i]) + end + -- token-create-time / master-token crc + for i=0, #tag.MTC do + table.insert(bytes, tag.MTC[i]) + end + -- process segments + if (type(tag.SEG[0])=='table') then + for i=0, #tag.SEG do + for i2=1, #tag.SEG[i].raw+1 do + table.insert(bytes, #bytes+1, tag.SEG[i].raw[i2]) + end + table.insert(bytes, #bytes+1, tag.SEG[i].crc) + for i2=0, #tag.SEG[i].data-1 do + table.insert(bytes, #bytes+1, tag.SEG[i].data[i2]) + end + end + end + -- fill with zeros + for i=#bytes+1, 1024 do + table.insert(bytes, i, '00') + end + print(#bytes.." bytes of Tag dumped") + return bytes + end + return oops("tag is no table in tagToBytes ("..type(tag)..")") +end + +--- virtual TAG functions +-- create tag-table helper +function createTagTable() + local t={ + ['MCD'] = '00', + ['MSN0']= '11', + ['MSN1']= '22', + ['MSN2']= '33', + ['MCC'] = 'cc', + ['DCFl']= 'ff', + ['DCFh']= 'ff', + ['Type']= 'GAM', + ['OLE'] = 0, + ['Stamp_len']= 18, + ['WRP'] = '00', + ['WRC'] = '00', + ['RD'] = '00', + ['raw'] = '9f', + ['SSC'] = 'ff', + ['data']= {}, + ['bck'] = {}, + ['MTC'] = {}, + ['SEG'] = {} + } + return t +end + +--- +-- put bytes into tag-table +function bytesToTag(bytes, tag) + if(istable(tag)) then + tag.MCD =bytes[1]; + tag.MSN0=bytes[2]; + tag.MSN1=bytes[3]; + tag.MSN2=bytes[4]; + tag.MCC =bytes[5]; + tag.DCFl=bytes[6]; + tag.DCFh=bytes[7]; + tag.raw =bytes[8]; + tag.SSC =bytes[9]; + tag.Type=getTokenType(tag.DCFl); + tag.OLE=bbit("0x"..tag.DCFl,7,1) + tag.WRP=("%d"):format(bbit("0x"..bytes[8],0,4)) + tag.WRC=("%d"):format(bbit("0x"..bytes[8],4,3)) + tag.RD=("%d"):format(bbit("0x"..bytes[8],7,1)) + tag.Stamp_len=(tonumber(0xfc,10)-tonumber(bbit("0x"..tag.DCFh,0,8),10)) + tag.data=bytesToTable(bytes, 10, 13) + tag.Bck=bytesToTable(bytes, 14, 20) + tag.MTC=bytesToTable(bytes, 21, 22) + + print("Tag-Type: ".. tag.Type) + if (tag.Type=="SAM" and #bytes>23) then + tag=segmentsToTag(bytes, tag) + print((#tag.SEG+1).." Segment(s) found") + end + print(#bytes.." bytes for Tag processed") + return tag + end + return oops("tag is no table in: bytesToTag ("..type(tag)..")") +end + +--- +-- dump tag-system area +function dumpCDF(tag) + local res="" + local i=0 + local raw="" + if (istable(tag)) then + res = res.."MCD: "..tag.MCD..", MSN: "..tag.MSN0.." "..tag.MSN1.." "..tag.MSN2..", MCC: "..tag.MCC.."\n" + res = res.."DCF: "..tag.DCFl.." "..tag.DCFh..", Token_Type="..tag.Type.." (OLE="..tag.OLE.."), Stamp_len="..tag.Stamp_len.."\n" + res = res.."WRP="..tag.WRP..", WRC="..tag.WRC..", RD="..tag.RD..", raw="..tag.raw..", SSC="..tag.SSC.."\n" + + -- credential + if (tag.raw..tag.SSC=="9fff") then + res = res.."Remaining Header Area\n" + for i=0, (#tag.data) do + res = res..tag.data[i].." " + end + res = res.."\nBackup Area\n" + for i=0, (#tag.Bck) do + res = res..tag.Bck[i].." " + end + res = res.."\nTime Area\n" + for i=0, (#tag.MTC) do + res = res..tag.MTC[i].." " + end + + -- Master Token + else + res = res .."Master-Token Area\n" + for i=0, (#tag.data) do + res = res..tag.data[i].." " + end + for i=0, (#tag.Bck) do + res = res..tag.Bck[i].." " + end + for i=0, (#tag.MTC-1) do + res = res..tag.MTC[i].." " + end + res = res .. " MT-CRC: "..tag.MTC[1] + end + return res + else print("no valid Tag in dumpCDF") end +end + +--- +-- dump single segment +function dumpSegment(tag, index) + local i=index + local i2 + local dp=0 --data-position in table + local res="" --result + local raw="" --raw-header + -- segment + if ( (istable(tag.SEG[i])) and tag.Type=="SAM") then + if (istable(tag.SEG[i].raw)) then + for k,v in pairs(tag.SEG[i].raw) do + raw=raw..v.." " + end + end + + -- segment header + res = res.."Segment "..("%02d"):format(tag.SEG[i].index)..": " + res = res .."raw header:"..string.sub(raw,0,-2)..", flag="..tag.SEG[i].flag..", (valid="..("%x"):format(tag.SEG[i].valid)..", last="..("%x"):format(tag.SEG[i].last).."), " + res = res .."len="..("%04d"):format(tag.SEG[i].len)..", WRP="..("%02x"):format(tag.SEG[i].WRP)..", WRC="..("%02x"):format(tag.SEG[i].WRC)..", " + res = res .."RD="..("%02x"):format(tag.SEG[i].RD)..", CRC="..tag.SEG[i].crc.." " + res = res .."("..(checkSegmentCrc(tag, i) and "valid" or "error")..")" + raw="" + + -- WRC protected + if (tag.SEG[i].WRC>0) then + res = res .."\nWRC protected area (Stamp):\n" + for i2=dp, tag.SEG[i].WRC-1 do + res = res..tag.SEG[i].data[dp].." " + dp=dp+1 + end + end + + -- WRP mprotected + if (tag.SEG[i].WRP>tag.SEG[i].WRC) then + res = res .."\nRemaining write protected area (Stamp):\n" + for i2=dp, tag.SEG[i].WRP-tag.SEG[i].WRC-1 do + res = res..tag.SEG[i].data[dp].." " + dp=dp+1 + end + end + + -- payload + if (#tag.SEG[i].data-dp>0) then + res = res .."\nRemaining segment payload:\n" + for i2=dp, #tag.SEG[i].data-2 do + res = res..tag.SEG[i].data[dp].." " + dp=dp+1 + end + if (tag.SEG[i].kgh) then + res = res..tag.SEG[i].data[dp].." (KGH: "..(checkKghCrc(tag, i) and "valid" or "error")..")" + else res = res..tag.SEG[i].data[dp] end + end + dp=0 + return res + else + return print("Segment not found") + end +end + +--- +-- check all segmnet-crc +function checkAllSegCrc(tag) + for i=0, #tag.SEG do + crc=calcSegmentCrc(tag, i) + tag.SEG[i].crc=crc + end +end + +--- +-- check all segmnet-crc +function checkAllKghCrc(tag) + for i=0, #tag.SEG do + crc=calcKghCrc(tag, i) + if (tag.SEG[i].kgh) then + tag.SEG[i].data[#tag.SEG[i].data-1]=crc + end + end +end + +--- +-- dump virtual Tag-Data +function dumpTag(tag) + local i, i2 + local res + local dp=0 + local raw="" + -- sytstem area + res ="\nCDF: System Area" + res= res.."\n"..dumpCDF(tag) + -- segments (user area) + if(istable(tag.SEG[0])) then + res = res.."\n\nADF: User Area" + for i=0, #tag.SEG do + res=res.."\n"..dumpSegment(tag, i).."\n" + end + end + return res +end + +--- +-- determine TagType (bits 0..6 of DCFlow) +function getTokenType(DCFl) + --[[ + 0x00–0x2f IAM + 0x30–0x6f SAM + 0x70–0x7f GAM + ]]-- + local tt = tonumber(bbit("0x"..DCFl,0,7),10) + if (tt >= 0 and tt <= 47) then tt = "IAM" + elseif (tt == 49) then tt = "SAM63" + elseif (tt == 48) then tt = "SAM64" + elseif (tt >= 50 and tt <= 111) then tt = "SAM" + elseif (tt >= 112 and tt <= 127) then tt = "GAM" + else tt = "???" end + return tt +end + +--- +-- regenerate segment-header (after edit) +function regenSegmentHeader(segment) + local seg=segment + local raw = segment.raw + local i + -- len bit0..7 | len=12bit=low nibble of byte1..byte0 + raw[1]=("%02x"):format(bbit("0x"..("%03x"):format(seg.len),0,8)) + -- high nibble of len bit6=valid , bit7=last of byte 1 | ?what are bit 5+6 for? maybe kgh? + raw[2]=("%02x"):format(bbit("0x"..("%03x"):format(seg.len),4.4)..bbit("0x"..("%02x"):format((seg.valid*64)+(seg.last*128)),0,8)) + -- WRP + raw[3]=("%02x"):format(bbit("0x"..("%02x"):format(seg.WRP),0,8)) + -- WRC + RD + raw[4]=("%02x"):format(bbit("0x"..("%03x"):format(seg.WRC),4,3)..bbit("0x"..("%02x"):format(seg.RD*128),0,8)) + -- flag + seg.flag=string.sub(raw[2],0,1) + --print(raw[1].." "..raw[2].." "..raw[3].." "..raw[4]) + if(#seg.data>(seg.len-5)) then + print("current payload: ".. #seg.data .." - desired payload: ".. seg.len-5) + print("Data-Length has being reduced: removing ".. #seg.data-(seg.len-5) .." bytes from Payload"); + for i=(seg.len-5), #seg.data-1 do + table.remove(seg.data) + end + elseif (#seg.data<(seg.len-5)) then + print("current payload: ".. #seg.data .." - desired payload: ".. seg.len-5) + print("Data-Length has being extended: adding "..(seg.len-5)-#seg.data.." bytes to Payload"); + for i=#seg.data, (seg.len-5)-1 do + table.insert(seg.data, '00') + end + end + return seg +end + +--- +-- get segmemnt-data from byte-table +function getSegmentData(bytes, start, index) + local segment={ + ['index'] = '00', + ['flag'] = 'c', + ['valid'] = 0, + ['last'] = 0, + ['len'] = 13, + ['raw'] = {'00', '00', '00', '00'}, + ['WRP'] = 4, + ['WRC'] = 0, + ['RD'] = 0, + ['crc'] = '00', + ['data'] = {}, + ['kgh'] = false + } + if (bytes[start]) then + local i + -- #index + segment.index = index + -- flag = high nibble of byte 1 + segment.flag = string.sub(bytes[start+1],0,1) + -- valid = bit 6 of byte 1 + segment.valid = bbit("0x"..bytes[start+1],6,1) + -- last = bit 7 of byte 1 + segment.last = bbit("0x"..bytes[start+1],7,1) + -- len = (byte 0)+(bit0-3 of byte 1) + segment.len = tonumber(bbit("0x"..bytes[start+1],0,4)..bytes[start],16) + -- raw segment header + segment.raw = {bytes[start], bytes[start+1], bytes[start+2], bytes[start+3]} + -- wrp (write proteted) = byte 2 + segment.WRP = tonumber(bytes[start+2],16) + -- wrc (write control) - bit 4-6 of byte 3 + segment.WRC = tonumber(bbit("0x"..bytes[start+3],4,3),16) + -- rd (read disabled) - bit 7 of byte 3 + segment.RD = tonumber(bbit("0x"..bytes[start+3],7,1),16) + -- crc byte 4 + segment.crc = bytes[start+4] + -- segment-data starts at segment.len - segment.header - segment.crc + for i=0, (segment.len-5) do + segment.data[i]=bytes[start+5+i] + end + return segment + else return false; + end +end + +--- +-- put segments from byte-table to tag-table +function segmentsToTag(bytes, tag) + if(#bytes>23) then + local start=23 + local i=-1 + if (istable(tag)) then + repeat + i=i+1 + tag.SEG[i]=getSegmentData(bytes, start, ("%02d"):format(i)) + if (tag.Type=="SAM") then + if (checkKghCrc(tag, i)) then tag.SEG[i].kgh=true end + end + start=start+tag.SEG[i].len + until ((tag.SEG[i].valid==0) or tag.SEG[i].last==1 or i==126) + return tag + else return oops("tag is no table in: segmentsToTag ("..type(tag)..")") end + else print("no Segments: must be a MIM22") end +end + +--- CRC calculation and validation +-- build kghCrc credentials +function kghCrcCredentials(tag, segid) + local x='00' + if (type(segid)=="string") then segid=tonumber(segid,10) end + if (segid>0) then x='93' end + local cred = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2..("%02x"):format(tag.SEG[segid].WRP) + cred = cred..("%02x"):format(tag.SEG[segid].WRC)..("%02x"):format(tag.SEG[segid].RD)..x + for i=0, #tag.SEG[segid].data-2 do + cred = cred..tag.SEG[segid].data[i] + end + return cred +end + +--- +-- validate kghCRC to segment in tag-table +function checkKghCrc(tag, segid) + if (type(tag.SEG[segid])=='table') then + if (tag.data[3]=="11" and tag.raw=="9f" and tag.SSC=="ff") then + local data=kghCrcCredentials(tag, segid) + if (("%02x"):format(utils.Crc8Legic(data))==tag.SEG[segid].data[tag.SEG[segid].len-5-1]) then return true; end + else return false; end + else oops("'Kaba Group header' detected but no Segment-Data found") end +end + +--- +-- calcuate kghCRC for a given segment +function calcKghCrc(tag, segid) + -- check if a 'Kaber Group Header' exists + local i + local data=kghCrcCredentials(tag, segid) + return ("%02x"):format(utils.Crc8Legic(data)) +end + +--- +-- build segmentCrc credentials +function segmentCrcCredentials(tag, segid) + local cred = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 + cred = cred ..tag.SEG[segid].raw[1]..tag.SEG[segid].raw[2]..tag.SEG[segid].raw[3]..tag.SEG[segid].raw[4] + return cred +end + +--- +-- validate segmentCRC for a given segment +function checkSegmentCrc(tag, segid) + local data=segmentCrcCredentials(tag, segid) + if (("%02x"):format(utils.Crc8Legic(data))==tag.SEG[segid].crc) then + return true + end + return false +end + +--- +-- calculate segmentCRC for a given segment +function calcSegmentCrc(tag, segid) + -- check if a 'Kaber Group Header' exists + local data=segmentCrcCredentials(tag, segid) + return ("%02x"):format(utils.Crc8Legic(data)) +end + +--- create master-token + +--- +-- write virtual Tag to real Tag +-- write clone-data to tag +function writeToTag(plainBytes, taglen, filename) + local bytes + if(utils.confirm("\nplace your empty tag onto the PM3 to read & write\n") == false) then + return + end + + -- write data to file + if (taglen > 0) then + WriteBytes = utils.input("enter number of bytes to write?", taglen) + + -- load file into pm3-buffer + if (type(filename)~="string") then filename=input("filename to load to pm3-buffer?","legic.temp") end + cmd = 'hf legic load '..filename + core.console(cmd) + + -- write pm3-buffer to Tag + for i=0, WriteBytes do + if ( i<5 or i>6) then + cmd = ('hf legic write 0x%02x 0x01'):format(i) + core.console(cmd) + --print(cmd) + elseif (i == 6) then + -- write DCF in reverse order (requires 'mosci-patch') + cmd = 'hf legic write 0x05 0x02' + core.console(cmd) + --print(cmd) + else + print("skipping byte 0x05 - will be written next step") + end + utils.Sleep(0.2) + end + end +end + +--- +-- edit segment helper +function editSegment(tag, index) + local k,v + local edit_possible="valid len RD WRP WRC Stamp Payload" + if (istable(tag.SEG[index])) then + for k,v in pairs(tag.SEG[index]) do + if(string.find(edit_possible,k)) then + tag.SEG[index][k]=tonumber(input(k..": ", v),10) + end + end + else print("Segment with Index: "..("%02d"):format(index).." not found in Tag") + return false + end + regenSegmentHeader(tag.SEG[index]) + print("\n"..dumpSegment(tag, index).."\n") + return tag +end + +--- +-- edit Segment Data +function editSegmentData(data) + if (istable(data)) then + for i=0, #data-1 do + data[i]=input("Data"..i..": ", data[i]) + end + return data + else + print("no Segment-Data found") + end +end + +--- +-- list available segmets in virtual tag +function segmentList(tag) + local i + local res = "" + if (istable(tag.SEG[0])) then + for i=0, #tag.SEG do + res = res .. tag.SEG[i].index .. " " + end + return res + else print("no Segments found in Tag") + return false + end +end + +--- +-- helper to selecting a segment +function selectSegment(tag) + local sel + if (istable(tag)) then + print("availabe Segments:\n"..segmentList(tag)) + sel=input("select Segment: ", '00') + sel=tonumber(sel,10) + if (sel) then return sel + else return '0' end + else + print("\nno Segments found") + return false + end +end + +--- +-- add segment +function addSegment(tag) + local i + local segment={ + ['index'] = '00', + ['flag'] = 'c', + ['valid'] = 1, + ['last'] = 1, + ['len'] = 13, + ['raw'] = {'0d', '40', '04', '00'}, + ['WRP'] = 4, + ['WRC'] = 0, + ['RD'] = 0, + ['crc'] = '00', + ['data'] = {}, + ['kgh'] = false + } + if (istable(tag.SEG[0])) then + tag.SEG[#tag.SEG].last=0 + table.insert(tag.SEG, segment) + for i=0, 8 do + tag.SEG[#tag.SEG].data[i]=("%02x"):format(i) + end + tag.SEG[#tag.SEG].index=("%02d"):format(#tag.SEG) + return tag + else + print("no Segment-Table found") + end +end + +--- +-- +function delSegment(tag, index) + local i + if (type(index)=="string") then index=tonumber(index,10) end + if (index > 0) then + table.remove(tag.SEG, index) + for i=0, #tag.SEG do + tag.SEG[i].index=("%02d"):format(i) + end + end + if(istable(tag.SEG[#tag.SEG])) then tag.SEG[#tag.SEG].last=1 end + return tag +end + +--- +-- helptext for modify-mode +function modifyHelp() + local t=[[ + + Data I/O Segment Manipulation File I/O +------------------ -------------------- --------------- + rt => read Tag ds => dump Segments lf => load File + wt => write Tag as => add Segment sf => save File + ct => copy io Tag es => edit Segment xf => xor File + tc => copy oi Tag ed => edit Data + di => dump inTag rs => remove Segment + do => dump outTag cc => check Segment-CRC + ck => check KGH + tk => toggle KGH-Flag + q => quit xc => get KGH-Str h => this Help + ]] + return t +end + +--- +-- modify Tag (interactive) +function modifyMode() + local i, outTAG, inTAG, outfile, infile, sel, segment, bytes, outbytes + actions = { + ["h"] = function(x) + print(modifyHelp().."\n".."tags im Memory:"..(istable(inTAG) and " inTAG" or "")..(istable(outTAG) and " outTAG" or "")) + end, + ["rt"] = function(x) inTAG=readFromPM3(); actions['di']('') end, + ["wt"] = function(x) + if(istable(inTAG)) then + local taglen=22 + for i=0, #inTAG.SEG do + taglen=taglen+inTAG.SEG[i].len+5 + end + -- read new tag (output tag) + outTAG=readFromPM3() + outbytes=tagToBytes(outTAG) + -- copy 'inputbuffer' to 'outputbuffer' + inTAG.MCD = outbytes[1] + inTAG.MSN0 = outbytes[2] + inTAG.MSN1 = outbytes[3] + inTAG.MSN2 = outbytes[4] + inTAG.MCC = outbytes[5] + -- recheck all segments-crc/kghcrc + checkAllSegCrc(inTAG) + checkAllKghCrc(inTAG) + --get bytes from ready outTAG + bytes=tagToBytes(inTAG) + if (bytes) then + writeFile(bytes, 'MylegicClone.hex') + writeToTag(bytes, taglen, 'MylegicClone.hex') + actions['rt']('') + end + end + end, + ["ct"] = function(x) + print("copy virtual input-TAG to output-TAG") + outTAG=inTAG + end, + ["tc"] = function(x) + print("copy virtual output-TAG to input-TAG") + inTAG=outTAG + end, + ["lf"] = function(x) + filename=input("enter filename: ", "legic.temp") + inTAG=readFile(filename) + end, + ["sf"] = function(x) + if(istable(inTAG)) then + outfile=input("enter filename:", "legic.temp") + bytes=tagToBytes(inTAG) + --bytes=xorBytes(bytes, inTAG.MCC) + if (bytes) then + writeFile(bytes, outfile) + end + end + end, + ["xf"] = function(x) + if(istable(inTAG)) then + outfile=input("enter filename:", "legic.temp") + crc=input("enter new crc: ('00' for a plain dump)", inTAG.MCC) + print("obfuscate witth: "..crc) + bytes=tagToBytes(inTAG) + bytes[5]=crc + if (bytes) then + writeFile(bytes, outfile) + end + end + end, + ["di"] = function(x) if (istable(inTAG)) then print("\n"..dumpTag(inTAG).."\n") end end, + ["do"] = function(x) if (istable(outTAG)) then print("\n"..dumpTag(outTAG).."\n") end end, + ["ds"] = function(x) + sel=selectSegment(inTAG) + if (sel) then print("\n"..(dumpSegment(inTAG, sel) or "no Segments available").."\n") end + end, + ["es"] = function(x) + sel=selectSegment(inTAG) + if (sel) then + if(istable(inTAG.SEG)) then + inTAG=editSegment(inTAG, sel) + inTAG.SEG[sel]=regenSegmentHeader(inTAG.SEG[sel]) + else print("no Segments in Tag") end + end + end, + ["as"] = function(x) + if (istable(inTAG.SEG[0])) then + inTAG=addSegment(inTAG) + inTAG.SEG[#inTAG.SEG-1]=regenSegmentHeader(inTAG.SEG[#inTAG.SEG-1]) + inTAG.SEG[#inTAG.SEG]=regenSegmentHeader(inTAG.SEG[#inTAG.SEG]) + else print("unsegmented Tag!") + end + end, + ["rs"] = function(x) + if (istable(inTAG)) then + sel=selectSegment(inTAG) + inTAG=delSegment(inTAG, sel) + for i=0, #inTAG.SEG do + inTAG.SEG[i]=regenSegmentHeader(inTAG.SEG[i]) + end + end + end, + ["ed"] = function(x) + sel=selectSegment(inTAG) + if (sel) then + inTAG.SEG[sel].data=editSegmentData(inTAG.SEG[sel].data) + end + end, + ["ts"] = function(x) + sel=selectSegment(inTAG) + regenSegmentHeader(inTAG.SEG[sel]) + end, + ["tk"] = function(x) + sel=selectSegment(inTAG) + if(inTAG.SEG[sel].kgh) then inTAG.SEG[sel].kgh=false + else inTAG.SEG[sel].kgh=true end + end, + ["k"] = function(x) + print(("%02x"):format(utils.Crc8Legic(x))) + end, + ["xc"] = function(x) + --get credential-string for kgh-crc on certain segment + --usage: xc + print("k "..kghCrcCredentials(inTAG, x)) + end, + ["cc"] = function(x) if (istable(inTAG)) then checkAllSegCrc(inTAG) end end, + ["ck"] = function(x) if (istable(inTAG)) then checkAllKghCrc(inTAG) end end, + ["q"] = function(x) end, + } + print("modify-modus! enter 'h' for help or 'q' to quit") + repeat + ic=input("Legic command? ('h' for help - 'q' for quit)", "h") + -- command actions + if (type(actions[string.lower(string.sub(ic,0,1))])=='function') then + actions[string.lower(string.sub(ic,0,1))](string.sub(ic,3)) + elseif (type(actions[string.lower(string.sub(ic,0,2))])=='function') then + actions[string.lower(string.sub(ic,0,2))](string.sub(ic,4)) + else actions['h']('') end + until (string.sub(ic,0,1)=="q") +end + +--- main +function main(args) + if (#args == 0 ) then modifyMode() end + --- variables + local inTAG, outTAG, outfile, interactive, crc, ofs, cfs, dfs + -- just a spacer for better readability + print() + --- parse arguments + for o, a in getopt.getopt(args, 'hrmi:do:c:') do + -- display help + if o == "h" then return help(); end + -- read tag from PM3 + if o == "r" then inTAG=readFromPM3() end + -- input file + if o == "i" then inTAG=readFile(a) end + -- dump virtual-Tag + if o == "d" then dfs=true end + -- interacive modifying + if o == "m" then interactive=true; modifyMode() end + -- xor (e.g. for clone or plain file) + if o == "c" then cfs=true; crc=a end + -- output file + if o == "o" then outfile=a; ofs=true end + end + + -- file conversion (output to file) + if (ofs) then + -- dump infile / tag-read + if (dfs) then + print("-----------------------------------------") + print(dumpTag(inTAG)) + end + bytes=tagToBytes(inTAG) + -- xor with given crc + if (cfs) then + bytes[5]=crc + end + -- write to outfile + if (bytes) then + writeFile(bytes, outfile) + -- reed new content into virtual tag + + inTAG=bytesToTag(bytes, inTAG) + -- show new content + if (dfs) then + print("-----------------------------------------") + print(dumpTag(outTAG)) + end + end + end + +end + +--- start +main(args) \ No newline at end of file diff --git a/client/scripts/legic_buffer2card.lua b/client/scripts/legic_buffer2card.lua new file mode 100644 index 00000000..845e8e8e --- /dev/null +++ b/client/scripts/legic_buffer2card.lua @@ -0,0 +1,54 @@ +-- this script writes bytes 8 to 256 on the Legic MIM256 +example = "Script writes to Legic Prime Tag from position 0x07 until 0xFF with the value 0x01" +author = "Mosci" +desc = +[[ +This is a script which writes value 0x01 to bytes from position 0x07 until 0xFF on a Legic Prime Tag (MIM256 or MIM1024) +(created with 'hf legic save my_dump.hex') + +optional arguments : + -h - Help text + +Examples : + script run legic_buffer2card +]] + +local utils = require('utils') +local getopt = require('getopt') +--- +-- This is only meant to be used when errors occur +function oops(err) + print("ERROR: ",err) + return nil, err + end +--- +-- Usage help +function help() + print(desc) + print("Example usage") + print(example) +end +-- +-- simple loop-write from 0x07 to 0xff +function main() + + -- parse arguments for the script + for o, a in getopt.getopt(args, 'h') do + if o == "h" then return help() end + end + + local cmd = '' + local i + for i = 7, 255 do + cmd = ('hf legic write 0x%02x 0x01'):format(i) + print(cmd) + core.clearCommandBuffer() + core.console(cmd) + + -- got a 'cmd-buffer overflow' on my mac - so just wait a little + -- works without that pause on my linux-box + utils.Sleep(0.1) + end +end + +main() -- 2.39.5 From 0d2c590974319db6fc54400ce153d86b68a09852 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 28 Feb 2016 22:43:21 +0100 Subject: [PATCH 12/16] ADD: num_to_bytebitsLSBF function. ADD: lf guard clone - works... needs some checking. ADD: added a option to "addparity" to set zero on fixed pos. --- client/cmddata.c | 4 +- client/cmdlfguard.c | 139 +++++++++++++++++++++++++------------------- client/util.c | 20 ++++++- client/util.h | 15 ++++- common/lfdemod.c | 17 +++--- 5 files changed, 123 insertions(+), 72 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index 8e0668f7..311e5b32 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -619,13 +619,13 @@ int CmdG_Prox_II_Demod(const char *Cmd) continue; } if (keyCnt<8){ //lsb first - xorKey = xorKey | (DemodBuffer[startIdx+idx]< clone Guardall tag"}, + {"clone", CmdGuardClone, 0, " clone Guardall tag"}, // {"sim", CmdGuardSim, 0, " simulate Guardall tag"}, {NULL, NULL, 0, NULL} }; diff --git a/client/util.c b/client/util.c index ae8e4fec..9768dbeb 100644 --- a/client/util.c +++ b/client/util.c @@ -103,6 +103,7 @@ void print_hex(const uint8_t * data, const size_t len) { printf("%02x ", data[i]); printf("\n"); } + void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) { int rownum = 0; @@ -178,6 +179,7 @@ char *sprint_hex_ascii(const uint8_t *data, const size_t len) { sprintf(tmp, "%s| %s", sprint_hex(data, max_len) , data); return buf; } + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { @@ -197,12 +199,22 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } -void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { +// takes a number (uint64_t) and creates a binarray in dest. +void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { while (len--) { dest[len] = n & 1; n >>= 1; } } +//least significant bit first +void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) +{ + for(int i = 0 ; i < len ; ++i) { + dest[i] = n & 1; + n >>= 1; + } +} + // aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp // to @@ -220,6 +232,8 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS return tmp; } +// takes a uint8_t src array, for len items and reverses the byte order in blocksizes (8,16,32,64), +// returns: the dest array contains the reordered src array. void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest){ for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){ for (size_t i = 0; i < blockSize; i++){ @@ -228,7 +242,6 @@ void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSiz } } - // ------------------------------------------------------------------------- // string parameters lib // ------------------------------------------------------------------------- @@ -493,6 +506,7 @@ void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length) *(target)= GetParity(source + length / 2, ODD, length / 2); } +// xor two arrays together for len items. The dst array contains the new xored values. void xor(unsigned char * dst, unsigned char * src, size_t len) { for( ; len > 0; len--,dst++,src++) *dst ^= *src; @@ -502,6 +516,7 @@ int32_t le24toh (uint8_t data[3]) { return (data[2] << 16) | (data[1] << 8) | data[0]; } +// Pack a bitarray into a uint32_t. uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits) { if (len > 32) return 0; @@ -526,6 +541,7 @@ void rol(uint8_t *data, const size_t len){ data[len-1] = first; } +// Swap bit order on a uint32_t value. Can be limited by nrbits just use say 8bits reversal uint32_t SwapBits(uint32_t value, int nrbits) { uint32_t newvalue = 0; for(int i = 0; i < nrbits; i++) { diff --git a/client/util.h b/client/util.h index 2813bb8c..9c16ba5b 100644 --- a/client/util.h +++ b/client/util.h @@ -36,6 +36,18 @@ #define EVEN 0 #define ODD 1 +#ifndef NIBBLE_HIGH +# define NIBBLE_HIGH(b) ( (b & 0xF0) >> 4 ) +#endif +#ifndef NIBBLE_LOW +# define NIBBLE_LOW(b) ( b & 0x0F ) +#endif +#ifndef CRUMB +# define CRUMB(b,p) (((b & (0x3 << p) ) >> p ) & 0xF) +#endif +#ifndef SWAP_NIBBLE +# define SWAP_NIBBLE(b) ( (NIBBLE_LOW(b)<< 4) | NIBBLE_HIGH(b)) +#endif int ukbhit(void); void AddLogLine(char *fileName, char *extData, char *c); @@ -53,7 +65,8 @@ char *sprint_hex_ascii(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); -void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest); +void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest); +void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest); uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest); diff --git a/common/lfdemod.c b/common/lfdemod.c index 1c05920d..edebe456 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -95,7 +95,7 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p // by marshmellow // takes a array of binary values, length of bits per parity (includes parity bit), -// Parity Type (1 for odd; 0 for even; 2 Always 1's), and binary Length (length to run) +// Parity Type (1 for odd; 0 for even; 2 Always 1's; 3 Always 0's), and binary Length (length to run) size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType) { uint32_t parityWd = 0; @@ -105,12 +105,16 @@ size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t p parityWd = (parityWd << 1) | BitSource[word+bit]; dest[j++] = (BitSource[word+bit]); } + // if parity fails then return 0 - if (pType == 2) { // then marker bit which should be a 1 - dest[j++]=1; - } else { - dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1; + switch (pType) { + case 3: dest[j++]=0; break; // marker bit which should be a 0 + case 2: dest[j++]=1; break; // marker bit which should be a 1 + default: + dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1; + break; } + bitCnt += pLen; parityWd = 0; } @@ -122,8 +126,7 @@ size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t p uint32_t bytebits_to_byte(uint8_t *src, size_t numbits) { uint32_t num = 0; - for(int i = 0 ; i < numbits ; i++) - { + for(int i = 0 ; i < numbits ; i++) { num = (num << 1) | (*src); src++; } -- 2.39.5 From 07291f87d8c6cfa3a7179776937df9eadc20f04d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 28 Feb 2016 23:28:38 +0100 Subject: [PATCH 13/16] ADD: finished of the "LF GUARD SIM" command. needs testing. --- client/cmdlf.c | 170 ++++++++++++++++++++++---------------------- client/cmdlfguard.c | 38 +++++----- 2 files changed, 102 insertions(+), 106 deletions(-) diff --git a/client/cmdlf.c b/client/cmdlf.c index 0f5d0dc0..09a97205 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -743,94 +743,94 @@ int CmdLFfskSim(const char *Cmd) // - allow pull data from DemodBuffer int CmdLFaskSim(const char *Cmd) { - //autodetect clock from Graphbuffer if using demod buffer + //autodetect clock from Graphbuffer if using demod buffer // needs clock, invert, manchester/raw as m or r, separator as s, and bitstream - uint8_t encoding = 1, separator = 0; - uint8_t clk=0, invert=0; - bool errors = FALSE; - char hexData[32] = {0x00}; - uint8_t data[255]= {0x00}; // store entered hex data - int dataLen = 0; - uint8_t cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00) - { - switch(param_getchar(Cmd, cmdp)) - { - case 'h': - return usage_lf_simask(); - case 'i': - invert = 1; - cmdp++; - break; - case 'c': - errors |= param_getdec(Cmd,cmdp+1,&clk); - cmdp+=2; - break; - case 'b': - encoding=2; //biphase - cmdp++; - break; - case 'm': - encoding=1; - cmdp++; - break; - case 'r': - encoding=0; - cmdp++; - break; - case 's': - separator=1; - cmdp++; - break; - case 'd': - dataLen = param_getstr(Cmd, cmdp+1, hexData); - if (dataLen==0) { - errors=TRUE; - } else { - dataLen = hextobinarray((char *)data, hexData); - } - if (dataLen==0) errors=TRUE; - if (errors) PrintAndLog ("Error getting hex data, datalen: %d",dataLen); - cmdp+=2; - break; - default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = TRUE; - break; - } - if(errors) break; - } - if(cmdp == 0 && DemodBufferLen == 0) - { - errors = TRUE;// No args - } + uint8_t encoding = 1, separator = 0, clk=0, invert=0; + bool errors = FALSE; + char hexData[32] = {0x00}; + uint8_t data[255]= {0x00}; // store entered hex data + int dataLen = 0; + uint8_t cmdp = 0; + + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'h': return usage_lf_simask(); + case 'i': + invert = 1; + cmdp++; + break; + case 'c': + errors |= param_getdec(Cmd,cmdp+1,&clk); + cmdp+=2; + break; + case 'b': + encoding=2; //biphase + cmdp++; + break; + case 'm': + encoding=1; + cmdp++; + break; + case 'r': + encoding=0; + cmdp++; + break; + case 's': + separator=1; + cmdp++; + break; + case 'd': + dataLen = param_getstr(Cmd, cmdp+1, hexData); + if (dataLen==0) + errors = TRUE; + else + dataLen = hextobinarray((char *)data, hexData); + + if (dataLen==0) errors = TRUE; + if (errors) PrintAndLog ("Error getting hex data, datalen: %d", dataLen); + cmdp+=2; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = TRUE; + break; + } + if(errors) break; + } + + if(cmdp == 0 && DemodBufferLen == 0) + errors = TRUE;// No args - //Validations - if(errors) - { - return usage_lf_simask(); - } - if (dataLen == 0){ //using DemodBuffer - if (clk == 0) clk = GetAskClock("0", false, false); - } else { - setDemodBuf(data, dataLen, 0); - } - if (clk == 0) clk = 64; - if (encoding == 0) clk = clk/2; //askraw needs to double the clock speed - uint16_t arg1, arg2; - size_t size=DemodBufferLen; - arg1 = clk << 8 | encoding; - arg2 = invert << 8 | separator; - if (size > USB_CMD_DATA_SIZE) { - PrintAndLog("DemodBuffer too long for current implementation - length: %d - max: %d", size, USB_CMD_DATA_SIZE); - size = USB_CMD_DATA_SIZE; - } - UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; - PrintAndLog("preparing to sim ask data: %d bits", size); - memcpy(c.d.asBytes, DemodBuffer, size); + //Validations + if(errors) return usage_lf_simask(); + + if (dataLen == 0){ //using DemodBuffer + if (clk == 0) + clk = GetAskClock("0", false, false); + } else { + setDemodBuf(data, dataLen, 0); + } + if (clk == 0) clk = 64; + if (encoding == 0) clk = clk/2; //askraw needs to double the clock speed + + size_t size = DemodBufferLen; + + if (size > USB_CMD_DATA_SIZE) { + PrintAndLog("DemodBuffer too long for current implementation - length: %d - max: %d", size, USB_CMD_DATA_SIZE); + size = USB_CMD_DATA_SIZE; + } + + PrintAndLog("preparing to sim ask data: %d bits", size); + + uint16_t arg1, arg2; + arg1 = clk << 8 | encoding; + arg2 = invert << 8 | separator; + + UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; + memcpy(c.d.asBytes, DemodBuffer, size); clearCommandBuffer(); - SendCommand(&c); - return 0; + SendCommand(&c); + return 0; } // by marshmellow - sim psk data given carrier, clock, invert diff --git a/client/cmdlfguard.c b/client/cmdlfguard.c index 828bdb68..05975eea 100644 --- a/client/cmdlfguard.c +++ b/client/cmdlfguard.c @@ -91,12 +91,6 @@ int GetGuardBits(uint32_t fc, uint32_t cn, uint8_t *guardBits) { if (g_debugMode) printf(" WIE | %s\n", sprint_hex(rawbytes, sizeof(rawbytes))); - // NIBBLE_SWAP (works on all data) - // for (i = 0; i < 12; ++i) - // rawbytes[i] = SWAP_NIBBLE( rawbytes[i] ); - - // printf("SWAP | %s\n", sprint_hex(rawbytes, sizeof(rawbytes))); - // XOR (only works on wiegand stuff) for (i = 1; i < 12; ++i) rawbytes[i] ^= xorKey ; @@ -111,7 +105,7 @@ int GetGuardBits(uint32_t fc, uint32_t cn, uint8_t *guardBits) { if (g_debugMode) printf(" Raw | %s\n", sprint_bin(pre, 64) ); // add spacer bit 0 every 4 bits, starting with index 0, - // 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. Ie 9bytes | 1byte xorkey, 8bytes rawdata (64bits, should be enough for a 40bit wiegand) + // 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. ie 9bytes | 1byte xorkey, 8bytes rawdata (64bits, should be enough for a 40bit wiegand) addParity(pre, guardBits+6, 64, 5, 3); // preamble @@ -121,10 +115,6 @@ int GetGuardBits(uint32_t fc, uint32_t cn, uint8_t *guardBits) { guardBits[3] = 1; guardBits[4] = 1; guardBits[5] = 0; -/* 6 B -PRE | 0110 1101 0101 1110 0001 1101 1101 0111 1101011011010110110101101101011 -FIN | 111110 0 0110 0 1101 0 0101 0 1110 0 0001 0 1101 0 1101 0 0111 0 110100110011010011001101001100110100110000000000 -*/ if (g_debugMode) printf(" FIN | %s\n", sprint_bin(guardBits, 96) ); return 1; @@ -194,16 +184,11 @@ int CmdGuardSim(const char *Cmd) { if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_lf_guard_sim(); uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0; + uint8_t clock = 64, encoding = 2, separator = 0, invert = 0; uint8_t bs[96]; - size_t size = sizeof(bs); - memset(bs, 0x00, size); + memset(bs, 0x00, sizeof(bs)); - // Pyramid uses: ASK Biphase, clk: 32, invert: 0 - uint64_t arg1, arg2; - arg1 = (10 << 8) + 8; - arg2 = 32 | 0; - if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_guard_sim(); facilitycode = (fc & 0x000000FF); @@ -215,9 +200,20 @@ int CmdGuardSim(const char *Cmd) { } PrintAndLog("Simulating Guardall - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber ); - + + // Guard uses: clk: 64, invert: 0, encoding: 2 (ASK Biphase) + uint64_t arg1, arg2; + arg1 = (clock << 8) | encoding; + arg2 = (invert << 8) | separator; + + uint8_t rawbytes[12]; + size_t size = sizeof(rawbytes); + for (uint8_t i=0; i < size; ++i){ + rawbytes[i] = bytebits_to_byte( bs + (i*8), 8); + } + UsbCommand c = {CMD_ASK_SIM_TAG, {arg1, arg2, size}}; - memcpy(c.d.asBytes, bs, size); + memcpy(c.d.asBytes, rawbytes, size ); clearCommandBuffer(); SendCommand(&c); return 0; @@ -227,7 +223,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"read", CmdGuardRead, 0, "Attempt to read and extract tag data"}, {"clone", CmdGuardClone, 0, " clone Guardall tag"}, -// {"sim", CmdGuardSim, 0, " simulate Guardall tag"}, + {"sim", CmdGuardSim, 0, " simulate Guardall tag"}, {NULL, NULL, 0, NULL} }; -- 2.39.5 From 547595784facfc9565ca08af18d9bead6bfac31b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 29 Feb 2016 09:05:54 +0100 Subject: [PATCH 14/16] CHG: Updated the CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65e161c4..b365dcf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added `lf guard clone/sim` (iceman) + - Added `lf pyramd clone/sim` (iceman) - trying to fix "hf 14b" command to be able to read CALYPSO card. (iceman) - `hf legic load`, it now loads faster and a casting bug is gone. (iceman) - Added `hf legic calccrc8` added a method to calculate the legic crc-8 value (iceman) -- 2.39.5 From c728b2b4cf2ce9fe4eebf0e46d74ef8542e56c16 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 1 Mar 2016 06:57:02 +0100 Subject: [PATCH 15/16] FIX: Added @marshmellow42 's fix for ASK/Biphase simulation on deviceside. CHG: Added @marshmellow42 's refactoring of "gprox-II" demod. --- armsrc/lfops.c | 4 +-- client/cmddata.c | 59 ++++++++++++++++++--------------------------- client/cmdlfguard.c | 2 +- common/lfdemod.c | 13 +++++----- 4 files changed, 33 insertions(+), 45 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 7f61c78d..54800f49 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -628,7 +628,7 @@ static void biphaseSimBit(uint8_t c, int *n, uint8_t clock, uint8_t *phase) memset(dest+(*n), c ^ *phase, clock); *phase ^= 1; } - + *n += clock; } // args clock, ask/man or askraw, invert, transmission separator @@ -646,7 +646,7 @@ void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) for (i=0; i>2; uint32_t FC = 0; uint32_t Card = 0; + //get raw 96 bits to print uint32_t raw1 = bytebits_to_byte(DemodBuffer+ans,32); uint32_t raw2 = bytebits_to_byte(DemodBuffer+ans+32, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer+ans+64, 32); @@ -649,13 +635,14 @@ int CmdG_Prox_II_Demod(const char *Cmd) if (fmtLen==36){ FC = ((ByteStream[3] & 0x7F)<<7) | (ByteStream[4]>>1); Card = ((ByteStream[4]&1)<<19) | (ByteStream[5]<<11) | (ByteStream[6]<<3) | (ByteStream[7]>>5); - PrintAndLog("G-Prox-II Found: FmtLen %d, FC %d, Card %d",fmtLen,FC,Card); + PrintAndLog("G-Prox-II Found: FmtLen %d, FC %u, Card %u", (int)fmtLen, FC, Card); } else if(fmtLen==26){ FC = ((ByteStream[3] & 0x7F)<<1) | (ByteStream[4]>>7); Card = ((ByteStream[4]&0x7F)<<9) | (ByteStream[5]<<1) | (ByteStream[6]>>7); - PrintAndLog("G-Prox-II Found: FmtLen %d, FC %d, Card %d",fmtLen,FC,Card); + PrintAndLog("G-Prox-II Found: FmtLen %d, FC %u, Card %u", (int)fmtLen, FC, Card); } else { - PrintAndLog("Unknown G-Prox-II Fmt Found: FmtLen %d",fmtLen); + PrintAndLog("Unknown G-Prox-II Fmt Found: FmtLen %d",(int)fmtLen); + PrintAndLog("Decoded Raw: %s", sprint_hex(ByteStream, 8)); } PrintAndLog("Raw: %08x%08x%08x", raw1,raw2,raw3); setDemodBuf(DemodBuffer+ans, 96, 0); diff --git a/client/cmdlfguard.c b/client/cmdlfguard.c index 05975eea..686ada27 100644 --- a/client/cmdlfguard.c +++ b/client/cmdlfguard.c @@ -48,7 +48,7 @@ int GetGuardBits(uint32_t fc, uint32_t cn, uint8_t *guardBits) { time_t t; srand((unsigned) time(&t)); //uint8_t xorKey = rand() % 0xFF; - uint8_t xorKey = 0x6b; + uint8_t xorKey = 0x66; uint8_t i; diff --git a/common/lfdemod.c b/common/lfdemod.c index edebe456..862d05ba 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -68,7 +68,7 @@ uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType) //by marshmellow // takes a array of binary values, start position, length of bits per parity (includes parity bit), -// Parity Type (1 for odd; 0 for even; 2 Always 1's), and binary Length (length to run) +// Parity Type (1 for odd; 0 for even; 2 for Always 1's; 3 for Always 0's), and binary Length (length to run) size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen) { uint32_t parityWd = 0; @@ -80,10 +80,11 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p } j--; // overwrite parity with next data // if parity fails then return 0 - if (pType == 2) { // then marker bit which should be a 1 - if (!BitStream[j]) return 0; - } else { - if (parityTest(parityWd, pLen, pType) == 0) return 0; + switch (pType) { + case 3: if (BitStream[j]==1) return 0; break; //should be 0 spacer bit + case 2: if (BitStream[j]==0) return 0; break; //should be 1 spacer bit + default: //test parity + if (parityTest(parityWd, pLen, pType) == 0) return 0; break; } bitCnt+=(pLen-1); parityWd = 0; @@ -96,6 +97,7 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p // by marshmellow // takes a array of binary values, length of bits per parity (includes parity bit), // Parity Type (1 for odd; 0 for even; 2 Always 1's; 3 Always 0's), and binary Length (length to run) +// Make sure *dest is long enough to store original sourceLen + #_of_parities_to_be_added size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType) { uint32_t parityWd = 0; @@ -114,7 +116,6 @@ size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t p dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1; break; } - bitCnt += pLen; parityWd = 0; } -- 2.39.5 From ff4ff94b2589558e84ec0a9b3eebe7250d3f350f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 1 Mar 2016 06:58:32 +0100 Subject: [PATCH 16/16] DEL: Removed old comment, after I've been compiling and testing all -W parameters in it. Didn't find any new warnings. Which is good. --- common/Makefile.common | 1 - 1 file changed, 1 deletion(-) diff --git a/common/Makefile.common b/common/Makefile.common index 72ad0758..90a8fa5a 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -67,7 +67,6 @@ VPATH = . ../common ../fpga ../zlib INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/usb_cmd.h $(APP_INCLUDES) -#-Wunused -Wsign-compare -Wtype-limits -Wuninitialized -Wno-deprecated -Wstrict-aliasing -Wpointer-arith -Wpointer-arith -Wformat-nonliteral -Winit-self -Wparentheses -Wunreachable-code CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -Wunused -std=c99 $(APP_CFLAGS) -Os LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n -- 2.39.5