2017-05-18 00:52:30 +08:00
--[[
2016-06-22 15:33:21 +08:00
if it don ' t works with you tag-layout - be so kind and let me know ;-)
Tested on Tags with those Layouts :
2016-03-21 02:25:48 +08:00
2016-02-28 21:50:49 +08:00
( example ) Legic - Prime Layout with ' Kaba Group Header '
+----+----+----+----+----+----+----+----+
2017-05-18 00:52:30 +08:00
0x00 | MCD | MSN0 | MSN1 | MSN2 | MCC | 60 | ea | 9 f |
2016-02-28 21:50:49 +08:00
+----+----+----+----+----+----+----+----+
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 |
+----+----+----+
2016-03-06 20:26:13 +08:00
MCD = Manufacturer ID
MSN = Manufacturer SerialNumber
60 ea = DCF Low + DCF high
9 f = raw byte which holds the bits for OLE , WRP , WRC , RD
ff = unknown but important
00 = unimportant
11 = unknown but important
Bck = header - backup - area
00 00 = Year ( 00 = 2000 ) & Week ( not important )
Seg = Segment Header
SegC = Crc8 over the Segment Header
Stp = Stamp ( could be more as 4 - up to 7 )
UID = dec User - ID for online - Mapping
kghC = crc8 over MCD + MSN0 .. MSN2 + UID
( example ) Legic - Cash on MIM256 / 1024 tag ' (37 bytes)
+----+----+----+----+----+----+----+----+
2017-05-18 00:52:30 +08:00
0x00 | Seg0 | Seg1 | Seg2 | Seg3 | SegC | STP0 | STP1 | STP2 |
2016-03-06 20:26:13 +08:00
+----+----+----+----+----+----+----+----+
0x08 | STP3 | STP4 | STP5 | STP6 | 01 | CURh | CURl | LIMh |
+----+----+----+----+----+----+----+----+
0x10 | LIMm | LIMl | CHKh | CHKl | BALh | BALm | BALl | LRBh |
+----+----+----+----+----+----+----+----+
0x18 | LRBm | LRBl | CHKh | CHKl | SHDh | SHDm | SHDl | LRSh |
+----+----+----+----+----+----+----+----+
0x20 | LRSm | LRSl | CV | CHKh | CHKl |
+----+----+----+----+----+
STP = Stamp ( seems to be always 7 bytes )
01 = unknown but important
CUR = currency in HEX ( ISO 4217 )
LIM = Cash - Limit
CHK = crc16 over byte - addr 0x05. .0 x12
BAL = Balance
LRB = ID of the reader that changed the balance
CHK = crc16 over BAL + LRB
SHD = shadow Balance
LRS = ID of the reader that changed the shadow balance ( ? ? should be always the same as LRB )
CV = Counter value for transactions
CHK = crc16 over SHD + LRS + CV
2016-06-22 15:33:21 +08:00
( example ) Legic - Prime Layout ' gantner unsegmented user-credential '
+----+----+----+----+----+----+----+----+
2017-05-18 00:52:30 +08:00
0x00 | MCD | MSN0 | MSN1 | MSN2 | MCC | 60 | ea | 08 |
2016-06-22 15:33:21 +08:00
+----+----+----+----+----+----+----+----+
0x08 | Stp0 | Stp1 | Stp2 | Stp3 | Stp4 | Dat0 | Dat1 | uCRC | <- addr 0x08. .0 x0f is WRP
+----+----+----+----+----+----+----+----+
0x10 | emb0 | <- this is only within wrp if addr 0x07 == 09
+----+
MCD = Manufacturer ID
MSN = Manufacturer SerialNumber
60 ea = DCF Low + DCF high
08 = raw byte which holds the bits for OLE , WRP , WRC , RD
Stp = Stamp ( could be more as 4 - up to 7 )
Dat = Online - Mapping Data
uCRC = crc8 over addr 0x00. .0 x03 + 0x07. .0 x0E
( example ) Legic - Prime Layout ' gantner unsegmented Master-Token (IAM) with a stamp_len of 4 '
+----+----+----+----+----+----+----+----+
2017-05-18 00:52:30 +08:00
0x00 | MCD | MSN0 | MSN1 | MSN2 | MCC | 20 | f8 | 08 |
2016-06-22 15:33:21 +08:00
+----+----+----+----+----+----+----+----+
0x08 | Stp0 | Stp1 | Stp2 | Stp3 | 00 | 00 | 00 | CRC1 |
+----+----+----+----+----+----+----+----+
2017-05-18 00:52:30 +08:00
0x10 | 00 | 00 | 00 | 00 | 00 | CRC2 |
2016-06-22 15:33:21 +08:00
+----+----+----+----+----+----+
MCD = Manufacturer ID
MSN = Manufacturer SerialNumber
60 ea = DCF Low + DCF high
08 = raw byte which holds the bits for OLE , WRP , WRC , RD
Stp = Stamp ( could be more as 4 - up to 7 )
Dat = Online - Mapping Data
CRC1 = crc8 over addr 0x00. .0 x03 + 0x07. .0 x0E ( special ' gantner crc8 ' )
CRC2 = MCD + MSB0 .. 2 + addr 0x06 + addr 0x05 + addr 0x07 + Stamp ( regular Master - Token - CRC )
2016-02-28 21:50:49 +08:00
--]]
example = " script run legic "
author = " Mosci "
2016-03-21 02:25:48 +08:00
version = " 1.0.3 "
2016-02-28 21:50:49 +08:00
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:
2016-03-21 02:25:48 +08:00
Data I / O Segment Manipulation Token - Data
----------------- -------------------- -----------------
rt => read Tag as => add Segment mt => make Token
wt => write Tag es => edit Segment Header et => edit Token data
ed => edit Segment Data tk => toggle KGH - Flag
2017-05-18 00:52:30 +08:00
File I / O rs => remove Segment
----------------- cc => check Segment-CRC
lf => load File ck => check KGH
sf => save File ds => dump Segments
xf => xor to File
2016-03-21 02:25:48 +08:00
( partially ) known Segments Virtual Tags Script Output
--------------------------- ------------------------------- ------------------------
dlc => dump Legic - Cash ct => copy mainTag to backupTag tac => toggle ansicolors
2017-05-18 00:52:30 +08:00
elc => edit Legic - Cash tc => copy backupTag to mainTag
d3p => dump 3 rd - Party - Cash tt => switch mainTag & backupTag
e3p => edit 3 rd - Party - Cash di => dump mainTag
2016-03-21 02:25:48 +08:00
do => dump backupTag
2016-03-06 20:26:13 +08:00
2017-05-18 00:52:30 +08:00
2016-02-28 21:50:49 +08:00
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 .
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
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 )
2017-05-18 00:52:30 +08:00
2016-02-28 21:50:49 +08:00
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
2016-03-21 02:25:48 +08:00
tt : ' toggle tag ' - copy mainTag to BackupTag and backupTag to mainTag
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
di : ' dump mainTag ' - shows the current content of the ' virtual Tag '
do : ' dump backupTag ' - shows the current content of the ' virtual outTag '
2016-02-28 21:50:49 +08:00
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 )
2016-03-01 14:07:56 +08:00
ed : ' edit data ' - edit the Data of a Segment ( ADF - Aera / Stamp & Payload specific Data )
et : ' edit Token ' - edit Data of a Token ( CDF - Area / SAM , SAM64 , SAM63 , IAM , GAM specific Data )
mt : ' make Token ' - create a Token ' from scratch ' ( guided )
2016-02-28 21:50:49 +08:00
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
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
dlc : ' dump Legic-Cash ' - show balance and checksums of a Legic - Cash Segment
elc : ' edit Legic-Cash ' - edit values of a Legic - Cash Segment
d3p : ' dump 3rd Party ' - show balance , history and checksums of a ( yet ) unknown 3 rd - Party Cash Segment
e3p : ' edit 3rd Party ' - edit Data in 3 rd - Party Cash Segment
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
tac : ' toggle ansicolors ' - switch on and off the colored text - output of this script
default can be changed by setting the variable ' colored_output ' to false
2016-02-28 21:50:49 +08:00
] ]
2016-03-06 20:26:13 +08:00
currentTag = " inTAG "
2016-03-21 02:25:48 +08:00
2017-05-18 00:52:30 +08:00
---
2016-03-01 14:07:56 +08:00
-- requirements
2016-03-21 02:25:48 +08:00
local utils = require ( ' utils ' )
local getopt = require ( ' getopt ' )
local ansicolors = require ( ' ansicolors ' )
2016-02-28 21:50:49 +08:00
2017-05-18 00:52:30 +08:00
---
2016-03-01 14:07:56 +08:00
-- global variables / defines
2016-02-28 21:50:49 +08:00
local bxor = bit32.bxor
local bbit = bit32.extract
local input = utils.input
local confirm = utils.confirm
2016-03-21 02:25:48 +08:00
---
-- init ansicolor-values & ansicolors switch
local colored_output = true
local acoff = " "
local acgreen = " "
local accyan = " "
local acred = " "
local acyellow = " "
local acblue = " "
local acmagenta = " "
--- Helper ---
---
-- default colors (change to whatever you want)
function load_colors ( onoff )
if ( onoff ) then
-- colors
acgreen = ansicolors.green
accyan = ansicolors.cyan
acred = ansicolors.red
acyellow = ansicolors.yellow
acblue = ansicolors.blue
acmagenta = ansicolors.magenta
acoff = ansicolors.reset
else
2017-05-18 00:52:30 +08:00
-- 'no color'
2016-03-21 02:25:48 +08:00
acgreen = " "
accyan = " "
acred = " "
acyellow = " "
acblue = " "
acmagenta = " "
acoff = " "
end
end
---
2016-03-06 20:26:13 +08:00
-- curency-codes for Legic-Cash-Segments (ISO 4217)
local currency = {
2017-05-18 00:52:30 +08:00
[ " 03d2 " ] = " EUR " ,
[ " 0348 " ] = " USD " ,
2016-03-06 20:26:13 +08:00
[ " 033A " ] = " GBP " ,
[ " 02F4 " ] = " CHF "
}
2017-05-18 00:52:30 +08:00
---
2016-02-28 21:50:49 +08:00
-- This is only meant to be used when errors occur
function oops ( err )
2016-03-21 02:25:48 +08:00
print ( acred .. " ERROR: " .. acoff , err )
2016-02-28 21:50:49 +08:00
return nil , err
end
2017-05-18 00:52:30 +08:00
---
2016-02-28 21:50:49 +08:00
-- Usage help
function help ( )
print ( desc )
2016-03-21 02:25:48 +08:00
print ( " Version: " .. version )
print ( " Example usage: " .. example )
2016-02-28 21:50:49 +08:00
end
2017-05-18 00:52:30 +08:00
---
2016-02-28 21:50:49 +08:00
-- table check helper
2017-05-18 00:52:30 +08:00
function istable ( t )
return type ( t ) == ' table '
2016-02-28 21:50:49 +08:00
end
---
2016-03-21 02:25:48 +08:00
-- creates a 'deep copy' of a table (a=b only references)
function deepCopy ( object )
local lookup_table = { }
local function _copy ( object )
if type ( object ) ~= " table " then
return object
elseif lookup_table [ object ] then
return lookup_table [ object ]
end
local new_table = { }
lookup_table [ object ] = new_table
for index , value in pairs ( object ) do
new_table [ _copy ( index ) ] = _copy ( value )
end
return setmetatable ( new_table , getmetatable ( object ) )
end
return _copy ( object )
end
2017-05-18 00:52:30 +08:00
---
2016-03-01 14:07:56 +08:00
-- xor single byte
2016-02-28 21:50:49 +08:00
function xorme ( hex , xor , index )
if ( index >= 23 ) then
return ( ' %02x ' ) : format ( bxor ( tonumber ( hex , 16 ) , tonumber ( xor , 16 ) ) )
else
return hex
end
end
2017-05-18 00:52:30 +08:00
---
2016-02-28 21:50:49 +08:00
-- (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
2017-05-18 00:52:30 +08:00
---
2016-02-28 21:50:49 +08:00
-- check availability of file
function file_check ( file_name )
2017-05-18 00:52:30 +08:00
local file_found = io.open ( file_name , " r " )
2016-02-28 21:50:49 +08:00
if file_found == nil then
return false
else
2017-05-18 00:52:30 +08:00
file_found : close ( )
2016-02-28 21:50:49 +08:00
return true
end
end
---
2016-03-21 02:25:48 +08:00
-- split csv-string into table
local function split ( str , sep )
local sep = sep or ' , '
local fields = { }
local matchfunc = string.gmatch ( str , " ([^ " .. sep .. " ]+) " )
if not matchfunc then return { str } end
for str in matchfunc do
table.insert ( fields , str )
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
return fields
2016-02-28 21:50:49 +08:00
end
---
2016-03-21 02:25:48 +08:00
-- put a string into a bytes-table
function str2bytes ( s )
2017-08-13 21:06:30 +08:00
if ( string.len ( s ) % 2 ~= 0 ) then
2017-07-30 15:17:48 +08:00
return print ( " stamp should be a even hexstring e.g.: deadbeef or 0badc0de " )
end
2016-03-21 02:25:48 +08:00
local res = { }
for i = 1 , string.len ( s ) , 2 do
table.insert ( res , string.sub ( s , i , ( i + 1 ) ) )
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
return res
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
---
2016-03-01 14:07:56 +08:00
-- put certain bytes into a new table
function bytesToTable ( bytes , bstart , bend )
2017-08-13 21:06:30 +08:00
local t = { }
for i = 0 , ( bend - bstart ) do
t [ i ] = bytes [ bstart + i ]
end
return t
2016-03-01 14:07:56 +08:00
end
2017-05-18 00:52:30 +08:00
---
2016-02-28 21:50:49 +08:00
-- read file into table
function getInputBytes ( infile )
local line
local bytes = { }
2017-05-18 00:52:30 +08:00
local fhi , err = io.open ( infile , " rb " )
2016-02-28 21:50:49 +08:00
if err then oops ( " faild to read from file " .. infile ) ; return false ; end
2017-05-18 00:52:30 +08:00
2017-08-13 21:06:30 +08:00
file_data = fhi : read ( " *a " ) ;
for i = 1 , # file_data do
bytes [ i ] = string.format ( " %x " , file_data : byte ( i ) )
end
2016-02-28 21:50:49 +08:00
fhi : close ( )
2017-08-13 21:06:30 +08:00
if ( bytes [ 7 ] == ' 00 ' ) then return false end
print ( # bytes .. " bytes from " .. infile .. " loaded " )
2016-02-28 21:50:49 +08:00
return bytes
end
---
-- create tag-table helper
function createTagTable ( )
2017-05-18 00:52:30 +08:00
local t = {
2016-02-28 21:50:49 +08:00
[ ' 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
2017-05-18 00:52:30 +08:00
---
2016-02-28 21:50:49 +08:00
-- put bytes into tag-table
function bytesToTag ( bytes , tag )
2017-08-13 21:06:30 +08:00
if istable ( tag ) == false then return oops ( " tag is no table in: bytesToTag ( " .. type ( tag ) .. " ) " ) end
2017-07-30 15:17:48 +08:00
2016-02-28 21:50:49 +08:00
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 ) )
2016-06-22 15:33:21 +08:00
if ( tag.Type == " SAM " and tag.raw == ' 9f ' ) then
2016-02-28 21:50:49 +08:00
tag.Stamp_len = ( tonumber ( 0xfc , 10 ) - tonumber ( bbit ( " 0x " .. tag.DCFh , 0 , 8 ) , 10 ) )
2016-06-22 15:33:21 +08:00
elseif ( tag.Type == " SAM " and ( tag.raw == ' 08 ' or tag.raw == ' 09 ' ) ) then
tag.Stamp_len = tonumber ( tag.raw , 10 )
end
2016-02-28 21:50:49 +08:00
tag.data = bytesToTable ( bytes , 10 , 13 )
tag.Bck = bytesToTable ( bytes , 14 , 20 )
tag.MTC = bytesToTable ( bytes , 21 , 22 )
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
print ( acgreen .. " Tag-Type: " .. tag.Type .. acoff )
2016-02-28 21:50:49 +08:00
if ( tag.Type == " SAM " and # bytes > 23 ) then
tag = segmentsToTag ( bytes , tag )
2016-03-21 02:25:48 +08:00
print ( acgreen .. ( # tag.SEG + 1 ) .. " Segment(s) found " .. acoff )
2016-03-01 14:07:56 +08:00
-- unsegmented Master-Token
2017-05-18 00:52:30 +08:00
-- only tag-data
else
2016-03-01 14:07:56 +08:00
for i = 0 , # tag.Bck do
table.insert ( tag.data , tag.Bck [ i ] )
2016-03-21 02:25:48 +08:00
end
2016-03-01 14:07:56 +08:00
tag.data [ # tag.data ] = tag.MTC [ 0 ]
tag.Bck = nil
--tag.MTC[0]=tag.MTC[1]
--tag.MTC[1]=nil
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
print ( accyan .. # bytes .. " bytes for Tag processed " .. acoff )
2016-02-28 21:50:49 +08:00
return tag
2017-07-30 15:17:48 +08:00
2016-02-28 21:50:49 +08:00
end
2017-05-18 00:52:30 +08:00
---
-- put segments from byte-table to tag-table
2016-03-21 02:25:48 +08:00
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
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
2016-02-28 21:50:49 +08:00
---
2016-03-01 14:07:56 +08:00
-- read Tag-Table in bytes-table
function tagToBytes ( tag )
2017-08-13 21:06:30 +08:00
if istable ( tag ) == false then return oops ( " tag is no table in tagToBytes ( " .. type ( tag ) .. " ) " ) end
2017-07-30 15:17:48 +08:00
2016-03-01 14:07:56 +08:00
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 ] )
2016-03-21 02:25:48 +08:00
end
2016-03-01 14:07:56 +08:00
-- backup data
if ( istable ( tag.Bck ) ) then
for i = 0 , # tag.Bck do
table.insert ( bytes , tag.Bck [ i ] )
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
end
2016-03-01 14:07:56 +08:00
-- token-create-time / master-token crc
for i = 0 , # tag.MTC do
table.insert ( bytes , tag.MTC [ i ] )
2016-03-21 02:25:48 +08:00
end
2016-03-01 14:07:56 +08:00
-- 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 ] )
2016-03-21 02:25:48 +08:00
end
2016-03-01 14:07:56 +08:00
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 ] )
2016-03-21 02:25:48 +08:00
end
2016-02-28 21:50:49 +08:00
end
end
2016-03-01 14:07:56 +08:00
-- fill with zeros
for i =# bytes + 1 , 1024 do
table.insert ( bytes , i , ' 00 ' )
end
return bytes
end
2016-02-28 21:50:49 +08:00
2016-03-21 02:25:48 +08:00
--- PM3 I/O ---
2017-05-18 00:52:30 +08:00
---
2016-03-21 02:25:48 +08:00
-- read from pm3 into virtual-tag
function readFromPM3 ( )
2017-05-18 00:52:30 +08:00
local tag , bytes , infile
2016-03-21 02:25:48 +08:00
infile = " legic.temp "
core.console ( " hf legic reader " )
2017-05-18 00:52:30 +08:00
core.console ( " hf legic esave " .. infile )
tag = readFile ( infile .. " .bin " )
2016-03-21 02:25:48 +08:00
return tag
end
2016-02-28 21:50:49 +08:00
---
2016-03-21 02:25:48 +08:00
-- write virtual Tag to real Tag
function writeToTag ( tag )
local bytes
local filename = ' MylegicClone.hex '
local taglen = 22
if ( utils.confirm ( acred .. " \n place the (empty) Tag onto the PM3 \n and confirm writing to this Tag: " .. acoff ) == false ) then
return
end
-- get used bytes / tag-len
2017-05-18 00:52:30 +08:00
if ( istable ( tag.SEG ) ) then
2016-03-21 02:25:48 +08:00
if ( istable ( tag.Bck ) ) then
for i = 0 , # tag.SEG do
taglen = taglen + tag.SEG [ i ] . len + 5
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
end
local uid_old = tag.MCD .. tag.MSN0 .. tag.MSN1 .. tag.MSN2
-- read new tag into memory so we can xor the new data with the new MCC
outTAG = readFromPM3 ( )
outbytes = tagToBytes ( outTAG )
-- copy 'inputbuffer' to 'outputbuffer'
tag.MCD = outbytes [ 1 ]
tag.MSN0 = outbytes [ 2 ]
tag.MSN1 = outbytes [ 3 ]
tag.MSN2 = outbytes [ 4 ]
tag.MCC = outbytes [ 5 ]
-- recheck all segments-crc/kghcrc (only on a credential)
2017-05-18 00:52:30 +08:00
if ( istable ( tag.Bck ) ) then
2016-03-21 02:25:48 +08:00
checkAllSegCrc ( tag )
checkAllKghCrc ( tag )
local uid_new = tag.MCD .. tag.MSN0 .. tag.MSN1 .. tag.MSN2
for i = 0 , # tag.SEG do
if ( check43rdPartyCash1 ( uid_old , tag.SEG [ i ] . data ) ) then
io.write ( accyan .. " \n fixing known checksums " .. acoff .. " ... " )
if ( fix3rdPartyCash1 ( uid_new , tag.SEG [ i ] . data ) ) then
io.write ( acgreen .. " done \n " .. acoff )
else oops ( " \n something went wrong at the repair of the 3rd-party-cash-segment " ) end
2016-02-28 21:50:49 +08:00
end
end
2016-03-21 02:25:48 +08:00
end
bytes = tagToBytes ( tag )
-- master-token-crc
2017-08-13 21:06:30 +08:00
if ( tag.Type ~= " SAM " ) then bytes [ 22 ] = calcMtCrc ( bytes ) end
2017-05-18 00:52:30 +08:00
if ( bytes ) then
2016-03-21 02:25:48 +08:00
print ( " write temp-file ' " .. filename .. " ' " )
print ( accyan )
2017-05-18 00:52:30 +08:00
writeFile ( bytes , filename )
2016-03-21 02:25:48 +08:00
--writeToTag(bytes, taglen, 'MylegicClone.hex')
print ( acoff )
end
end
-- write data to file
if ( taglen > 0 ) then
WriteBytes = utils.input ( acyellow .. " enter number of bytes to write? " .. acoff , taglen )
-- load file into pm3-buffer
2017-08-13 21:06:30 +08:00
if ( type ( filename ) ~= " string " ) then filename = input ( acyellow .. " filename to load to pm3-buffer? " .. acoff , " legic.temp " ) end
2016-03-21 02:25:48 +08:00
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
2017-07-30 15:17:48 +08:00
cmd = ( ' hf legic write o 0x%02x d 0x01 ' ) : format ( i )
2016-03-21 02:25:48 +08:00
core.console ( cmd )
--print(cmd)
elseif ( i == 6 ) then
2017-05-18 00:52:30 +08:00
-- write DCF in reverse order (requires 'mosci-patch')
2017-07-30 15:17:48 +08:00
cmd = ' hf legic write o 0x05 d 0x02 '
2016-03-21 02:25:48 +08:00
print ( acgreen .. cmd .. acoff )
core.console ( cmd )
--print(cmd)
else
print ( acgreen .. " skip byte 0x05 - will be written next step " .. acoff )
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
utils.Sleep ( 0.2 )
end
end
end
--- File I/O ---
---
-- read file into virtual-tag
function readFile ( filename )
print ( accyan )
local bytes = { }
local tag = { }
2017-08-13 21:06:30 +08:00
if file_check ( filename ) == false then return oops ( " input file: " .. filename .. " not found " ) end
2017-07-30 15:17:48 +08:00
2016-03-21 02:25:48 +08:00
bytes = getInputBytes ( filename )
2017-07-30 15:17:48 +08:00
2017-08-13 21:06:30 +08:00
if bytes == false then return oops ( ' couldnt get input bytes ' ) end
-- make plain bytes
bytes = xorBytes ( bytes , bytes [ 5 ] )
print ( " create virtual tag from " .. # bytes .. " bytes " )
-- create Tag for plain bytes
tag = createTagTable ( )
-- load plain bytes to tag-table
print ( acoff )
tag = bytesToTag ( bytes , tag )
2017-07-30 15:17:48 +08:00
2016-03-21 02:25:48 +08:00
return tag
end
2017-05-18 00:52:30 +08:00
---
2016-03-21 02:25:48 +08:00
-- write bytes to file
function writeFile ( bytes , filename )
2017-08-13 21:06:30 +08:00
if ( filename ~= ' MylegicClone.hex ' ) then
if ( file_check ( filename ) ) then
local answer = confirm ( " \n the output-file " .. filename .. " alredy exists! \n this will delete the previous content! \n continue? " )
if ( answer == false ) then return print ( " user abort " ) end
end
end
local line
2016-03-21 02:25:48 +08:00
local bcnt = 0
local fho , err = io.open ( filename , " w " )
if err then oops ( " OOps ... faild to open output-file " .. filename ) end
2017-08-13 21:06:30 +08:00
bytes = xorBytes ( bytes , bytes [ 5 ] )
2016-03-21 02:25:48 +08:00
for i = 1 , # bytes do
2017-05-18 00:52:30 +08:00
if ( bcnt == 0 ) then
2017-08-13 21:06:30 +08:00
line = bytes [ i ]
2017-05-18 00:52:30 +08:00
elseif ( bcnt <= 7 ) then
2017-08-13 21:06:30 +08:00
line = line .. " " .. bytes [ i ]
2016-03-21 02:25:48 +08:00
end
if ( bcnt == 7 ) then
-- write line to new file
fho : write ( line .. " \n " )
-- reset counter & line
2017-08-13 21:06:30 +08:00
bcnt = - 1
line = " "
2016-03-21 02:25:48 +08:00
end
2017-08-13 21:06:30 +08:00
bcnt = bcnt + 1
2016-03-21 02:25:48 +08:00
end
fho : close ( )
print ( " \n wrote " .. # bytes .. " bytes to " .. filename )
return true
end
--- Map related ---
2017-05-18 00:52:30 +08:00
---
2016-03-21 02:25:48 +08:00
-- make tagMap
function makeTagMap ( )
local tagMap = { }
2017-08-13 21:06:30 +08:00
if ( # tagMap == 0 ) then
tagMap [ ' name ' ] = input ( accyan .. " enter Name for this Map: " .. acoff , " newTagMap " )
2016-03-21 02:25:48 +08:00
tagMap [ ' mappings ' ] = { }
tagMap [ ' crc8 ' ] = { }
-- insert fixed Tag-CRC
table.insert ( tagMap.crc8 , { name = ' TAG-CRC ' , pos = 5 , seq = { 1 , 4 } } )
tagMap [ ' crc16 ' ] = { }
end
print ( accyan .. " new tagMap created " .. acoff )
2017-05-18 00:52:30 +08:00
return tagMap
end
2016-03-21 02:25:48 +08:00
---
-- save mapping to file
function saveTagMap ( map , filename )
if ( string.len ( filename ) > 0 ) then
if ( file_check ( filename ) ) then
local answer = confirm ( " \n the output-file " .. filename .. " alredy exists! \n this will delete the previous content! \n continue? " )
if ( answer == false ) then return print ( " user abort " ) end
end
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
local line
local fho , err = io.open ( filename , " w " )
if err then oops ( " OOps ... faild to open output-file " .. filename ) end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- write line to new file
for k , v in pairs ( map ) do
if ( istable ( v ) ) then
for k2 , v2 in pairs ( v ) do
if ( k == ' mappings ' ) then
fho : write ( k .. " , " .. k2 .. " , " .. v2 [ ' name ' ] .. " , " .. v2 [ ' start ' ] .. " , " .. v2 [ ' end ' ] .. " , " .. ( ( v2 [ ' highlight ' ] ) and " 1 " or " 0 " ) .. " \n " )
elseif ( k == " crc8 " ) then
local tmp = " "
tmp = k .. " , " .. k2 .. " , " .. v2 [ ' name ' ] .. " , " .. v2 [ ' pos ' ] .. " , "
tmp = tmp .. tbl2seqstr ( v2 [ ' seq ' ] )
fho : write ( tmp .. " \n " )
end
end
else
fho : write ( k .. " , " .. v .. " \n " )
end
end
fho : close ( )
return true
end
---
-- toggle higligh
function toggleHighlight ( tbl )
2017-07-30 15:17:48 +08:00
if ( tbl [ ' highlight ' ] ) then
tbl [ ' highlight ' ] = false
else
tbl [ ' highlight ' ] = true
end
2016-03-21 02:25:48 +08:00
return tbl
end
---
-- return table od seqence-string
function seqstr2tbl ( seqstr )
local s = split ( seqstr )
local res = { }
if ( # s >= 1 ) then
for sk , sv in pairs ( s ) do
s2 = split ( sv , ' - ' )
if ( # s2 == 2 ) then
table.insert ( res , s2 [ 1 ] )
table.insert ( res , s2 [ 2 ] )
end
end
end
return res
end
---
-- return sequence-string from table
function tbl2seqstr ( seqtbl )
local res = " "
if ( istable ( seqtbl ) ) then
for sk , sv in pairs ( seqtbl ) do
res = res .. sv .. ( ( sk % 2 == 0 ) and " , " or " - " )
end
if ( string.sub ( res , string.len ( res ) ) == " , " ) then
res = string.sub ( res , 1 , string.len ( res ) - 1 )
end
end
return res
end
---
-- read map-file into map
function loadTagMap ( filename )
local map = { mappings = { } , crc8 = { } , crc16 = { } }
local m = 0
local c = 0
local line , fields
local temp = { }
local offset = 0
if ( file_check ( filename ) == false ) then
return oops ( " input file: " .. filename .. " not found " )
else
local fhi , err = io.open ( filename )
while true do
line = fhi : read ( )
2017-05-18 00:52:30 +08:00
if line == nil then
break
2016-03-21 02:25:48 +08:00
else
fields = split ( line )
end
2017-05-18 00:52:30 +08:00
if ( # fields == 2 ) then
2016-03-21 02:25:48 +08:00
if ( fields [ 1 ] == ' offset ' ) then
offset = tonumber ( fields [ 2 ] , 10 )
end
-- map-name
2017-05-18 00:52:30 +08:00
map [ fields [ 1 ] ] = fields [ 2 ]
2016-03-21 02:25:48 +08:00
elseif ( fields [ 1 ] == ' mappings ' ) then
m = m + 1
temp = { }
-- mapping
temp [ ' name ' ] = fields [ 3 ]
temp [ ' start ' ] = tonumber ( fields [ 4 ] , 10 )
temp [ ' end ' ] = tonumber ( fields [ 5 ] , 10 )
2017-05-18 00:52:30 +08:00
if ( temp [ ' start ' ] > 22 ) then
temp [ ' start ' ] = temp [ ' start ' ] + offset
temp [ ' end ' ] = temp [ ' end ' ] + offset
2016-03-21 02:25:48 +08:00
end
if ( tonumber ( fields [ 6 ] , 10 ) == 1 ) then temp [ ' highlight ' ] = true
else temp [ ' highlight ' ] = false end
table.insert ( map [ ' mappings ' ] , m , temp )
elseif ( fields [ 1 ] == ' crc8 ' ) then
c = c + 1
temp = { }
-- crc8
temp [ ' name ' ] = fields [ 3 ]
temp [ ' pos ' ] = tonumber ( fields [ 4 ] , 10 ) + offset
local s = string.sub ( line , string.len ( fields [ 1 ] .. " , " .. fields [ 2 ] .. " , " .. fields [ 3 ] .. " , " ) + 1 , string.len ( line ) )
temp [ ' seq ' ] = seqstr2tbl ( s )
for k , v in pairs ( temp [ ' seq ' ] ) do
if ( tonumber ( v , 10 ) > 22 ) then v = tonumber ( v , 10 ) + offset end
2017-05-18 00:52:30 +08:00
temp [ ' seq ' ] [ k ] = tonumber ( v , 10 )
end
2016-03-21 02:25:48 +08:00
table.insert ( map.crc8 , temp )
end
end
fhi : close ( )
end
return map
end
---
-- dump tagMap (mappings only)
function dumpTagMap ( tag , tagMap )
if ( # tagMap.mappings > 0 ) then
bytes = tagToBytes ( tag )
local temp
local lastend = 0
-- start display mappings
for k , v in pairs ( tagMap.mappings ) do
if ( ( lastend + 1 ) < v [ ' start ' ] ) then
print ( " ... " )
end
if ( isPosCrc8 ( tagMap , v [ ' start ' ] ) > 0 ) then
if ( checkMapCrc8 ( tagMap , bytes , isPosCrc8 ( tagMap , v [ ' start ' ] ) ) ) then
io.write ( " ( " .. ( " %04d " ) : format ( v [ ' start ' ] ) .. " - " .. ( " %04d " ) : format ( v [ ' end ' ] ) .. " ) " .. acgreen .. v [ ' name ' ] .. acoff .. " : " )
else
io.write ( " ( " .. ( " %04d " ) : format ( v [ ' start ' ] ) .. " - " .. ( " %04d " ) : format ( v [ ' end ' ] ) .. " ) " .. acred .. v [ ' name ' ] .. acoff .. " : " )
end
else
io.write ( " ( " .. ( " %04d " ) : format ( v [ ' start ' ] ) .. " - " .. ( " %04d " ) : format ( v [ ' end ' ] ) .. " ) " .. ( ( v [ ' highlight ' ] ) and acmagenta or acyellow ) .. v [ ' name ' ] .. acoff .. " : " )
end
temp = " "
for i = ( ( string.len ( v [ ' name ' ] ) ) / 10 ) , 2 do
temp = temp .. " \t "
end
for i = v [ ' start ' ] , v [ ' end ' ] do
temp = temp .. bytes [ i ] .. " "
end
print ( temp )
lastend = v [ ' end ' ]
end
end
end
---
--
function isPosCrc8 ( tagMap , pos )
local res = 0
if ( # tagMap.crc8 > 0 ) then
for k , v in pairs ( tagMap.crc8 ) do
if ( v [ ' pos ' ] == pos ) then res = k end
end
end
return res
end
---
-- check mapped crc
function checkMapCrc8 ( tagMap , bytes , n )
local res = false
if ( # tagMap.crc8 > 0 ) then
if ( istable ( tagMap.crc8 [ n ] ) ) then
2017-05-18 00:52:30 +08:00
temp = " "
2016-03-21 02:25:48 +08:00
for k2 , v2 in pairs ( tagMap.crc8 [ n ] ) do
if ( istable ( v2 ) ) then
temp = temp .. tbl2seqstr ( v2 )
end
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
local tempres = " "
local tempres = getSequences ( bytes , temp )
tempres = ( " %02x " ) : format ( utils.Crc8Legic ( tempres ) )
if ( bytes [ tagMap.crc8 [ n ] [ ' pos ' ] ] == tempres ) then
res = true
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
end
end
return res
end
---
-- edit existing Map
function editTagMap ( tag , tagMap )
local t = [ [
2017-05-18 00:52:30 +08:00
Data : dm = show dr = dump raw
2016-03-21 02:25:48 +08:00
Mappings : im = insert am = add rm = remove
2017-05-18 00:52:30 +08:00
CRC8 : ac8 = add sc8 = show rc8 = remove
2016-03-21 02:25:48 +08:00
: q = exit h = Help
] ]
--if(#tagMap.mappings==0) then oops("no mappings in tagMap"); return tagMap end
print ( " tagMap edit-mode submenu " )
2017-05-18 00:52:30 +08:00
repeat
2016-03-21 02:25:48 +08:00
x = input ( ' tagMap submenu: ' , ' h ' )
if ( x == ' h ' ) then print ( t )
elseif ( x == ' dm ' ) then tagMmap = dumpTagMap ( tag , tagMap )
elseif ( x == ' dr ' ) then tagMmap = dumpMap ( tag , tagMap )
2017-05-18 00:52:30 +08:00
elseif ( x == ' rc8 ' ) then
2016-03-21 02:25:48 +08:00
if ( istable ( tagMap.crc8 ) ) then
local x1 = selectTableEntry ( tagMap.crc8 , " select number of CRC8 to remove: " )
if ( istable ( tagMap.crc8 [ x1 ] ) ) then
table.remove ( tagMap.crc8 , x1 )
end
end
elseif ( x == ' ac8 ' ) then
local p = tonumber ( input ( " enter byte-addr of crc8 " , ' 0 ' ) , 10 )
if ( p > 0 ) then
local i1 = input ( " enter comma-seperated byte-sequences (e.g.: '1-4,23-26') " , ' 1-4,23-26 ' )
local s1 = split ( i1 , ' , ' )
if ( # s1 > 0 ) then
local temp = { seq = { } }
for k , v in pairs ( s1 ) do
v1 = split ( v , ' - ' )
if ( # v1 == 2 ) then
table.insert ( temp.seq , v1 [ 1 ] )
table.insert ( temp.seq , v1 [ 2 ] )
end
end
temp [ ' pos ' ] = p
temp [ ' name ' ] = input ( " enter a name for the CRC8 " , " CRC " .. ( # tagMap.crc8 + 1 ) )
table.insert ( tagMap.crc8 , temp )
end
end
2017-05-18 00:52:30 +08:00
elseif ( string.sub ( x , 1 , 3 ) == ' sc8 ' ) then
2016-03-21 02:25:48 +08:00
local bytes = tagToBytes ( tag )
local res , pos
-- trigger manually by sc8 <'4digit' checkadd> <'seqeuence-string'>
-- e.g.: sc8 0027 1-4,23-36
2017-05-18 00:52:30 +08:00
if ( string.len ( x ) >= 9 ) then
2016-03-21 02:25:48 +08:00
pos = tonumber ( string.sub ( x , 5 , 8 ) , 10 )
2017-05-18 00:52:30 +08:00
x = string.sub ( x , 9 , string.len ( x ) )
2016-03-21 02:25:48 +08:00
print ( " x: " .. x .. " - pos: " .. pos )
else
x = selectTableEntry ( tagMap.crc8 , " select CRC: " )
if ( istable ( tagMap.crc8 [ x ] ) ) then
pos = tagMap.crc8 [ x ] [ ' pos ' ]
x = tbl2seqstr ( tagMap.crc8 [ x ] [ ' seq ' ] )
end
end
if ( type ( x ) == ' string ' ) then
res = ( " %02x " ) : format ( utils.Crc8Legic ( getSequences ( bytes , x ) ) )
print ( accyan .. " Sequence: \t " .. acoff .. x )
print ( accyan .. " Bytes: \t \t " .. acoff .. getSequences ( bytes , x ) )
print ( accyan .. " calculated: " .. acoff .. res .. accyan .. " bytes[ " .. pos .. " ]: " .. acoff .. bytes [ pos ] .. " ( " .. compareCrc ( utils.Crc8Legic ( getSequences ( bytes , x ) ) , bytes [ pos ] ) .. " ) " )
end
elseif ( x == " tm " ) then
x = selectTableEntry ( tagMap.mappings , " select number of Mapping: " )
tagMap.mappings [ x ] = toggleHighlight ( tagMap.mappings [ x ] )
elseif ( x == ' am ' ) then tagMap = addMapping ( tag , tagMap )
elseif ( x == ' im ' ) then tagMap = addMapping ( tag , tagMap , selectTableEntry ( tagMap.mappings , " select List-Position for insert: " ) )
elseif ( x == ' rm ' ) then tagMap = deleteMapping ( tag , tagMap )
elseif ( x == ' mas ' ) then tagMap = mapTag ( tagMap ) ; tagMap = mapAllSegments ( tag , tagMap )
elseif ( type ( actions [ string.sub ( x , 3 ) ] ) == ' function ' ) then actions [ string.sub ( x , 3 ) ] ( )
end
until x == ' q '
print ( " exit sub-Menu " )
return tagMap
end
---
-- dump raw mapped and unmapped
function dumpMap ( tag , tagMap )
local dstart = 1
local dend , cnt
local bytes = tagToBytes ( tag )
local stats = getSegmentStats ( bytes )
dend = stats [ # stats ] [ ' end ' ]
print ( accyan .. " Tag uses " .. dend .. " bytes: " .. acoff )
for i = dstart , dend do
if ( check4MappedByte ( i , tagMap ) and not check4MapCrc8 ( i , tagMap ) and not check4Highlight ( i , tagMap ) ) then io.write ( " " .. acyellow )
2017-05-18 00:52:30 +08:00
elseif ( check4MapCrc8 ( i , tagMap ) ) then
2016-03-21 02:25:48 +08:00
if ( checkMapCrc8 ( tagMap , bytes , isPosCrc8 ( tagMap , i ) ) ) then
io.write ( " " .. acgreen )
2017-05-18 00:52:30 +08:00
else
2016-03-21 02:25:48 +08:00
io.write ( " " .. acred )
end
2017-05-18 00:52:30 +08:00
else
io.write ( " " .. acoff )
2016-03-21 02:25:48 +08:00
end
-- highlighted mapping
if ( check4Highlight ( i , tagMap ) ) then io.write ( " " .. acmagenta ) end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
io.write ( bytes [ i ] )
2017-05-18 00:52:30 +08:00
if ( i % 8 == 0 ) then io.write ( " \n " )
2016-03-21 02:25:48 +08:00
else io.write ( " " ) end
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
io.write ( " \n " .. acoff )
end
---
-- show bytes used for crc-calculation
function getSequences ( bytes , seqstr )
2017-08-13 21:06:30 +08:00
if ( type ( seqstr ) ~= " string " ) then seqstr = input ( " enter comma-seperated sequences (e.g.: '1-4,23-26') " , ' 1-4,23-26 ' ) end
local seqs = split ( seqstr , ' , ' )
2016-03-21 02:25:48 +08:00
local res = " "
if ( # seqs > 0 ) then
for k , v in pairs ( seqs ) do
local seq = split ( v , ' - ' )
2017-08-13 21:06:30 +08:00
if ( # seq >= 2 ) then
for i = seq [ 1 ] , seq [ 2 ] do
res = res .. bytes [ i ] .. " "
2016-03-21 02:25:48 +08:00
end
end
2017-08-13 21:06:30 +08:00
if ( string.len ( res ) > 0 ) then res = res .. " " end
2016-03-21 02:25:48 +08:00
end
else
oops ( " no sequence found in ' " .. seqstr .. " ' " )
end
return res
end
---
-- check if byte-addr is a know crc
function check4MapCrc8 ( addr , tagMap )
local res = false
for i = 1 , # tagMap.crc8 do
if ( addr == tagMap.crc8 [ i ] [ ' pos ' ] ) then
res = true
end
end
return res
end
---
-- check if byte-addr is a know crc
function check4MapCrc16 ( addr , tagMap )
local res = false
for i = 1 , # tagMap.crc16 do
if ( addr == tagMap.crc16 [ i ] [ ' pos ' ] ) then
res = true
end
end
return res
end
---
-- check if byte is mapped or not
function check4MappedByte ( addr , tagMap )
local res = false
for _ , v in pairs ( tagMap.mappings ) do
if ( addr >= v [ ' start ' ] and addr <= v [ ' end ' ] ) then
res = true
end
end
return res
end
---
-- check if byte is highlighted or not
function check4Highlight ( addr , tagMap )
local res = false
for _ , v in pairs ( tagMap.mappings ) do
if ( addr >= v [ ' start ' ] and addr <= v [ ' end ' ] ) then
res = v [ ' highlight ' ]
end
end
return res
end
---
-- add interactive mapping
function addMapping ( tag , tagMap , x )
2017-08-13 21:06:30 +08:00
if ( type ( x ) ~= " number " ) then x = # tagMap.mappings + 1 end
local bytes = tagToBytes ( tag )
2016-03-21 02:25:48 +08:00
local myMapping = { }
2017-08-13 21:06:30 +08:00
myMapping [ ' name ' ] = input ( accyan .. " enter Maping-Name: " .. acoff , string.format ( " mapping %d " , # tagMap.mappings + 1 ) )
myMapping [ ' start ' ] = tonumber ( input ( accyan .. " enter start-addr: " .. acoff , ' 1 ' ) , 10 )
myMapping [ ' end ' ] = tonumber ( input ( accyan .. " enter end-addr: " .. acoff , # bytes ) , 10 )
myMapping [ ' highlight ' ] = confirm ( " set highlighted " )
2017-05-18 00:52:30 +08:00
table.insert ( tagMap.mappings , x , myMapping )
2016-03-21 02:25:48 +08:00
return tagMap
end
---
-- delete mapping
function deleteMapping ( tag , tagMap )
if ( # tagMap.mappings > 0 ) then
local d = selectTableEntry ( tagMap.mappings , " select number of Mapping to remove: " )
if ( type ( d ) == ' number ' ) then
table.remove ( tagMap.mappings , d )
else oops ( " deleteMapping: got type = " .. type ( d ) .. " - expected type = 'number' " )
end
end
2017-05-18 00:52:30 +08:00
return tagMap
2016-03-21 02:25:48 +08:00
end
---
-- select a mapping from a tagmap
function selectTableEntry ( table , action )
2017-08-13 21:06:30 +08:00
if ( type ( action ) ~= " string " ) then action = " select number of item: " end
2016-03-21 02:25:48 +08:00
for k , v in pairs ( table ) do
print ( accyan .. k .. acoff .. " \t -> " .. accyan .. v [ ' name ' ] .. acoff )
end
local res = tonumber ( input ( action , 0 ) , 10 )
if ( istable ( table [ res ] ) ) then
return res
else
return false
end
end
---
-- map all segments
function mapAllSegments ( tag , tagMap )
local bytes = tagToBytes ( tag )
local WRP , WRC , WRPC
segs = getSegmentStats ( bytes )
if ( istable ( segs ) ) then
for k , v in pairs ( segs ) do
-- wrp (write proteted) = byte 2
WRP = tonumber ( bytes [ v [ ' start ' ] + 2 ] , 16 )
-- wrc (write control) - bit 4-6 of byte 3
WRC = tonumber ( bbit ( " 0x " .. bytes [ v [ ' start ' ] + 3 ] , 4 , 3 ) , 16 )
--tagMap=mapTokenData(tagMap, 'Segment '..("%02d"):format(v['index']).." HDR", v['start'], v['start']+3)
tagMap = mapTokenData ( tagMap , ' Segment ' .. ( " %02d " ) : format ( v [ ' index ' ] ) .. " CRC " , v [ ' start ' ] + 4 , v [ ' start ' ] + 4 , true )
table.insert ( tagMap.crc8 , { name = ' Segment ' .. ( " %02d " ) : format ( v [ ' index ' ] ) .. " CRC " , pos = v [ ' start ' ] + 4 , seq = { 1 , 4 , v [ ' start ' ] , v [ ' start ' ] + 3 } } )
2017-05-18 00:52:30 +08:00
if ( WRC > WRP ) then
2016-03-21 02:25:48 +08:00
WRPC = WRC
tagMap = mapTokenData ( tagMap , ' Segment ' .. ( " %02d " ) : format ( v [ ' index ' ] ) .. " WRC " , v [ ' start ' ] + 5 , v [ ' start ' ] + 5 + WRC - 1 , true )
elseif ( WRP > WRC and WRC > 0 ) then
WRPC = WRP
tagMap = mapTokenData ( tagMap , ' Segment ' .. ( " %02d " ) : format ( v [ ' index ' ] ) .. " WRC " , v [ ' start ' ] + 5 , v [ ' start ' ] + 5 + WRC - 1 , true )
tagMap = mapTokenData ( tagMap , ' Segment ' .. ( " %02d " ) : format ( v [ ' index ' ] ) .. " WRP " , v [ ' start ' ] + WRC + 5 , v [ ' start ' ] + 5 + WRP - 1 , true )
else
WRPC = WRP
tagMap = mapTokenData ( tagMap , ' Segment ' .. ( " %02d " ) : format ( v [ ' index ' ] ) .. " WRP " , v [ ' start ' ] + 5 , v [ ' start ' ] + 5 + WRP - 1 , true )
end
tagMap = mapTokenData ( tagMap , ' Segment ' .. ( " %02d " ) : format ( v [ ' index ' ] ) .. " data " , v [ ' start ' ] + 5 + WRPC , v [ ' end ' ] , false )
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
end
print ( # segs .. " Segments mapped " )
else
oops ( " autoMapSegments failed: no Segments found " )
end
return tagMap
end
2017-05-18 00:52:30 +08:00
---
2016-03-21 02:25:48 +08:00
-- map all token data
function mapTokenData ( tagMap , mname , mstart , mend , mhigh )
--if ( not mhigh ) then mhigh=false end
local myMapping = { }
myMapping [ ' name ' ] = mname
myMapping [ ' start ' ] = mstart
myMapping [ ' end ' ] = mend
myMapping [ ' highlight ' ] = mhigh
2017-05-18 00:52:30 +08:00
table.insert ( tagMap.mappings , myMapping )
2016-03-21 02:25:48 +08:00
return tagMap
end
---
-- map a map
function mapTag ( tagMap )
tagMap = makeTagMap ( )
tagMap = mapTokenData ( tagMap , ' Tag-ID ' , 1 , 4 , true )
tagMap = mapTokenData ( tagMap , ' Tag-CRC ' , 5 , 5 , false )
tagMap = mapTokenData ( tagMap , ' DCF ' , 6 , 7 , true )
tagMap = mapTokenData ( tagMap , ' THDR-Raw/Stamp-Len ' , 8 , 8 , true )
tagMap = mapTokenData ( tagMap , ' SSC ' , 9 , 9 , true )
tagMap = mapTokenData ( tagMap , ' Header ' , 10 , 13 , false )
tagMap = mapTokenData ( tagMap , ' Backup ' , 14 , 19 , true )
tagMap = mapTokenData ( tagMap , ' Bck-CRC ' , 20 , 20 , false )
tagMap = mapTokenData ( tagMap , ' TokenTime ' , 21 , 22 , false )
return tagMap
end
--- Dump Data ---
---
-- dump virtual Tag-Data
function dumpTag ( tag )
local i , i2
local res
local dp = 0
local raw = " "
-- sytstem area
res = acyellow .. " \n CDF: System Area " .. acoff
res = res .. " \n " .. dumpCDF ( tag )
-- segments (user-token area)
2016-06-22 15:33:21 +08:00
if ( tag.Type == " SAM " and tag.raw == ' 9f ' ) then
2016-03-21 02:25:48 +08:00
res = res .. acyellow .. " \n \n ADF: User Area " .. acoff
for i = 0 , # tag.SEG do
res = res .. " \n " .. dumpSegment ( tag , i ) .. " \n "
end
end
return res
end
---
-- dump tag-system area
function dumpCDF ( tag )
local res = " "
local i = 0
local raw = " "
local bytes
if ( istable ( tag ) ) then
res = res .. accyan .. " MCD: " .. acoff .. tag.MCD .. accyan .. " MSN: " .. acoff .. tag.MSN0 .. " " .. tag.MSN1 .. " " .. tag.MSN2 .. accyan .. " MCC: " .. acoff .. 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 .. ( ( tag.raw == ' 9f ' ) and ( " , SSC= " .. tag.SSC .. " \n " ) or " \n " )
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- credential (end-user tag)
2016-06-22 15:33:21 +08:00
if ( tag.Type == " SAM " and tag.raw == ' 9f ' ) then
2016-03-21 02:25:48 +08:00
res = res .. " Remaining Header Area \n "
for i = 0 , ( # tag.data ) do
res = res .. tag.data [ i ] .. " "
end
res = res .. " \n Backup Area \n "
for i = 0 , ( # tag.Bck ) do
res = res .. tag.Bck [ i ] .. " "
end
res = res .. " \n Time Area \n "
for i = 0 , ( # tag.MTC ) do
res = res .. tag.MTC [ i ] .. " "
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- Master Token specific
2016-06-22 15:33:21 +08:00
elseif ( tag.Type ~= " SAM " ) then
2016-03-21 02:25:48 +08:00
res = res .. " Master-Token Area \n Stamp: "
res = res .. tag.SSC .. " "
for i = 0 , tag.Stamp_len - 2 do
res = res .. tag.data [ i ] .. " "
end
res = res .. " \n unused payload \n "
for i = 0 , ( # tag.data - tag.Stamp_len - 1 ) do
res = res .. tag.data [ i ] .. " "
end
bytes = tagToBytes ( tag )
local mtcrc = calcMtCrc ( bytes )
res = res .. " \n Master-Token CRC: "
res = res .. tag.MTC [ 1 ] .. " ( " .. ( ( tag.MTC [ 1 ] == mtcrc ) and " valid " or " error " ) .. " ) "
2017-05-18 00:52:30 +08:00
2016-06-22 15:33:21 +08:00
-- 'Gantner User-Credential' specific
elseif ( tag.Type == " SAM " and ( tag.raw == ' 08 ' or tag.raw == ' 09 ' ) ) then
print ( acgreen .. " Gantner Detected " .. acoff )
2016-03-21 02:25:48 +08:00
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
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
2017-05-18 00:52:30 +08:00
if ( ( istable ( tag.SEG [ i ] ) ) and tag.Type == " SAM " and tag.raw == " 9f " ) then
2016-03-21 02:25:48 +08:00
if ( istable ( tag.SEG [ i ] . raw ) ) then
for k , v in pairs ( tag.SEG [ i ] . raw ) do
raw = raw .. v .. " "
end
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- segment header
res = res .. accyan .. " Segment " .. ( " %02d " ) : format ( tag.SEG [ i ] . index ) .. acoff .. " : "
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 acgreen .. " valid " or acred .. " error " ) .. acoff .. " ) "
raw = " "
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- WRC protected
if ( ( tag.SEG [ i ] . WRC > 0 ) ) then
res = res .. " \n WRC protected area: \n "
for i2 = dp , dp + tag.SEG [ i ] . WRC - 1 do
res = res .. tag.SEG [ i ] . data [ i2 ] .. " "
dp = dp + 1
end
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- WRP mprotected
if ( tag.SEG [ i ] . WRP > tag.SEG [ i ] . WRC ) then
res = res .. " \n Remaining write protected area: \n "
for i2 = dp , dp + ( tag.SEG [ i ] . WRP - tag.SEG [ i ] . WRC ) - 1 do
res = res .. tag.SEG [ i ] . data [ i2 ] .. " "
dp = dp + 1
end
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- payload
if ( # tag.SEG [ i ] . data - dp > 0 ) then
res = res .. " \n Remaining segment payload: \n "
for i2 = dp , # tag.SEG [ i ] . data - 2 do
res = res .. tag.SEG [ i ] . data [ dp ] .. " "
dp = dp + 1
end
2017-05-18 00:52:30 +08:00
if ( tag.SEG [ i ] . kgh ) then
2016-03-21 02:25:48 +08:00
res = res .. tag.SEG [ i ] . data [ dp ] .. " (KGH: " .. ( checkKghCrc ( tag , i ) and acgreen .. " valid " or acred .. " error " ) .. acoff .. " ) "
else res = res .. tag.SEG [ i ] . data [ dp ] end
end
dp = 0
2017-05-18 00:52:30 +08:00
return res
2016-03-21 02:25:48 +08:00
else
2017-05-18 00:52:30 +08:00
return print ( " Segment not found " )
2016-03-21 02:25:48 +08:00
end
end
---
-- return bytes 'sstrat' to 'send' from a table
function dumpTable ( tab , header , tstart , tend )
res = " "
for i = tstart , tend do
res = res .. tab [ i ] .. " "
end
2017-07-30 15:17:48 +08:00
if ( # header == 0 ) then
return res
else
return ( header .. " # " .. ( tend - tstart + 1 ) .. " \n " .. res )
end
2016-03-21 02:25:48 +08:00
end
---
-- dump 3rd Party Cash
function dump3rdPartyCash1 ( tag , seg )
local uid = tag.MCD .. tag.MSN0 .. tag.MSN1 .. tag.MSN2
local stamp = tag.SEG [ seg ] . data [ 0 ] .. " " .. tag.SEG [ seg ] . data [ 1 ] .. " " .. tag.SEG [ seg ] . data [ 2 ]
local datastamp = tag.SEG [ seg ] . data [ 20 ] .. " " .. tag.SEG [ seg ] . data [ 21 ] .. " " .. tag.SEG [ seg ] . data [ 22 ]
local balance = tonumber ( tag.SEG [ seg ] . data [ 32 ] .. tag.SEG [ seg ] . data [ 33 ] , 16 )
local balancecrc = utils.Crc8Legic ( uid .. tag.SEG [ seg ] . data [ 32 ] .. tag.SEG [ seg ] . data [ 33 ] )
local mirror = tonumber ( tag.SEG [ seg ] . data [ 35 ] .. tag.SEG [ seg ] . data [ 36 ] , 16 )
local mirrorcrc = utils.Crc8Legic ( uid .. tag.SEG [ seg ] . data [ 35 ] .. tag.SEG [ seg ] . data [ 36 ] )
local lastbal0 = tonumber ( tag.SEG [ seg ] . data [ 39 ] .. tag.SEG [ seg ] . data [ 40 ] , 16 )
local lastbal1 = tonumber ( tag.SEG [ seg ] . data [ 41 ] .. tag.SEG [ seg ] . data [ 42 ] , 16 )
local lastbal2 = tonumber ( tag.SEG [ seg ] . data [ 43 ] .. tag.SEG [ seg ] . data [ 44 ] , 16 )
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
test = " "
-- display decoded/known stuff
print ( " \n ------------------------------ " )
print ( " Tag-ID: \t \t " .. uid )
2017-05-18 00:52:30 +08:00
print ( " Stamp: \t \t " .. stamp )
2016-03-21 02:25:48 +08:00
print ( " UID-Mapping: \t \t " .. ( " %06d " ) : format ( tonumber ( tag.SEG [ seg ] . data [ 46 ] .. tag.SEG [ seg ] . data [ 47 ] .. tag.SEG [ seg ] . data [ 48 ] , 16 ) ) )
2017-05-18 00:52:30 +08:00
print ( " ------------------------------ " )
print ( " checksum 1: \t \t " .. tag.SEG [ seg ] . data [ 31 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ seg ] . data , " " , 19 , 30 ) ) , tag.SEG [ seg ] . data [ 31 ] ) .. " ) " )
2016-03-21 02:25:48 +08:00
print ( " checksum 2: \t \t " .. tag.SEG [ seg ] . data [ 34 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ seg ] . data , " " , 32 , 33 ) ) , tag.SEG [ seg ] . data [ 34 ] ) .. " ) " )
2017-05-18 00:52:30 +08:00
print ( " checksum 3: \t \t " .. tag.SEG [ seg ] . data [ 37 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ seg ] . data , " " , 35 , 36 ) ) , tag.SEG [ seg ] . data [ 37 ] ) .. " ) " )
2016-03-21 02:25:48 +08:00
print ( " checksum 4: \t \t " .. tag.SEG [ seg ] . data [ 55 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ seg ] . data , " " , 46 , 54 ) ) , tag.SEG [ seg ] . data [ 55 ] ) .. " ) " )
2017-05-18 00:52:30 +08:00
print ( " checksum 5: \t \t " .. tag.SEG [ seg ] . data [ 62 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ seg ] . data , " " , 56 , 61 ) ) , tag.SEG [ seg ] . data [ 62 ] ) .. " ) " )
2016-03-21 02:25:48 +08:00
print ( " checksum 6: \t \t " .. tag.SEG [ seg ] . data [ 73 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ seg ] . data , " " , 63 , 72 ) ) , tag.SEG [ seg ] . data [ 73 ] ) .. " ) " )
2017-05-18 00:52:30 +08:00
print ( " checksum 7: \t \t " .. tag.SEG [ seg ] . data [ 89 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ seg ] . data , " " , 74 , 88 ) ) , tag.SEG [ seg ] . data [ 89 ] ) .. " ) " )
print ( " ------------------------------ " )
2016-03-21 02:25:48 +08:00
print ( string.format ( " Balance: \t \t %3.2f " , balance / 100 ) .. " " .. " ( " .. compareCrc ( balancecrc , tag.SEG [ seg ] . data [ 34 ] ) .. " ) " )
2017-05-18 00:52:30 +08:00
print ( string.format ( " Shadow: \t \t \t %3.2f " , mirror / 100 ) .. " " .. " ( " .. compareCrc ( balancecrc , tag.SEG [ seg ] . data [ 37 ] ) .. " ) " )
print ( " ------------------------------ " )
print ( string.format ( " History 1: \t \t %3.2f " , lastbal0 / 100 ) )
print ( string.format ( " History 2: \t \t %3.2f " , lastbal1 / 100 ) )
print ( string.format ( " History 3: \t \t %3.2f " , lastbal2 / 100 ) )
print ( " ------------------------------ \n " )
2016-03-21 02:25:48 +08:00
end
---
-- dump Legic-Cash data
function dumpLegicCash ( tag , x )
2017-07-30 15:17:48 +08:00
2017-08-13 21:06:30 +08:00
if istable ( tag.SEG [ x ] ) == false then return end
2017-07-30 15:17:48 +08:00
2016-03-21 02:25:48 +08:00
io.write ( " in Segment " .. tag.SEG [ x ] . index .. " : \n " )
print ( " -------------------------------- \n \t Legic-Cash Values \n -------------------------------- " )
local limit , curr , balance , rid , tcv
-- currency of balance & limit
curr = currency [ tag.SEG [ x ] . data [ 8 ] .. tag.SEG [ x ] . data [ 9 ] ]
-- maximum balance
limit = string.format ( " %4.2f " , tonumber ( tag.SEG [ x ] . data [ 10 ] .. tag.SEG [ x ] . data [ 11 ] .. tag.SEG [ x ] . data [ 12 ] , 16 ) / 100 )
-- current balance
balance = string.format ( " %4.2f " , tonumber ( tag.SEG [ x ] . data [ 15 ] .. tag.SEG [ x ] . data [ 16 ] .. tag.SEG [ x ] . data [ 17 ] , 16 ) / 100 )
-- reader-id who wrote last transaction
rid = tonumber ( tag.SEG [ x ] . data [ 18 ] .. tag.SEG [ x ] . data [ 19 ] .. tag.SEG [ x ] . data [ 20 ] , 16 )
-- transaction counter value
tcv = tonumber ( tag.SEG [ x ] . data [ 29 ] , 16 )
print ( " Currency: \t \t " .. curr )
print ( " Limit: \t \t \t " .. limit )
print ( " Balance: \t \t " .. balance )
print ( " Transaction Counter: \t " .. tcv )
print ( " Reader-ID: \t \t " .. rid .. " \n -------------------------------- \n " )
end
---
-- raw 3rd-party
function print3rdPartyCash1 ( tag , x )
2017-07-30 15:17:48 +08:00
2017-08-13 21:06:30 +08:00
if istable ( tag.SEG [ x ] ) == false then return end
2017-07-30 15:17:48 +08:00
2016-03-21 02:25:48 +08:00
local uid = tag.MCD .. tag.MSN0 .. tag.MSN1 .. tag.MSN2
print ( " \n \t \t Stamp : " .. dumpTable ( tag.SEG [ x ] . data , " " , 0 , 2 ) )
print ( " \t \t Block 0: " .. dumpTable ( tag.SEG [ x ] . data , " " , 3 , 18 ) )
print ( )
print ( " \t \t Block 1: " .. dumpTable ( tag.SEG [ x ] . data , " " , 19 , 30 ) )
print ( " checksum 1: Tag-ID .. Block 1 => LegicCrc8 = " .. tag.SEG [ x ] . data [ 31 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ x ] . data , " " , 19 , 30 ) ) , tag.SEG [ x ] . data [ 31 ] ) .. " ) " )
print ( )
print ( " \t \t Block 2: " .. dumpTable ( tag.SEG [ x ] . data , " " , 32 , 33 ) )
print ( " checksum 2: Block 2 => LegicCrc8 = " .. tag.SEG [ x ] . data [ 34 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ x ] . data , " " , 32 , 33 ) ) , tag.SEG [ x ] . data [ 34 ] ) .. " ) " )
print ( )
print ( " \t \t Block 3: " .. dumpTable ( tag.SEG [ x ] . data , " " , 35 , 36 ) )
print ( " checksum 3: Block 3 => LegicCrc8 = " .. tag.SEG [ x ] . data [ 37 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ x ] . data , " " , 35 , 36 ) ) , tag.SEG [ x ] . data [ 37 ] ) .. " ) " )
print ( )
print ( " \t \t yet unknown: " .. tag.SEG [ x ] . data [ 38 ] )
print ( )
2017-05-18 00:52:30 +08:00
print ( " \t \t Hisatory 1: " .. dumpTable ( tag.SEG [ x ] . data , " " , 39 , 40 ) )
print ( " \t \t Hisatory 2: " .. dumpTable ( tag.SEG [ x ] . data , " " , 41 , 42 ) )
print ( " \t \t Hisatory 3: " .. dumpTable ( tag.SEG [ x ] . data , " " , 43 , 44 ) )
2016-03-21 02:25:48 +08:00
print ( )
2017-05-18 00:52:30 +08:00
print ( " \t \t yet unknown: " .. tag.SEG [ x ] . data [ 45 ] )
2016-03-21 02:25:48 +08:00
print ( )
print ( " \t \t KGH-UID HEX: " .. dumpTable ( tag.SEG [ x ] . data , " " , 46 , 48 ) )
print ( " \t \t Block 4: " .. dumpTable ( tag.SEG [ x ] . data , " " , 49 , 54 ) )
print ( " checksum 4: Tag-ID .. KGH-UID .. Block 4 => LegicCrc8 = " .. tag.SEG [ x ] . data [ 55 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ x ] . data , " " , 46 , 54 ) ) , tag.SEG [ x ] . data [ 55 ] ) .. " ) " )
print ( )
print ( " \t \t Block 5: " .. dumpTable ( tag.SEG [ x ] . data , " " , 56 , 61 ) )
print ( " checksum 5: Tag-ID .. Block 5 => LegicCrc8 = " .. tag.SEG [ x ] . data [ 62 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ x ] . data , " " , 56 , 61 ) ) , tag.SEG [ x ] . data [ 62 ] ) .. " ) " )
print ( )
print ( " \t \t Block 6: " .. dumpTable ( tag.SEG [ x ] . data , " " , 63 , 72 ) )
print ( " checksum 6: Tag-ID .. Block 6 => LegicCrc8 = " .. tag.SEG [ x ] . data [ 73 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ x ] . data , " " , 63 , 72 ) ) , tag.SEG [ x ] . data [ 73 ] ) .. " ) " )
print ( )
print ( " \t \t Block 7: " .. dumpTable ( tag.SEG [ x ] . data , " " , 74 , 88 ) )
print ( " checksum 7: Tag-ID .. Block 7 => LegicCrc8 = " .. tag.SEG [ x ] . data [ 89 ] .. " ( " .. compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( tag.SEG [ x ] . data , " " , 74 , 88 ) ) , tag.SEG [ x ] . data [ 89 ] ) .. " ) " )
print ( )
print ( " \t \t Block 8: " .. dumpTable ( tag.SEG [ x ] . data , " " , 90 , 94 ) )
end
--- Token related --
---
-- make token
function makeToken ( )
local mt = {
[ ' Type ' ] = { " SAM " , " SAM63 " , " SAM64 " , " IAM " , " GAM " } ,
[ ' DCF ' ] = { " 60ea " , " 31fa " , " 30fa " , " 80fa " , " f0fa " } ,
[ ' WRP ' ] = { " 15 " , " 2 " , " 2 " , " 2 " , " 2 " } ,
[ ' WRC ' ] = { " 01 " , " 02 " , " 02 " , " 00 " , " 00 " } ,
[ ' RD ' ] = { " 01 " , " 00 " , " 00 " , " 00 " , " 00 " } ,
[ ' Stamp ' ] = { " 00 " , " 00 " , " 00 " , " 00 " , " 00 " } ,
[ ' Segment ' ] = { " 0d " , " c0 " , " 04 " , " 00 " , " be " , " 01 " , " 02 " , " 03 " , " 04 " , " 01 " , " 02 " , " 03 " , " 04 " }
}
ttype = " "
for k , v in pairs ( mt.Type ) do
2017-08-13 21:06:30 +08:00
ttype = ttype .. k .. " ) " .. v .. " "
2016-03-21 02:25:48 +08:00
end
2017-08-13 21:06:30 +08:00
mtq = tonumber ( input ( " select number for Token-Type \n " .. ttype , ' 1 ' ) , 10 )
if ( type ( mtq ) ~= " number " ) then return print ( " selection invalid! " )
elseif ( mtq > # mt.Type ) then return print ( " selection invalid! " )
2016-03-21 02:25:48 +08:00
else print ( " Token-Type ' " .. mt.Type [ mtq ] .. " ' selected " ) end
2017-08-13 21:06:30 +08:00
local raw = calcHeaderRaw ( mt.WRP [ mtq ] , mt.WRC [ mtq ] , mt.RD [ mtq ] )
local mtCRC = " 00 "
2017-05-18 00:52:30 +08:00
2017-08-13 21:06:30 +08:00
bytes = { " 01 " , " 02 " , " 03 " , " 04 " , " cb " , string.sub ( mt.DCF [ mtq ] , 0 , 2 ) , string.sub ( mt.DCF [ mtq ] , 3 ) , raw ,
2016-03-21 02:25:48 +08:00
" 00 " , " 00 " , " 00 " , " 00 " , " 00 " , " 00 " , " 00 " , " 00 " ,
" 00 " , " 00 " , " 00 " , " 00 " , " 00 " , " 00 " }
2017-08-13 21:06:30 +08:00
if ( mtq == 1 ) then
for i = 0 , # mt.Segment do
2016-03-21 02:25:48 +08:00
table.insert ( bytes , mt.Segment [ i ] )
end
2017-08-13 21:06:30 +08:00
bytes [ 9 ] = " ff "
2016-03-21 02:25:48 +08:00
end
-- fill bytes
2017-08-13 21:06:30 +08:00
for i = # bytes , 1023 do table.insert ( bytes , " 00 " ) end
2016-03-21 02:25:48 +08:00
-- if Master-Token -> calc Master-Token-CRC
2017-08-13 21:06:30 +08:00
if ( mtq > 1 ) then bytes [ 22 ] = calcMtCrc ( bytes ) end
local tempTag = createTagTable ( )
2016-03-21 02:25:48 +08:00
-- remove segment if MasterToken
2017-08-13 21:06:30 +08:00
if ( mtq > 1 ) then tempTag.SEG [ 0 ] = nil end
2016-03-21 02:25:48 +08:00
return bytesToTag ( bytes , tempTag )
end
2017-05-18 00:52:30 +08:00
---
2016-03-21 02:25:48 +08:00
-- edit token-data
function editTag ( tag )
-- for simulation it makes sense to edit everything
2017-08-13 21:06:30 +08:00
local edit_sim = " MCD MSN0 MSN1 MSN2 MCC DCFl DCFh WRP WRC RD "
2016-03-21 02:25:48 +08:00
-- on real tags it makes only sense to edit DCF, WRP, WRC, RD
2017-08-13 21:06:30 +08:00
local edit_real = " DCFl DCFh WRP WRC RD "
2016-03-21 02:25:48 +08:00
if ( confirm ( acyellow .. " do you want to edit non-writeable values (e.g. for simulation)? " .. acoff ) ) then
2017-08-13 21:06:30 +08:00
edit_tag = edit_sim
else edit_tag = edit_real end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
if ( istable ( tag ) ) then
for k , v in pairs ( tag ) do
2017-08-13 21:06:30 +08:00
if ( type ( v ) ~= " table " and type ( v ) ~= " boolean " and string.find ( edit_tag , k ) ) then
tag [ k ] = input ( " value for: " .. accyan .. k .. acoff , v )
2016-03-21 02:25:48 +08:00
end
end
2017-05-18 00:52:30 +08:00
2017-08-13 21:06:30 +08:00
if ( tag.Type == " SAM " ) then ttype = " Header " ; else ttype = " Stamp " ; end
2016-03-21 02:25:48 +08:00
if ( confirm ( acyellow .. " do you want to edit " .. ttype .. " Data? " .. acoff ) ) then
-- master-token specific
2017-08-13 21:06:30 +08:00
if ( istable ( tag.Bck ) == false ) then
2016-03-21 02:25:48 +08:00
-- stamp-data length=(0xfc-DCFh)
-- on MT: SSC holds the Starting Stamp Character (Stamp0)
tag.SSC = input ( ttype .. " 0: " , tag.SSC )
-- rest of stamp-bytes are in tag.data 0..n
for i = 0 , ( tonumber ( 0xfc , 10 ) - ( " %d " ) : format ( ' 0x ' .. tag.DCFh ) ) - 2 do
2017-08-13 21:06:30 +08:00
tag.data [ i ] = input ( ttype .. i + 1 .. " : " , tag.data [ i ] )
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
else
2017-05-18 00:52:30 +08:00
--- on credentials byte7 should always be 9f and byte8 ff
2016-03-21 02:25:48 +08:00
-- on Master-Token not (even on SAM63/64 not)
-- tag.SSC=input(ttype.."0: ", tag.SSC)
2016-03-01 14:07:56 +08:00
for i = 0 , # tag.data do
2017-08-13 21:06:30 +08:00
tag.data [ i ] = input ( ttype .. i .. " : " , tag.data [ i ] )
2016-03-21 02:25:48 +08:00
end
end
end
2017-05-18 00:52:30 +08:00
2017-08-13 21:06:30 +08:00
bytes = tagToBytes ( tag )
2017-05-18 00:52:30 +08:00
2016-03-01 14:07:56 +08:00
--- check data-consistency (calculate tag.raw)
2017-08-13 21:06:30 +08:00
bytes [ 8 ] = calcHeaderRaw ( tag.WRP , tag.WRC , tag.RD )
2017-05-18 00:52:30 +08:00
2016-03-01 14:07:56 +08:00
--- Master-Token specific
-- should be triggered if a SAM was converted to a non-SAM (user-Token to Master-Token)
-- or a Master-Token has being edited (also SAM64 & SAM63 - which are in fact Master-Token)
2017-08-13 21:06:30 +08:00
if ( tag.Type ~= " SAM " or bytes [ 6 ] .. bytes [ 7 ] ~= " 60ea " ) then
2016-03-01 14:07:56 +08:00
-- calc new Master-Token crc
2017-08-13 21:06:30 +08:00
bytes [ 22 ] = calcMtCrc ( bytes )
2016-03-01 14:07:56 +08:00
else
-- ensure tag.SSC set to 'ff' on credential-token (SAM)
2017-08-13 21:06:30 +08:00
bytes [ 9 ] = ' ff '
2016-03-01 14:07:56 +08:00
-- if a Master-Token was converted to a Credential-Token
-- lets unset the Time-Area to 00 00 (will contain Stamp-Data on MT)
2017-08-13 21:06:30 +08:00
bytes [ 21 ] = ' 00 '
bytes [ 22 ] = ' 00 '
2016-03-21 02:25:48 +08:00
end
2017-05-18 00:52:30 +08:00
2017-08-13 21:06:30 +08:00
tag = bytesToTag ( bytes , tag )
2016-02-28 21:50:49 +08:00
end
end
---
2016-03-01 14:07:56 +08:00
-- calculates header-byte (addr 0x07)
function calcHeaderRaw ( wrp , wrc , rd )
2017-08-13 21:06:30 +08:00
wrp = ( " %02x " ) : format ( tonumber ( wrp , 10 ) )
rd = tonumber ( rd , 16 )
local res = ( " %02x " ) : format ( tonumber ( wrp , 16 ) + tonumber ( wrc .. " 0 " , 16 ) + ( ( rd > 0 ) and tonumber ( " 8 " .. ( rd - 1 ) , 16 ) or 0 ) )
2016-03-01 14:07:56 +08:00
return res
2016-02-28 21:50:49 +08:00
end
2017-05-18 00:52:30 +08:00
---
2016-03-21 02:25:48 +08:00
-- determine TagType (bits 0..6 of DCFlow)
function getTokenType ( DCFl )
--[[
2017-05-18 00:52:30 +08:00
0x00 – 0x2f IAM
0x30 – 0x6f SAM
2016-03-21 02:25:48 +08:00
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
2016-02-28 21:50:49 +08:00
---
2016-03-21 02:25:48 +08:00
-- clear beackup-area of a virtual tag
function clearBackupArea ( tag )
for i = 1 , # tag.Bck do
tag.Bck [ i ] = ' 00 '
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
return tag
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
--- Segment related --
2016-02-28 21:50:49 +08:00
---
-- 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
}
2017-05-18 00:52:30 +08:00
if ( bytes [ start ] ) then
local i
2016-02-28 21:50:49 +08:00
-- #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
2017-05-18 00:52:30 +08:00
else return false ;
2016-02-28 21:50:49 +08:00
end
end
2016-03-21 02:25:48 +08:00
---
2017-05-18 00:52:30 +08:00
-- get index, start-aadr, length and content
2016-03-21 02:25:48 +08:00
function getSegmentStats ( bytes )
local sStats = { }
local sValid , sLast , sLen , sStart , x
sStart = 23
x = 0
repeat
local s = { }
-- valid = bit 6 of byte 1
sValid = bbit ( " 0x " .. bytes [ sStart + 1 ] , 6 , 1 )
-- last = bit 7 of byte 1
sLast = bbit ( " 0x " .. bytes [ sStart + 1 ] , 7 , 1 )
-- len = (byte 0)+(bit0-3 of byte 1)
sLen = tonumber ( bbit ( " 0x " .. bytes [ sStart + 1 ] , 0 , 4 ) .. bytes [ sStart ] , 16 )
--print("index: "..("%02d"):format(x).." Len: "..sLen.." start:"..sStart.." end: "..(sStart+sLen-1))
s [ ' index ' ] = x
s [ ' start ' ] = sStart
s [ ' end ' ] = sStart + sLen - 1
s [ ' len ' ] = sLen
if ( ( sStart + sLen - 1 ) > sStart ) then
table.insert ( sStats , s )
end
sStart = sStart + sLen
x = x + 1
until ( sLast == 1 or sValid == 0 or x == 126 )
if ( # sStats > 0 ) then return sStats
else return false ; end
end
2016-02-28 21:50:49 +08:00
---
2016-03-01 14:07:56 +08:00
-- regenerate segment-header (after edit)
function regenSegmentHeader ( segment )
local seg = segment
local raw = segment.raw
2016-03-21 02:25:48 +08:00
local i
2016-03-01 14:07:56 +08:00
-- 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?
2016-03-21 02:25:48 +08:00
raw [ 2 ] = ( " %02x " ) : format ( bbit ( " 0x " .. ( " %03x " ) : format ( seg.len ) , 8 , 4 ) + bbit ( " 0x " .. ( " %02x " ) : format ( ( seg.valid * 64 ) + ( seg.last * 128 ) ) , 0 , 8 ) )
2016-03-01 14:07:56 +08:00
-- WRP
raw [ 3 ] = ( " %02x " ) : format ( bbit ( " 0x " .. ( " %02x " ) : format ( seg.WRP ) , 0 , 8 ) )
-- WRC + RD
2016-03-21 02:25:48 +08:00
raw [ 4 ] = ( " %02x " ) : format ( tonumber ( ( seg.WRC * 16 ) + ( seg.RD * 128 ) , 10 ) )
2016-03-01 14:07:56 +08:00
-- 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 )
2016-03-21 02:25:48 +08:00
print ( acyellow .. " Data-Length has being reduced: " .. acgreen .. " auto-removing " .. acyellow .. # seg.data - ( seg.len - 5 ) .. acgreen .. " bytes from Payload! " .. acoff ) ;
2016-03-01 14:07:56 +08:00
for i = ( seg.len - 5 ) , # seg.data - 1 do
table.remove ( seg.data )
2016-03-21 02:25:48 +08:00
end
2016-03-01 14:07:56 +08:00
elseif ( # seg.data < ( seg.len - 5 ) ) then
print ( " current payload: " .. # seg.data .. " - desired payload: " .. seg.len - 5 )
2016-03-21 02:25:48 +08:00
print ( acyellow .. " Data-Length has being extended: " .. acgreen .. " auto-adding " .. acyellow .. ( seg.len - 5 ) -# seg.data .. acgreen .. " bytes to Payload! " .. acoff ) ;
for i =# seg.data , ( seg.len - 5 - 1 ) do
2016-03-01 14:07:56 +08:00
table.insert ( seg.data , ' 00 ' )
end
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
return seg
2016-02-28 21:50:49 +08:00
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
2016-03-21 02:25:48 +08:00
tag.SEG [ index ] [ k ] = tonumber ( input ( accyan .. k .. acoff .. " : " , v ) , 10 )
2016-02-28 21:50:49 +08:00
end
end
else print ( " Segment with Index: " .. ( " %02d " ) : format ( index ) .. " not found in Tag " )
return false
end
2017-05-18 00:52:30 +08:00
regenSegmentHeader ( tag.SEG [ index ] )
2016-02-28 21:50:49 +08:00
print ( " \n " .. dumpSegment ( tag , index ) .. " \n " )
return tag
end
---
-- edit Segment Data
function editSegmentData ( data )
2017-08-13 21:06:30 +08:00
io.write ( " \n " )
if istable ( data ) == false then print ( " no Segment-Data found " ) end
2017-07-30 15:17:48 +08:00
local lc = check4LegicCash ( data )
2016-02-28 21:50:49 +08:00
for i = 0 , # data - 1 do
2017-08-13 21:06:30 +08:00
data [ i ] = input ( accyan .. " Data " .. i .. acoff .. " : " , data [ i ] )
2017-05-18 00:52:30 +08:00
end
2017-07-30 15:17:48 +08:00
if ( lc ) then
data = fixLegicCash ( data )
2017-08-13 21:06:30 +08:00
end
2017-07-30 15:17:48 +08:00
return data
2016-02-28 21:50:49 +08:00
end
---
-- list available segmets in virtual tag
function segmentList ( tag )
local i
2017-05-18 00:52:30 +08:00
local res = " "
2016-02-28 21:50:49 +08:00
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
2017-05-18 00:52:30 +08:00
if ( istable ( tag.SEG [ 0 ] ) ) then
2016-02-28 21:50:49 +08:00
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 ( " \n no Segments found " )
return false
end
end
2017-05-18 00:52:30 +08:00
2016-02-28 21:50:49 +08:00
---
-- 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
---
2016-03-21 02:25:48 +08:00
-- get only the stamp-bytes of a segment
function getSegmentStamp ( seg , bytes )
local stamp = " "
local stamp_len = 7
--- the 'real' stamp on MIM is not really easy to tell for me since the 'data-block' covers stamp0..stampn+data0..datan
2017-05-18 00:52:30 +08:00
-- there a no stamps longer than 7 bytes & they are write-protected by default , and I have not seen user-credntials
2016-03-21 02:25:48 +08:00
-- with stamps smaller 3 bytes (except: Master-Token)
2017-05-18 00:52:30 +08:00
-- WRP -> Read/Write Protection
2016-03-21 02:25:48 +08:00
-- WRC -> Read/Write Condition
-- RD depends on WRC - if WRC > 0 and RD=1: only reader with matching #WRC of Stamp-bytes in thier Database have Read-Access to the Tag
if ( seg.WRP < 7 ) then stamp_len = ( seg.WRP ) end
for i = 1 , ( stamp_len ) do
stamp = stamp .. seg.data [ i - 1 ]
2016-03-06 20:26:13 +08:00
end
2017-05-18 00:52:30 +08:00
if ( bytes ) then
2016-03-21 02:25:48 +08:00
stamp = str2bytes ( stamp )
return stamp
else return stamp end
2016-03-06 20:26:13 +08:00
end
---
2016-03-21 02:25:48 +08:00
-- edit stamp of a segment
function editStamp ( new_stamp , uid , data )
local stamp = str2bytes ( new_stamp )
for i = 0 , # stamp - 1 do
data [ i ] = stamp [ i + 1 ]
end
-- now fill in stamp
for i = 0 , ( string.len ( new_stamp ) / 2 ) - 1 do
data [ i ] = stamp [ i + 1 ]
end
return fix3rdPartyCash1 ( uid , data )
2016-03-06 20:26:13 +08:00
end
---
2016-03-21 02:25:48 +08:00
-- autoselect special/known segments
function autoSelectSegment ( tag , s )
local uid = tag.MCD .. tag.MSN0 .. tag.MSN1 .. tag.MSN2
local x =# tag.SEG + 1
local res = false
io.write ( " autoSelect " )
--- search for desired segment-type
-- 3rd Party Segment
if ( s == " 3rdparty " ) then
2017-05-18 00:52:30 +08:00
repeat
2016-03-21 02:25:48 +08:00
io.write ( " . " )
x = x - 1
res = check43rdPartyCash1 ( uid , tag.SEG [ x ] . data )
until ( res or x == 0 )
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
-- Legic-Cash Segment
if ( s == " legiccash " ) then
2017-05-18 00:52:30 +08:00
repeat
2016-03-21 02:25:48 +08:00
io.write ( " . " )
x = x - 1
res = check4LegicCash ( tag.SEG [ x ] . data )
until ( res or x == 0 )
end
---
-- segment found
if ( res ) then
io.write ( " \n autoselected Index: " .. string.format ( " %02d " , x ) .. " \n " )
return x
end
---
2017-05-18 00:52:30 +08:00
-- nothing found
io.write ( acyellow .. " no Segment found \n " .. acoff )
return - 1
2016-03-06 20:26:13 +08:00
end
---
2016-03-21 02:25:48 +08:00
-- delete segment (except segment 00)
function delSegment ( tag , index )
if ( istable ( tag.SEG [ 0 ] ) ) then
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
2016-03-06 20:26:13 +08:00
end
end
---
-- edit uid 3rd party cash
function edit3rdUid ( mapid , uid , data )
mapid = ( " %06x " ) : format ( tonumber ( mapid , 10 ) )
2016-03-21 02:25:48 +08:00
data [ 46 ] = string.sub ( mapid , 1 , 2 )
2016-03-06 20:26:13 +08:00
data [ 47 ] = string.sub ( mapid , 3 , 4 )
data [ 48 ] = string.sub ( mapid , 5 , 6 )
return fix3rdPartyCash1 ( uid , data )
end
---
-- edit balance 3rd party cash
function edit3rdCash ( new_cash , uid , data )
new_cash = ( " %04x " ) : format ( new_cash )
data [ 32 ] = string.sub ( new_cash , 0 , 2 )
data [ 33 ] = string.sub ( new_cash , 3 , 4 )
data [ 34 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. new_cash ) )
data [ 35 ] = string.sub ( new_cash , 0 , 2 )
data [ 36 ] = string.sub ( new_cash , 3 , 4 )
data [ 37 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. new_cash ) )
data [ 39 ] = string.sub ( new_cash , 0 , 2 )
data [ 40 ] = string.sub ( new_cash , 3 , 4 )
data [ 41 ] = ' 00 '
data [ 42 ] = ' 00 '
data [ 43 ] = ' 00 '
data [ 44 ] = ' 00 '
return fix3rdPartyCash1 ( uid , data )
end
---
2016-03-21 02:25:48 +08:00
-- edit 3rd-party cash
function edit3rdPartyCash1 ( tag , x )
local uid = tag.MCD .. tag.MSN0 .. tag.MSN1 .. tag.MSN2
if ( confirm ( " \n edit Balance? " ) ) then
local new_cash = input ( " enter new Balance≤ \n without comma and without currency-sign! (0-65535) " , " 100 " )
tag.SEG [ x ] . data = edit3rdCash ( new_cash , uid , tag.SEG [ x ] . data )
end
-- change User-ID (used for online-account-mapping)
if ( confirm ( " \n edit UserID-Mapping? " ) ) then
local new_mapid = input ( " enter new UserID (6-digit value) " , " 012345 " )
tag.SEG [ x ] . data = edit3rdUid ( new_mapid , uid , tag.SEG [ x ] . data )
2016-03-06 20:26:13 +08:00
end
2016-03-21 02:25:48 +08:00
if ( confirm ( " \n edit Stamp? " ) ) then
local new_stamp = input ( " enter new Stamp " , getSegmentStamp ( tag.SEG [ x ] ) )
tag.SEG [ x ] . data = editStamp ( new_stamp , uid , tag.SEG [ x ] . data )
new_stamp = getSegmentStamp ( tag.SEG [ x ] , ' true ' )
print ( " stamp_bytes: " .. # new_stamp )
-- replace stamp in 'block 1' also
io.write ( " editing stamp in Block 1 also " )
for i = 20 , ( 20 +# new_stamp - 1 ) do
tag.SEG [ x ] . data [ i ] = new_stamp [ i - 19 ]
io.write ( " . " ) ;
end
print ( " done " )
-- fix known checksums
tag.SEG [ x ] . data = fix3rdPartyCash1 ( uid , tag.SEG [ x ] . data )
2017-05-18 00:52:30 +08:00
end
return tag
2016-03-06 20:26:13 +08:00
end
---
2016-03-21 02:25:48 +08:00
-- edit Legic Cash
function editLegicCash ( data )
local limit , curr , balance , rid , tcv
-- currency of balance & limit
curr = currency [ data [ 8 ] .. data [ 9 ] ]
-- maximum balance
limit = string.format ( " %4.2f " , tonumber ( data [ 10 ] .. data [ 11 ] .. data [ 12 ] , 16 ) / 100 )
-- current balance
balance = string.format ( " %4.2f " , tonumber ( data [ 15 ] .. data [ 16 ] .. data [ 17 ] , 16 ) / 100 )
-- reader-id who wrote last transaction
rid = tonumber ( data [ 18 ] .. data [ 19 ] .. data [ 20 ] , 16 )
-- transaction counter value
tcv = tonumber ( data [ 29 ] , 16 )
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- edit currency
if ( confirm ( accyan .. " change Currency? " .. acoff ) ) then
for k , v in pairs ( currency ) do io.write ( k .. " = " .. v .. " \n " ) end
curr = input ( accyan .. " enter the 4-digit Hex for the new Currency: " .. acoff , data [ 8 ] .. data [ 9 ] )
data [ 8 ] = string.sub ( curr , 1 , 2 )
data [ 9 ] = string.sub ( curr , 3 , 4 )
2016-03-06 20:26:13 +08:00
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- edit limit
if ( confirm ( accyan .. " change Limit? " .. acoff ) ) then
limit = string.format ( " %06x " , input ( accyan .. " enter the Decimal for the new Limit: " .. acoff , limit ) )
data [ 10 ] = string.sub ( limit , 1 , 2 )
data [ 11 ] = string.sub ( limit , 3 , 4 )
data [ 12 ] = string.sub ( limit , 5 , 6 )
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- edit balance
if ( confirm ( accyan .. " change Balance? " .. acoff ) ) then
balance = string.format ( " %06x " , input ( accyan .. " enter the Decimal for the new Balance: " .. acoff , balance ) )
print ( " Balance: " .. balance )
data [ 15 ] = string.sub ( balance , 1 , 2 )
data [ 16 ] = string.sub ( balance , 3 , 4 )
data [ 17 ] = string.sub ( balance , 5 , 6 )
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
-- edit transaction-counter
if ( confirm ( accyan .. " change Transaction-Counter? " .. acoff ) ) then
tcv = string.format ( " %02x " , input ( accyan .. " enter the 4-digit Hex for the new Currency: " .. acoff , data [ 29 ] ) )
data [ 29 ] = tcv
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
-- edit reader.id
if ( confirm ( accyan .. " change Last-Reader-ID? " .. acoff ) ) then
rid = string.format ( " %06x " , input ( accyan .. " enter the Decimal for the new Balance: " .. acoff , rid ) )
print ( " Balance: " .. balance )
data [ 18 ] = string.sub ( rid , 1 , 2 )
data [ 19 ] = string.sub ( rid , 3 , 4 )
data [ 20 ] = string.sub ( rid , 5 , 6 )
end
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
return fixLegicCash ( data )
2016-03-06 20:26:13 +08:00
end
---
-- chack for signature of a 'Legic-Cash-Segment'
function check4LegicCash ( data )
if ( # data == 32 ) then
local stamp_len = ( # data - 25 )
local stamp = " "
for i = 0 , stamp_len - 1 do
stamp = stamp .. data [ i ] .. " "
end
if ( data [ 7 ] == " 01 " ) then
if ( ( " %04x " ) : format ( utils.Crc16 ( dumpTable ( data , " " , 0 , 12 ) ) ) == data [ 13 ] .. data [ 14 ] ) then
if ( ( " %04x " ) : format ( utils.Crc16 ( dumpTable ( data , " " , 15 , 20 ) ) ) == data [ 21 ] .. data [ 22 ] ) then
if ( ( " %04x " ) : format ( utils.Crc16 ( dumpTable ( data , " " , 23 , 29 ) ) ) == data [ 30 ] .. data [ 31 ] ) then
2016-03-21 02:25:48 +08:00
io.write ( accyan .. " Legic-Cash Segment detected " .. acoff )
2016-03-06 20:26:13 +08:00
return true
end
end
end
end
end
return false
end
2016-03-21 02:25:48 +08:00
---
-- chack for signature of a '3rd Party Cash-Segment' - not all bytes know until yet !!
function check43rdPartyCash1 ( uid , data )
if ( # data == 95 ) then
-- too explicit checking will avoid fixing ;-)
if ( string.find ( compareCrc ( utils.Crc8Legic ( uid .. dumpTable ( data , " " , 19 , 30 ) ) , data [ 31 ] ) , " valid " ) ) then
--if (compareCrc(utils.Crc8Legic(uid..data[32]..data[33]), data[34])=="valid") then
--if (compareCrc(utils.Crc8Legic(uid..data[35]..data[36]), data[37])=="valid") then
--if (compareCrc(utils.Crc8Legic(uid..dumpTable(data, "", 56, 61)), data[62])=="valid") then
--if (compareCrc(utils.Crc8Legic(uid..dumpTable(data, "", 74, 88)), data[89])=="valid") then
io.write ( accyan .. " 3rd Party Cash-Segment detected " .. acoff )
return true
--end
--end
--end
--end
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
end
return false
end
--- CRC related ---
---
-- build segmentCrc credentials
2017-05-18 00:52:30 +08:00
function segmentCrcCredentials ( tag , segid )
2016-03-21 02:25:48 +08:00
if ( istable ( tag.SEG [ 0 ] ) ) then
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
else return print ( acyellow .. " Master-Token / unsegmented Tag! " .. acoff ) end
end
---
-- build kghCrc credentials
2017-05-18 00:52:30 +08:00
function kghCrcCredentials ( tag , segid )
2016-03-21 02:25:48 +08:00
if ( istable ( tag ) and istable ( tag.SEG [ 0 ] ) ) then
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
end
---
-- compare two bytes
function compareCrc ( calc , guess )
calc = ( " %02x " ) : format ( calc )
if ( calc == guess ) then return acgreen .. " valid " .. acoff
else return acred .. " error " .. acoff .. calc .. " != " .. guess end
end
---
-- compare 4 bytes
function compareCrc16 ( calc , guess )
calc = ( " %04x " ) : format ( calc )
if ( calc == guess ) then return acgreen .. " valid " .. acoff
else return acred .. " error " .. acoff .. calc .. " != " .. guess end
end
---
-- repair / fix crc's of a 'Legic-Cash-Segment'
function fixLegicCash ( data )
if ( # data == 32 and data [ 7 ] == " 01 " ) then
local crc1 , crc2 , crc3
-- set shadow-balance equal to balance
data [ 23 ] = data [ 15 ]
data [ 24 ] = data [ 16 ]
data [ 25 ] = data [ 17 ]
-- set shadow-last-reader to last-reader
data [ 26 ] = data [ 18 ]
data [ 27 ] = data [ 19 ]
data [ 28 ] = data [ 20 ]
-- calculate all crc's
crc1 = ( " %04x " ) : format ( utils.Crc16 ( dumpTable ( data , " " , 0 , 12 ) ) )
crc2 = ( " %04x " ) : format ( utils.Crc16 ( dumpTable ( data , " " , 15 , 20 ) ) )
crc3 = ( " %04x " ) : format ( utils.Crc16 ( dumpTable ( data , " " , 23 , 29 ) ) )
-- set crc's
data [ 13 ] = string.sub ( crc1 , 1 , 2 )
data [ 14 ] = string.sub ( crc1 , 3 , 4 )
data [ 21 ] = string.sub ( crc2 , 1 , 2 )
data [ 22 ] = string.sub ( crc2 , 3 , 4 )
data [ 30 ] = string.sub ( crc3 , 1 , 2 )
data [ 31 ] = string.sub ( crc3 , 3 , 4 )
return data
end
end
---
-- repair / fix (yet known) crc's of a '3rd Party Cash-Segment' - not all bytes know until yet !!
function fix3rdPartyCash1 ( uid , data )
if ( # data == 95 ) then
-- checksum 1
data [ 31 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. dumpTable ( data , " " , 19 , 30 ) ) )
-- checksum 2
data [ 34 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. data [ 32 ] .. data [ 33 ] ) )
-- checksum 3
data [ 37 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. data [ 35 ] .. data [ 36 ] ) )
-- checksum 4
data [ 55 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. dumpTable ( data , " " , 46 , 54 ) ) )
-- checksum 5
data [ 62 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. dumpTable ( data , " " , 56 , 61 ) ) )
-- checksum 6
data [ 73 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. dumpTable ( data , " " , 63 , 72 ) ) )
-- checksum 7
data [ 89 ] = ( " %02x " ) : format ( utils.Crc8Legic ( uid .. dumpTable ( data , " " , 74 , 88 ) ) )
return data
end
end
2016-03-01 14:07:56 +08:00
---
-- calculate Master-Token crc
2017-05-18 00:52:30 +08:00
function calcMtCrc ( bytes )
2016-03-01 14:07:56 +08:00
--print(#bytes)
local cmd = bytes [ 1 ] .. bytes [ 2 ] .. bytes [ 3 ] .. bytes [ 4 ] .. bytes [ 7 ] .. bytes [ 6 ] .. bytes [ 8 ]
local len = ( tonumber ( 0xfc , 10 ) - ( " %d " ) : format ( ' 0x ' .. bytes [ 7 ] ) )
for i = 1 , len do
cmd = cmd .. bytes [ 8 + i ]
end
local res = ( " %02x " ) : format ( utils.Crc8Legic ( cmd ) )
return res
end
2016-03-21 02:25:48 +08:00
---
-- calculate segmentCRC for a given segment
function calcSegmentCrc ( tag , segid )
if ( istable ( tag.SEG [ 0 ] ) ) then
-- check if a 'Kaber Group Header' exists
local data = segmentCrcCredentials ( tag , segid )
return ( " %02x " ) : format ( utils.Crc8Legic ( data ) )
end
end
---
2017-05-18 00:52:30 +08:00
-- calcuate kghCRC for a given segment
2016-03-21 02:25:48 +08:00
function calcKghCrc ( tag , segid )
if ( istable ( tag.SEG [ 0 ] ) ) then
-- check if a 'Kaber Group Header' exists
local i
local data = kghCrcCredentials ( tag , segid )
return ( " %02x " ) : format ( utils.Crc8Legic ( data ) )
end
end
2016-03-01 14:07:56 +08:00
---
2017-07-30 15:17:48 +08:00
-- check all segment-crc
2016-03-01 14:07:56 +08:00
function checkAllSegCrc ( tag )
if ( istable ( tag.SEG [ 0 ] ) ) then
for i = 0 , # tag.SEG do
crc = calcSegmentCrc ( tag , i )
tag.SEG [ i ] . crc = crc
end
2016-03-21 02:25:48 +08:00
else return print ( acyellow .. " Master-Token / unsegmented Tag " .. acoff ) end
2016-03-01 14:07:56 +08:00
end
---
-- check all segmnet-crc
function checkAllKghCrc ( tag )
if ( istable ( tag.SEG [ 0 ] ) ) then
for i = 0 , # tag.SEG do
crc = calcKghCrc ( tag , i )
2017-05-18 00:52:30 +08:00
if ( tag.SEG [ i ] . kgh ) then
2016-03-01 14:07:56 +08:00
tag.SEG [ i ] . data [ # tag.SEG [ i ] . data - 1 ] = crc
end
end
end
end
---
2016-03-21 02:25:48 +08:00
-- validate segmentCRC for a given segment
function checkSegmentCrc ( tag , segid )
local data = segmentCrcCredentials ( tag , segid )
2017-05-18 00:52:30 +08:00
if ( ( " %02x " ) : format ( utils.Crc8Legic ( data ) ) == tag.SEG [ segid ] . crc ) then
2016-03-21 02:25:48 +08:00
return true
2016-03-01 14:07:56 +08:00
end
2016-03-21 02:25:48 +08:00
return false
2016-03-01 14:07:56 +08:00
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 )
2017-05-18 00:52:30 +08:00
if ( ( " %02x " ) : format ( utils.Crc8Legic ( data ) ) == tag.SEG [ segid ] . data [ tag.SEG [ segid ] . len - 5 - 1 ] ) then return true ; end
2016-03-01 14:07:56 +08:00
else return false ; end
2016-03-21 02:25:48 +08:00
else oops ( acred .. " 'Kaba Group header' detected but no Segment-Data found " .. ansocolors.reset ) end
2016-03-01 14:07:56 +08:00
end
2016-02-28 21:50:49 +08:00
---
-- helptext for modify-mode
function modifyHelp ( )
local t = [ [
2017-05-18 00:52:30 +08:00
2016-03-21 02:25:48 +08:00
Data I / O Segment Manipulation Token - Data
----------------- -------------------- ---------------------
rt => read Tag as => add Segment mt => make Token
wt => write Tag es => edit Segment Header et => edit Token data
ed => edit Segment Data tk => toggle KGH - Flag
2017-05-18 00:52:30 +08:00
File I / O rs => remove Segment
----------------- cc => check Segment-CRC
lf => load File ck => check KGH
sf => save File ds => dump Segments
xf => xor to File
Virtual Tags tagMap ( partial ) known Segments
2016-03-21 02:25:48 +08:00
-------------------------------- --------------------- ---------------------------
2017-05-18 00:52:30 +08:00
ct => copy mainTag to backupTag mm => make ( new ) Map dlc => dump Legic - Cash
tc => copy backupTag to mainTag em => edit Map submenu elc => edit Legic - Cash
2016-03-21 02:25:48 +08:00
tt => switch mainTag & backupTag lm => load map from file d3p => dump 3 rd - Party - Cash
di => dump mainTag sm => save map to file e3p => edit 3 rd - Party - Cash
2017-05-18 00:52:30 +08:00
do => dump backupTag
2016-03-21 02:25:48 +08:00
h => this help q => quit
2017-05-18 00:52:30 +08:00
] ]
2016-02-28 21:50:49 +08:00
return t
end
2017-05-18 00:52:30 +08:00
---
2016-02-28 21:50:49 +08:00
-- modify Tag (interactive)
function modifyMode ( )
2016-03-21 02:25:48 +08:00
local i , backupTAG , outTAG , inTAG , outfile , infile , sel , segment , bytes , outbytes , tagMap
2017-05-18 00:52:30 +08:00
2016-02-28 21:50:49 +08:00
actions = {
2016-03-21 02:25:48 +08:00
---
-- helptext
2017-05-18 00:52:30 +08:00
[ " h " ] = function ( x )
print ( " Version: " .. version ) ;
2016-03-21 02:25:48 +08:00
print ( modifyHelp ( ) .. " \n " .. " tags im Memory: " .. ( istable ( inTAG ) and ( ( currentTag == ' inTAG ' ) and acgreen .. " *mainTAG " .. acoff or " mainTAG " ) or " " ) .. " " .. ( istable ( backupTAG ) and ( ( currentTag == ' backupTAG ' ) and acgreen .. " *backupTAG " .. acoff or " backupTAG " ) or " " ) )
2016-02-28 21:50:49 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- read real Tag with PM3 into virtual 'mainTAG'
2017-05-18 00:52:30 +08:00
[ " rt " ] = function ( x )
inTAG = readFromPM3 ( ) ;
--actions.di()
2016-03-06 20:26:13 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- write content of virtual 'mainTAG' to real Tag with PM3
2017-05-18 00:52:30 +08:00
[ " wt " ] = function ( x )
2016-03-21 02:25:48 +08:00
writeToTag ( inTAG )
2016-02-28 21:50:49 +08:00
end ,
2016-03-06 20:26:13 +08:00
---
2017-05-18 00:52:30 +08:00
-- copy mainTAG to backupTAG
[ " ct " ] = function ( x )
print ( accyan .. " copy mainTAG to backupTAG " .. acoff )
2016-03-06 20:26:13 +08:00
backupTAG = deepCopy ( inTAG )
2016-02-28 21:50:49 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- copy backupTAG to mainTAG
2017-05-18 00:52:30 +08:00
[ " tc " ] = function ( x )
2016-03-21 02:25:48 +08:00
print ( accyan .. " copy backupTAG to mainTAG " .. acoff )
2016-03-06 20:26:13 +08:00
inTAG = deepCopy ( backupTAG )
end ,
2016-03-21 02:25:48 +08:00
---
-- toggle between mainTAG and backupTAG
2017-05-18 00:52:30 +08:00
[ " tt " ] = function ( x )
2016-03-21 02:25:48 +08:00
-- copy main to temp
outTAG = deepCopy ( inTAG )
-- copy backup to main
inTAG = deepCopy ( backupTAG )
print ( accyan .. " toggle to " .. accyan .. ( ( currentTag == ' inTAG ' ) and " backupTAG " or " mainTAG " ) .. acoff )
if ( currentTag == " inTAG " ) then currentTag = ' backupTAG '
else currentTag = ' inTAG ' end
-- copy temp (main) to backup
backupTAG = deepCopy ( outTAG )
2016-02-28 21:50:49 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- load file into mainTAG
2017-05-18 00:52:30 +08:00
[ " lf " ] = function ( x )
2017-07-30 15:17:48 +08:00
if ( type ( x ) == ' string ' and file_check ( x ) ) then
filename = x
else
filename = input ( " enter filename: " , " legic.temp " )
end
2016-02-28 21:50:49 +08:00
inTAG = readFile ( filename )
2016-03-21 02:25:48 +08:00
-- check for existing tagMap
if ( file_check ( filename .. " .map " ) ) then
if ( confirm ( accyan .. " Mapping-File for " .. acoff .. filename .. accyan .. " found - load it also? " .. acoff ) ) then
tagMap = loadTagMap ( filename .. " .map " )
end
2017-05-18 00:52:30 +08:00
end
2016-02-28 21:50:49 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- save values of mainTAG to a file (xored with MCC of mainTAG)
2017-05-18 00:52:30 +08:00
[ " sf " ] = function ( x )
2016-02-28 21:50:49 +08:00
if ( istable ( inTAG ) ) then
outfile = input ( " enter filename: " , " legic.temp " )
bytes = tagToBytes ( inTAG )
--bytes=xorBytes(bytes, inTAG.MCC)
2017-05-18 00:52:30 +08:00
if ( bytes ) then
2016-02-28 21:50:49 +08:00
writeFile ( bytes , outfile )
end
end
end ,
2016-03-21 02:25:48 +08:00
---
2017-05-18 00:52:30 +08:00
-- save values of mainTAG to a file (xored with 'specific' MCC)
[ " xf " ] = function ( x )
2016-02-28 21:50:49 +08:00
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
2017-05-18 00:52:30 +08:00
if ( bytes ) then
2016-02-28 21:50:49 +08:00
writeFile ( bytes , outfile )
end
end
end ,
2016-03-21 02:25:48 +08:00
---
-- dump mainTAG (and all Segments)
2017-05-18 00:52:30 +08:00
[ " di " ] = function ( x )
if ( istable ( inTAG ) ) then
2016-03-06 20:26:13 +08:00
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
if ( istable ( inTAG.SEG [ 0 ] ) ) then
for i = 0 , # inTAG.SEG do
if ( check43rdPartyCash1 ( uid , inTAG.SEG [ i ] . data ) ) then
2017-05-18 00:52:30 +08:00
io.write ( accyan .. " in Segment index: " .. inTAG.SEG [ i ] . index .. acoff .. " \n " )
2016-03-06 20:26:13 +08:00
elseif ( check4LegicCash ( inTAG.SEG [ i ] . data ) ) then
2016-03-21 02:25:48 +08:00
io.write ( accyan .. " in Segment index: " .. inTAG.SEG [ i ] . index .. acoff .. " \n " )
2017-05-18 00:52:30 +08:00
lc = true ;
2016-03-06 20:26:13 +08:00
lci = inTAG.SEG [ i ] . index ;
end
end
end
2017-05-18 00:52:30 +08:00
print ( " \n " .. dumpTag ( inTAG ) .. " \n " )
2016-03-06 20:26:13 +08:00
if ( lc ) then actions [ " dlc " ] ( lci ) end
2016-03-21 02:25:48 +08:00
lc = false
2017-05-18 00:52:30 +08:00
end
2016-03-06 20:26:13 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- dump backupTAG (and all Segments)
2016-03-06 20:26:13 +08:00
[ " do " ] = function ( x ) if ( istable ( backupTAG ) ) then print ( " \n " .. dumpTag ( backupTAG ) .. " \n " ) end end ,
2016-03-21 02:25:48 +08:00
---
-- create a empty tagMap
2017-05-18 00:52:30 +08:00
[ " mm " ] = function ( x )
2016-03-21 02:25:48 +08:00
-- clear existing tagMap and init
2017-05-18 00:52:30 +08:00
if ( istable ( inTAG ) ) then
2016-03-21 02:25:48 +08:00
tagMap = makeTagMap ( )
end
end ,
---
-- edit a tagMap
2017-05-18 00:52:30 +08:00
[ " em " ] = function ( x )
if ( istable ( inTAG ) == false ) then
if ( confirm ( " no mainTAG in memory! \n read from PM3? " ) ) then
actions [ ' rt ' ] ( )
elseif ( confirm ( " load from File? " ) ) then
actions [ ' lf ' ] ( )
2016-03-21 02:25:48 +08:00
else return
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
end
2017-05-18 00:52:30 +08:00
if ( istable ( tagMap ) == false ) then actions [ ' mm ' ] ( ) end
2016-03-21 02:25:48 +08:00
-- edit
tagMap = editTagMap ( inTAG , tagMap )
end ,
---
-- save a tagMap
2017-05-18 00:52:30 +08:00
[ " sm " ] = function ( x )
2016-03-21 02:25:48 +08:00
if ( istable ( tagMap ) ) then
if ( istable ( tagMap ) and # tagMap.mappings > 0 ) then
print ( accyan .. " Map contains " .. acoff .. # tagMap .. accyan .. " mappings " .. acoff )
saveTagMap ( tagMap , input ( accyan .. " enter filename: " .. acoff , " Legic.map " ) )
2017-05-18 00:52:30 +08:00
else
2016-03-21 02:25:48 +08:00
print ( acyellow .. " no mappings in tagMap! " .. acoff )
end
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
end ,
---
-- load a tagMap
2017-05-18 00:52:30 +08:00
[ " lm " ] = function ( x )
2016-03-21 02:25:48 +08:00
tagMap = loadTagMap ( input ( accyan .. " enter filename: " .. acoff , " Legic.map " ) )
end ,
---
-- dump single segment
2017-05-18 00:52:30 +08:00
[ " ds " ] = function ( x )
2017-07-30 15:17:48 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
sel = tonumber ( x , 10 )
else
sel = selectSegment ( inTAG )
end
2017-05-18 00:52:30 +08:00
if ( sel ) then print ( " \n " .. ( dumpSegment ( inTAG , sel ) or acred .. " no Segments available " ) .. acoff .. " \n " ) end
2016-02-28 21:50:49 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- edit segment header
2017-05-18 00:52:30 +08:00
[ " es " ] = function ( x )
2016-03-01 14:07:56 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then sel = tonumber ( x , 10 )
else sel = selectSegment ( inTAG ) end
2017-05-18 00:52:30 +08:00
if ( sel ) then
2016-03-01 14:07:56 +08:00
if ( istable ( inTAG.SEG [ 0 ] ) ) then
2016-02-28 21:50:49 +08:00
inTAG = editSegment ( inTAG , sel )
inTAG.SEG [ sel ] = regenSegmentHeader ( inTAG.SEG [ sel ] )
2017-07-30 15:17:48 +08:00
else
print ( acyellow .. " no Segments in Tag " .. acoff )
end
2016-02-28 21:50:49 +08:00
end
end ,
2016-03-21 02:25:48 +08:00
---
-- add segment
2017-05-18 00:52:30 +08:00
[ " as " ] = function ( x )
2016-02-28 21:50:49 +08:00
if ( istable ( inTAG.SEG [ 0 ] ) ) then
inTAG = addSegment ( inTAG )
inTAG.SEG [ # inTAG.SEG - 1 ] = regenSegmentHeader ( inTAG.SEG [ # inTAG.SEG - 1 ] )
2017-05-18 00:52:30 +08:00
inTAG.SEG [ # inTAG.SEG ] = regenSegmentHeader ( inTAG.SEG [ # inTAG.SEG ] )
2016-03-21 02:25:48 +08:00
else print ( accyan .. " Master-Token / unsegmented Tag! " .. acoff )
2016-02-28 21:50:49 +08:00
end
end ,
2016-03-21 02:25:48 +08:00
---
-- remove segment
2017-05-18 00:52:30 +08:00
[ " rs " ] = function ( x )
2016-03-01 14:07:56 +08:00
if ( istable ( inTAG.SEG [ 0 ] ) ) then
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then sel = tonumber ( x , 10 )
else sel = selectSegment ( inTAG ) end
2016-02-28 21:50:49 +08:00
inTAG = delSegment ( inTAG , sel )
for i = 0 , # inTAG.SEG do
inTAG.SEG [ i ] = regenSegmentHeader ( inTAG.SEG [ i ] )
end
end
end ,
2016-03-21 02:25:48 +08:00
---
-- edit data-portion of single segment
2017-05-18 00:52:30 +08:00
[ " ed " ] = function ( x )
2016-03-01 14:07:56 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then sel = tonumber ( x , 10 )
else sel = selectSegment ( inTAG ) end
2017-05-18 00:52:30 +08:00
if ( istable ( inTAG.SEG [ sel ] ) ) then
inTAG.SEG [ sel ] . data = editSegmentData ( inTAG.SEG [ sel ] . data )
2016-02-28 21:50:49 +08:00
end
end ,
2016-03-21 02:25:48 +08:00
---
-- edit Tag (MCD, MSN, MCC etc.)
2017-05-18 00:52:30 +08:00
[ " et " ] = function ( x )
2016-03-01 14:07:56 +08:00
if ( istable ( inTAG ) ) then
editTag ( inTAG )
end
end ,
2016-03-21 02:25:48 +08:00
---
-- make (dummy) Token
2016-03-01 14:07:56 +08:00
[ " mt " ] = function ( x ) inTAG = makeToken ( ) ; actions.di ( ) end ,
2016-03-21 02:25:48 +08:00
---
-- fix segment-crc on single segment
2017-05-18 00:52:30 +08:00
[ " ts " ] = function ( x )
2016-03-01 14:07:56 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then sel = tonumber ( x , 10 )
else sel = selectSegment ( inTAG ) end
2017-05-18 00:52:30 +08:00
regenSegmentHeader ( inTAG.SEG [ sel ] )
2016-02-28 21:50:49 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
2017-05-18 00:52:30 +08:00
-- toggle kgh-crc-flag on a single segment
[ " tk " ] = function ( x )
2016-03-01 14:07:56 +08:00
if ( istable ( inTAG ) and istable ( inTAG.SEG [ 0 ] ) ) then
2017-07-30 15:17:48 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
sel = tonumber ( x , 10 )
else
sel = selectSegment ( inTAG )
end
if ( inTAG.SEG [ sel ] . kgh ) then
inTAG.SEG [ sel ] . kgh = false
else
inTAG.SEG [ sel ] . kgh = true
end
2016-03-01 14:07:56 +08:00
end
2016-02-28 21:50:49 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- calculate LegicCrc8
[ " k " ] = function ( x )
2016-03-01 14:07:56 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
2017-05-18 00:52:30 +08:00
print ( ( " %02x " ) : format ( utils.Crc8Legic ( x ) ) )
2016-03-01 14:07:56 +08:00
end
2016-03-21 02:25:48 +08:00
end ,
---
-- noop
2016-03-06 20:26:13 +08:00
[ " xb " ] = function ( x )
2016-03-21 02:25:48 +08:00
end ,
---
2017-05-18 00:52:30 +08:00
-- print string for LegicCrc8-calculation about single segment
[ " xc " ] = function ( x )
2016-03-01 14:07:56 +08:00
if ( istable ( inTAG ) and istable ( inTAG.SEG [ 0 ] ) ) then
2017-07-30 15:17:48 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
sel = tonumber ( x , 10 )
else
sel = selectSegment ( inTAG )
end
2017-05-18 00:52:30 +08:00
print ( " k " .. kghCrcCredentials ( inTAG , sel ) )
end
2016-02-28 21:50:49 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- fix legic-cash checksums
2017-05-18 00:52:30 +08:00
[ " flc " ] = function ( x )
2017-07-30 15:17:48 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
x = tonumber ( x , 10 )
else
x = selectSegment ( inTAG )
end
2016-03-21 02:25:48 +08:00
inTAG.SEG [ x ] . data = fixLegicCash ( inTAG.SEG [ x ] . data )
end ,
---
-- edit legic-cash values fixLegicCash(data)
2017-05-18 00:52:30 +08:00
[ " elc " ] = function ( x )
2016-03-21 02:25:48 +08:00
x = autoSelectSegment ( inTAG , " legiccash " )
inTAG.SEG [ x ] . data = editLegicCash ( inTAG.SEG [ x ] . data )
end ,
---
-- dump legic-cash human-readable
2017-05-18 00:52:30 +08:00
[ " dlc " ] = function ( x )
2016-03-06 20:26:13 +08:00
-- if segment index was user defined
2017-05-18 00:52:30 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
2016-03-06 20:26:13 +08:00
x = tonumber ( x , 10 )
print ( string.format ( " User-Selected Index %02d " , x ) )
2017-07-30 15:17:48 +08:00
else
2016-03-06 20:26:13 +08:00
-- or try to find match
2017-07-30 15:17:48 +08:00
x = autoSelectSegment ( inTAG , " legiccash " )
end
2016-03-21 02:25:48 +08:00
-- dump it
dumpLegicCash ( inTAG , x )
2016-03-06 20:26:13 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- dump 3rd-party-cash-segment
2016-03-06 20:26:13 +08:00
[ " d3p " ] = function ( x )
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
-- if segment index was user defined
2017-05-18 00:52:30 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
2016-03-06 20:26:13 +08:00
x = tonumber ( x , 10 )
print ( string.format ( " User-Selected Index %02d " , x ) )
2017-07-30 15:17:48 +08:00
else
2016-03-06 20:26:13 +08:00
-- or try to find match
2017-07-30 15:17:48 +08:00
x = autoSelectSegment ( inTAG , " 3rdparty " )
end
2016-03-06 20:26:13 +08:00
if ( istable ( inTAG ) and istable ( inTAG.SEG [ x ] ) and inTAG.SEG [ x ] . len == 100 ) then
uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
if ( check43rdPartyCash1 ( uid , inTAG.SEG [ x ] . data ) ) then
dump3rdPartyCash1 ( inTAG , x )
end
end
end ,
2016-03-21 02:25:48 +08:00
---
-- dump 3rd-party-cash-segment (raw blocks and checksums over 'known areas')
2016-03-06 20:26:13 +08:00
[ " r3p " ] = function ( x )
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
-- if segment index was user defined
2017-05-18 00:52:30 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
2016-03-06 20:26:13 +08:00
x = tonumber ( x , 10 )
print ( string.format ( " User-Selected Index %02d " , x ) )
2017-07-30 15:17:48 +08:00
else
2016-03-06 20:26:13 +08:00
-- or try to find match
2017-07-30 15:17:48 +08:00
x = autoSelectSegment ( inTAG , " 3rdparty " )
end
2016-03-21 02:25:48 +08:00
print3rdPartyCash1 ( inTAG , x )
2016-03-06 20:26:13 +08:00
end ,
2016-03-21 02:25:48 +08:00
---
-- edit 3rd-party-cash-segment values (Balance, Mapping-UID, Stamp)
2017-05-18 00:52:30 +08:00
[ " e3p " ] = function ( x )
2016-03-06 20:26:13 +08:00
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
-- if segment index was user defined
2017-05-18 00:52:30 +08:00
if ( type ( x ) == " string " and string.len ( x ) > 0 ) then
2016-03-06 20:26:13 +08:00
x = tonumber ( x , 10 )
print ( string.format ( " User-Selected Index %02d " , x ) )
2017-07-30 15:17:48 +08:00
else
2016-03-06 20:26:13 +08:00
-- or try to find match
2017-07-30 15:17:48 +08:00
x = autoSelectSegment ( inTAG , " 3rdparty " )
end
2016-03-06 20:26:13 +08:00
if ( istable ( inTAG ) and istable ( inTAG.SEG [ x ] ) and inTAG.SEG [ x ] . len == 100 ) then
2016-03-21 02:25:48 +08:00
inTAG = edit3rdPartyCash1 ( inTAG , x )
2016-03-06 20:26:13 +08:00
dump3rdPartyCash1 ( inTAG , x )
end
end ,
2016-03-21 02:25:48 +08:00
---
-- force fixing 3rd-party-checksums
2017-05-18 00:52:30 +08:00
[ " f3p " ] = function ( x )
2017-07-30 15:17:48 +08:00
if ( type ( x ) == " string " and string.len ( x ) >= 2 ) then
x = tonumber ( x , 10 )
else
x = selectSegment ( inTAG )
end
2017-05-18 00:52:30 +08:00
if ( istable ( inTAG.SEG [ x ] ) ) then
2016-03-21 02:25:48 +08:00
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
inTAG.SEG [ x ] . data = fix3rdPartyCash1 ( uid , inTAG.SEG [ x ] . data )
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
end ,
---
2017-05-18 00:52:30 +08:00
-- get stamp from single segment
2016-03-06 20:26:13 +08:00
[ " gs " ] = function ( x )
2017-07-30 15:17:48 +08:00
if ( type ( x ) == " string " and string.len ( x ) >= 2 ) then
x = tonumber ( x , 10 )
else
x = selectSegment ( inTAG )
end
2016-03-06 20:26:13 +08:00
local stamp = getSegmentStamp ( inTAG.SEG [ x ] )
print ( " Stamp : " .. stamp )
stamp = str2bytes ( stamp )
print ( " lenght: " .. # stamp )
end ,
2016-03-21 02:25:48 +08:00
---
-- calculate crc16
2017-05-18 00:52:30 +08:00
[ " c6 " ] = function ( x ) local crc16 = string.format ( " %4.04x " , utils.Crc16 ( x ) )
2016-03-06 20:26:13 +08:00
print ( string.sub ( crc16 , 0 , 2 ) .. " " .. string.sub ( crc16 , 3 , 4 ) )
end ,
2016-03-21 02:25:48 +08:00
---
-- check & fix segments-crc of all segments
[ " cc " ] = function ( x ) if ( istable ( inTAG ) ) then checkAllSegCrc ( inTAG ) end end ,
---
-- set backup-area-bytes to '00'
2017-05-18 00:52:30 +08:00
[ " cb " ] = function ( x )
2016-03-06 20:26:13 +08:00
if ( istable ( inTAG ) ) then
2016-03-21 02:25:48 +08:00
print ( accyan .. " purge BackupArea " .. acoff )
2017-05-18 00:52:30 +08:00
inTAG = clearBackupArea ( inTAG )
end
end ,
2016-03-21 02:25:48 +08:00
---
-- check and fix all segments inTAG.SEG[x].kgh toggled 'on'
[ " ck " ] = function ( x ) if ( istable ( inTAG ) ) then checkAllKghCrc ( inTAG ) end end ,
---
-- check and fix all segments inTAG.SEG[x].kgh toggled 'on'
2017-05-18 00:52:30 +08:00
[ " tac " ] = function ( x )
if ( colored_output ) then
2016-03-21 02:25:48 +08:00
colored_output = false
else
colored_output = true
2017-05-18 00:52:30 +08:00
end
2016-03-21 02:25:48 +08:00
load_colors ( colored_output )
2016-03-06 20:26:13 +08:00
end ,
2016-02-28 21:50:49 +08:00
}
2017-05-18 00:52:30 +08:00
repeat
2016-03-21 02:25:48 +08:00
-- defualt message / prompt
2016-02-28 21:50:49 +08:00
ic = input ( " Legic command? ('h' for help - 'q' for quit) " , " h " )
2016-03-21 02:25:48 +08:00
-- command actions decisions (first match, longer commands before shorter)
2016-03-06 20:26:13 +08:00
if ( type ( actions [ string.lower ( string.sub ( ic , 0 , 3 ) ) ] ) == ' function ' ) then
actions [ string.lower ( string.sub ( ic , 0 , 3 ) ) ] ( string.sub ( ic , 5 ) )
2016-02-28 21:50:49 +08:00
elseif ( type ( actions [ string.lower ( string.sub ( ic , 0 , 2 ) ) ] ) == ' function ' ) then
actions [ string.lower ( string.sub ( ic , 0 , 2 ) ) ] ( string.sub ( ic , 4 ) )
2016-03-06 20:26:13 +08:00
elseif ( type ( actions [ string.lower ( string.sub ( ic , 0 , 1 ) ) ] ) == ' function ' ) then
actions [ string.lower ( string.sub ( ic , 0 , 1 ) ) ] ( string.sub ( ic , 3 ) )
2017-07-30 15:17:48 +08:00
else
actions.h ( ' ' )
end
2016-02-28 21:50:49 +08:00
until ( string.sub ( ic , 0 , 1 ) == " q " )
end
2016-03-21 02:25:48 +08:00
---
-- main function
2016-02-28 21:50:49 +08:00
function main ( args )
2016-03-21 02:25:48 +08:00
-- set init colors/switch (can be toggled with 'tac' => 'toggle ansicolors')
load_colors ( colored_output )
2016-02-28 21:50:49 +08:00
if ( # args == 0 ) then modifyMode ( ) end
--- variables
2016-03-06 20:26:13 +08:00
local inTAG , backupTAG , outTAG , outfile , interactive , crc , ofs , cfs , dfs
2016-02-28 21:50:49 +08:00
-- just a spacer for better readability
print ( )
--- parse arguments
2017-05-18 00:52:30 +08:00
for o , a in getopt.getopt ( args , ' hrmi:do:c: ' ) do
2016-02-28 21:50:49 +08:00
-- 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
2017-05-18 00:52:30 +08:00
-- dump virtual-Tag
2016-02-28 21:50:49 +08:00
if o == " d " then dfs = true end
-- interacive modifying
2017-07-30 15:17:48 +08:00
if o == " m " then
interactive = true
modifyMode ( )
end
2016-02-28 21:50:49 +08:00
-- xor (e.g. for clone or plain file)
2017-07-30 15:17:48 +08:00
if o == " c " then
cfs = true
crc = a
end
2016-02-28 21:50:49 +08:00
-- output file
2017-07-30 15:17:48 +08:00
if o == " o " then
outfile = a
ofs = true
end
2016-02-28 21:50:49 +08:00
end
2017-05-18 00:52:30 +08:00
2016-02-28 21:50:49 +08:00
-- file conversion (output to file)
2017-08-13 21:06:30 +08:00
if ofs == false then return end
2017-07-30 15:17:48 +08:00
2016-02-28 21:50:49 +08:00
-- dump infile / tag-read
2017-05-18 00:52:30 +08:00
if ( dfs ) then
print ( " ----------------------------------------- " )
2016-02-28 21:50:49 +08:00
print ( dumpTag ( inTAG ) )
end
2017-07-30 15:17:48 +08:00
2016-02-28 21:50:49 +08:00
bytes = tagToBytes ( inTAG )
2017-05-18 00:52:30 +08:00
if ( cfs ) then
2016-03-01 14:07:56 +08:00
-- xor willl be done in function writeFile
-- with the value of byte[5]
2017-05-18 00:52:30 +08:00
bytes [ 5 ] = crc
2016-02-28 21:50:49 +08:00
end
2017-07-30 15:17:48 +08:00
2016-02-28 21:50:49 +08:00
-- write to outfile
2017-05-18 00:52:30 +08:00
if ( bytes ) then
2016-02-28 21:50:49 +08:00
writeFile ( bytes , outfile )
2017-05-18 00:52:30 +08:00
--- read real tag into virtual tag
2016-03-01 14:07:56 +08:00
-- inTAG=readFromPM3() end
--- or simply use the bytes that where wriiten
2016-02-28 21:50:49 +08:00
inTAG = bytesToTag ( bytes , inTAG )
-- show new content
2017-05-18 00:52:30 +08:00
if ( dfs ) then
2016-02-28 21:50:49 +08:00
print ( " ----------------------------------------- " )
2017-05-18 00:52:30 +08:00
print ( dumpTag ( inTAG ) )
2016-02-28 21:50:49 +08:00
end
end
2017-05-18 00:52:30 +08:00
2016-02-28 21:50:49 +08:00
end
2016-03-21 02:25:48 +08:00
---
-- script start
2017-07-30 15:17:48 +08:00
main ( args )