2017-05-17 18:52:30 +02:00
--[[
2016-06-22 09:33:21 +02: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-20 19:25:48 +01:00
2019-03-09 10:34:43 +01:00
(example) Legic-Prime Layout with 'Kaba Group Header'
2016-02-28 14:50:49 +01:00
+----+----+----+----+----+----+----+----+
2017-05-17 18:52:30 +02:00
0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 9f |
2016-02-28 14:50:49 +01: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 13:26:13 +01:00
MCD = Manufacturer ID
MSN = Manufacturer SerialNumber
60 ea = DCF Low + DCF high
9f = 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
2019-03-09 10:34:43 +01:00
(example) Legic-Cash on MIM256/1024 tag' (37 bytes)
2016-03-06 13:26:13 +01:00
+----+----+----+----+----+----+----+----+
2017-05-17 18:52:30 +02:00
0x00|Seg0|Seg1|Seg2|Seg3|SegC|STP0|STP1|STP2|
2016-03-06 13:26:13 +01: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..0x12
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 09:33:21 +02:00
2019-03-09 10:34:43 +01:00
(example) Legic-Prime Layout 'gantner unsegmented user-credential'
2016-06-22 09:33:21 +02:00
+----+----+----+----+----+----+----+----+
2017-05-17 18:52:30 +02:00
0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 08 |
2016-06-22 09:33:21 +02:00
+----+----+----+----+----+----+----+----+
0x08|Stp0|Stp1|Stp2|Stp3|Stp4|Dat0|Dat1|uCRC| <- addr 0x08..0x0f 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..0x03+0x07..0x0E
2019-03-09 10:34:43 +01:00
(example) Legic-Prime Layout 'gantner unsegmented Master-Token (IAM) with a stamp_len of 4'
2016-06-22 09:33:21 +02:00
+----+----+----+----+----+----+----+----+
2017-05-17 18:52:30 +02:00
0x00|MCD |MSN0|MSN1|MSN2|MCC | 20 | f8 | 08 |
2016-06-22 09:33:21 +02:00
+----+----+----+----+----+----+----+----+
0x08|Stp0|Stp1|Stp2|Stp3| 00 | 00 | 00 |CRC1|
+----+----+----+----+----+----+----+----+
2017-05-17 18:52:30 +02:00
0x10| 00 | 00 | 00 | 00 | 00 |CRC2|
2016-06-22 09:33:21 +02: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..0x03+0x07..0x0E (special 'gantner crc8')
CRC2 = MCD + MSB0..2+ addr 0x06 + addr 0x05 + addr 0x07 + Stamp (regular Master-Token-CRC)
2016-02-28 14:50:49 +01:00
--]]
2020-04-08 22:47:13 +02:00
--[[
Known issues; needs to be fixed:
* last byte in last segment is handled incorrectly when it is the last bytes on the card itself (MIM256: => byte 256)
--]]
2016-02-28 14:50:49 +01:00
example = "script run legic"
2020-04-08 22:47:13 +02:00
author = "Mosci, uhei"
version = "1.0.4"
2016-03-20 19:25:48 +01:00
2016-02-28 14:50:49 +01:00
desc =
[[
This script helps you to read, create and modify Legic Prime Tags (MIM22, MIM256, MIM1024)
2020-04-08 22:47:13 +02:00
The virtual tag (and therefore the file to be saved) is always a MIM1024 tag.
2016-02-28 14:50:49 +01:00
it's kinda interactive with following commands in three categories:
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
File I/O rs => remove Segment
----------------- cc => check Segment-CRC
2020-04-08 22:47:13 +02:00
lf => load bin File ck => check KGH
sf => save eml/bin File ds => dump Segments
2017-05-17 18:52:30 +02:00
xf => xor to File
2016-03-20 19:25:48 +01:00
(partially) known Segments Virtual Tags Script Output
--------------------------- ------------------------------- ------------------------
dlc => dump Legic-Cash ct => copy mainTag to backupTag tac => toggle ansicolors
2017-05-17 18:52:30 +02:00
elc => edit Legic-Cash tc => copy backupTag to mainTag
d3p => dump 3rd-Party-Cash tt => switch mainTag & backupTag
e3p => edit 3rd-Party-Cash di => dump mainTag
2016-03-20 19:25:48 +01:00
do => dump backupTag
2016-03-06 13:26:13 +01:00
2017-05-17 18:52:30 +02:00
2016-02-28 14:50:49 +01: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-17 18:52:30 +02:00
2020-04-08 22:47:13 +02:00
lf: 'load file' - load a (xored) binary file (*.bin) from the local Filesystem into the 'virtual inTag'
sf: 'save file' - saves the 'virtual inTag' to the local Filesystem as eml and bin (xored with Tag-MCC)
2016-03-20 19:25:48 +01:00
xf: 'xor file' - saves the 'virtual inTag' to the local Filesystem (xored with choosen MCC - use '00' for plain values)
2017-05-17 18:52:30 +02:00
2016-02-28 14:50:49 +01: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-20 19:25:48 +01:00
tt: 'toggle tag' - copy mainTag to BackupTag and backupTag to mainTag
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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 14:50:49 +01: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 07:07:56 +01: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 14:50:49 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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 3rd-Party Cash Segment
e3p: 'edit 3rd Party' - edit Data in 3rd-Party Cash Segment
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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 14:50:49 +01:00
]]
2016-03-06 13:26:13 +01:00
currentTag = "inTAG"
2016-03-20 19:25:48 +01:00
2017-05-17 18:52:30 +02:00
---
2016-03-01 07:07:56 +01:00
-- requirements
2016-03-20 19:25:48 +01:00
local utils = require ( 'utils' )
local getopt = require ( 'getopt' )
local ansicolors = require ( 'ansicolors' )
2016-02-28 14:50:49 +01:00
2017-05-17 18:52:30 +02:00
---
2016-03-01 07:07:56 +01:00
-- global variables / defines
2016-02-28 14:50:49 +01:00
local bxor = bit32.bxor
local bbit = bit32.extract
local input = utils.input
local confirm = utils.confirm
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
-- 'no color'
2016-03-20 19:25:48 +01:00
acgreen = ""
accyan = ""
acred = ""
acyellow = ""
acblue = ""
acmagenta = ""
acoff = ""
end
end
---
2016-03-06 13:26:13 +01:00
-- curency-codes for Legic-Cash-Segments (ISO 4217)
local currency = {
2017-05-17 18:52:30 +02:00
[ "03d2" ] = "EUR" ,
[ "0348" ] = "USD" ,
2016-03-06 13:26:13 +01:00
[ "033A" ] = "GBP" ,
[ "02F4" ] = "CHF"
}
2017-05-17 18:52:30 +02:00
---
2016-02-28 14:50:49 +01:00
-- This is only meant to be used when errors occur
function oops ( err )
2019-03-09 10:34:43 +01:00
print ( acred .. "ERROR: " .. acoff , err )
return nil , err
2016-02-28 14:50:49 +01:00
end
2017-05-17 18:52:30 +02:00
---
2016-02-28 14:50:49 +01:00
-- Usage help
function help ()
2019-03-09 10:34:43 +01:00
print ( desc )
print ( "Version: " .. version )
print ( "Example usage: " .. example )
2016-02-28 14:50:49 +01:00
end
2017-05-17 18:52:30 +02:00
---
2016-02-28 14:50:49 +01:00
-- table check helper
2017-05-17 18:52:30 +02:00
function istable ( t )
return type ( t ) == 'table'
2016-02-28 14:50:49 +01:00
end
2020-04-08 22:47:13 +02:00
---
-- To have two char string for a byte
local function padString ( str )
if ( # str == 1 ) then
return '0' .. str
end
return str
end
2016-02-28 14:50:49 +01:00
---
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
---
2016-03-01 07:07:56 +01:00
-- xor single byte
2016-02-28 14:50:49 +01:00
function xorme ( hex , xor , index )
2019-03-09 10:34:43 +01:00
if ( index >= 23 ) then
return ( '%02x' ): format ( bxor ( tonumber ( hex , 16 ) , tonumber ( xor , 16 ) ))
else
return hex
end
2016-02-28 14:50:49 +01:00
end
2017-05-17 18:52:30 +02:00
---
2016-02-28 14:50:49 +01:00
-- (de)obfuscate bytes
function xorBytes ( inBytes , crc )
2019-03-09 10:34:43 +01:00
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
2016-02-28 14:50:49 +01:00
end
2017-05-17 18:52:30 +02:00
---
2016-02-28 14:50:49 +01:00
-- check availability of file
function file_check ( file_name )
2019-05-14 11:54:25 +02:00
local file_found = io.open ( file_name , "r" )
if file_found == nil then
return false
else
file_found : close ()
return true
end
2016-02-28 14:50:49 +01:00
end
---
2016-03-20 19:25:48 +01: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 14:50:49 +01:00
end
2016-03-20 19:25:48 +01:00
return fields
2016-02-28 14:50:49 +01:00
end
---
2016-03-20 19:25:48 +01:00
-- put a string into a bytes-table
function str2bytes ( s )
2019-03-09 10:34:43 +01:00
if ( string.len ( s ) % 2 ~= 0 ) then
return print ( "stamp should be a even hexstring e.g.: deadbeef or 0badc0de" )
end
2016-03-20 19:25:48 +01:00
local res = {}
for i = 1 , string.len ( s ), 2 do
table.insert ( res , string.sub ( s , i ,( i + 1 )))
2016-02-28 14:50:49 +01:00
end
2016-03-20 19:25:48 +01:00
return res
2016-02-28 14:50:49 +01:00
end
2016-03-20 19:25:48 +01:00
---
2016-03-01 07:07:56 +01:00
-- put certain bytes into a new table
function bytesToTable ( bytes , bstart , bend )
2019-03-09 10:34:43 +01:00
local t = {}
for i = 0 , ( bend - bstart ) do
t [ i ] = bytes [ bstart + i ]
end
return t
2016-03-01 07:07:56 +01:00
end
2017-05-17 18:52:30 +02:00
---
2016-02-28 14:50:49 +01:00
-- read file into table
function getInputBytes ( infile )
2019-03-09 10:34:43 +01:00
local line
local bytes = {}
local fhi , err = io.open ( infile , "rb" )
if err then oops ( "faild to read from file " .. infile ); return false ; end
2017-05-17 18:52:30 +02:00
2019-03-09 10:34:43 +01:00
file_data = fhi : read ( "*a" );
for i = 1 , # file_data do
bytes [ i ] = string.format ( "%x" , file_data : byte ( i ))
end
fhi : close ()
if ( bytes [ 7 ] == '00' ) then return false end
print ( # bytes .. " bytes from " .. infile .. " loaded" )
return bytes
2016-02-28 14:50:49 +01:00
end
---
-- create tag-table helper
function createTagTable ()
2017-05-17 18:52:30 +02:00
local t = {
2016-02-28 14:50:49 +01: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-17 18:52:30 +02:00
---
2016-02-28 14:50:49 +01:00
-- put bytes into tag-table
function bytesToTag ( bytes , tag )
2019-03-09 10:34:43 +01:00
if istable ( tag ) == false then return oops ( "tag is no table in: bytesToTag (" .. type ( tag ) .. ")" ) end
2018-11-11 01:18:14 +01:00
2020-04-08 22:47:13 +02:00
tag.MCD = padString ( bytes [ 1 ]);
tag.MSN0 = padString ( bytes [ 2 ]);
tag.MSN1 = padString ( bytes [ 3 ]);
tag.MSN2 = padString ( bytes [ 4 ]);
tag.MCC = padString ( bytes [ 5 ]);
tag.DCFl = padString ( bytes [ 6 ]);
tag.DCFh = padString ( bytes [ 7 ]);
tag.raw = padString ( bytes [ 8 ]);
tag.SSC = padString ( bytes [ 9 ]);
2016-02-28 14:50:49 +01:00
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 09:33:21 +02:00
if ( tag.Type == "SAM" and tag.raw == '9f' ) then
2016-02-28 14:50:49 +01:00
tag.Stamp_len = ( tonumber ( 0xfc , 10 ) - tonumber ( bbit ( "0x" .. tag.DCFh , 0 , 8 ), 10 ))
2016-06-22 09:33:21 +02: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 14:50:49 +01:00
tag.data = bytesToTable ( bytes , 10 , 13 )
tag.Bck = bytesToTable ( bytes , 14 , 20 )
tag.MTC = bytesToTable ( bytes , 21 , 22 )
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
print ( acgreen .. "Tag-Type: " .. tag.Type .. acoff )
2016-02-28 14:50:49 +01:00
if ( tag.Type == "SAM" and # bytes > 23 ) then
tag = segmentsToTag ( bytes , tag )
2016-03-20 19:25:48 +01:00
print ( acgreen .. ( # tag.SEG + 1 ) .. " Segment(s) found" .. acoff )
2016-03-01 07:07:56 +01:00
-- unsegmented Master-Token
2017-05-17 18:52:30 +02:00
-- only tag-data
else
2016-03-01 07:07:56 +01:00
for i = 0 , # tag.Bck do
table.insert ( tag.data , tag.Bck [ i ])
2016-03-20 19:25:48 +01:00
end
2016-03-01 07:07:56 +01:00
tag.data [ # tag.data ] = tag.MTC [ 0 ]
tag.Bck = nil
--tag.MTC[0]=tag.MTC[1]
--tag.MTC[1]=nil
2016-02-28 14:50:49 +01:00
end
2016-03-20 19:25:48 +01:00
print ( accyan ..# bytes .. " bytes for Tag processed" .. acoff )
2016-02-28 14:50:49 +01:00
return tag
2017-07-30 09:17:48 +02:00
2016-02-28 14:50:49 +01:00
end
2017-05-17 18:52:30 +02:00
---
-- put segments from byte-table to tag-table
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
2016-02-28 14:50:49 +01:00
---
2016-03-01 07:07:56 +01:00
-- read Tag-Table in bytes-table
function tagToBytes ( tag )
2019-03-09 10:34:43 +01:00
if istable ( tag ) == false then return oops ( "tag is no table in tagToBytes (" .. type ( tag ) .. ")" ) end
2018-11-11 01:18:14 +01:00
2016-03-01 07:07:56 +01: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-20 19:25:48 +01:00
end
2016-03-01 07:07:56 +01:00
-- backup data
if ( istable ( tag.Bck )) then
for i = 0 , # tag.Bck do
table.insert ( bytes , tag.Bck [ i ])
2016-02-28 14:50:49 +01:00
end
2016-03-20 19:25:48 +01:00
end
2016-03-01 07:07:56 +01:00
-- token-create-time / master-token crc
for i = 0 , # tag.MTC do
table.insert ( bytes , tag.MTC [ i ])
2016-03-20 19:25:48 +01:00
end
2016-03-01 07:07:56 +01: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-20 19:25:48 +01:00
end
2016-03-01 07:07:56 +01: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-20 19:25:48 +01:00
end
2016-02-28 14:50:49 +01:00
end
end
2016-03-01 07:07:56 +01:00
-- fill with zeros
for i =# bytes + 1 , 1024 do
table.insert ( bytes , i , '00' )
end
return bytes
end
2016-02-28 14:50:49 +01:00
2020-04-08 22:47:13 +02:00
---
2016-03-20 19:25:48 +01:00
--- PM3 I/O ---
-- write virtual Tag to real Tag
function writeToTag ( tag )
2019-03-09 10:34:43 +01:00
local bytes
local taglen = 22
2020-04-08 22:47:13 +02:00
local writeDCF = false
if ( utils.confirm ( acred .. " \n Place the (empty) Tag onto the PM3 \n and confirm writing to this Tag: " .. acoff ) == false ) then
2019-03-09 10:34:43 +01:00
return
end
2020-04-08 22:47:13 +02:00
if ( utils.confirm ( acred .. " \n Should the decremental field (DCF) be written?: " .. acoff ) == true ) then
writeDCF = true
end
2018-11-11 12:34:59 +01:00
2019-03-09 10:34:43 +01:00
-- get used bytes / tag-len
if ( istable ( tag.SEG )) then
if ( istable ( tag.Bck )) then
for i = 0 , # tag.SEG do
2020-04-08 22:47:13 +02:00
taglen = taglen + tag.SEG [ i ] . len
2019-03-09 10:34:43 +01:00
end
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)
if ( istable ( tag.Bck )) then
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
end
end
end
bytes = tagToBytes ( tag )
-- master-token-crc
if ( tag.Type ~= "SAM" ) then
bytes [ 22 ] = calcMtCrc ( bytes )
end
if ( bytes ) then
2020-04-08 22:47:13 +02:00
bytes = xorBytes ( bytes , tag.MCC )
2019-03-09 10:34:43 +01:00
end
end
2020-04-08 22:47:13 +02:00
2019-03-09 10:34:43 +01:00
-- write data to file
if ( taglen > 0 ) then
2019-05-14 11:42:58 -04:00
WriteBytes = input ( acyellow .. "enter number of bytes to write?" .. acoff , taglen )
2019-03-09 10:34:43 +01:00
-- write pm3-buffer to Tag
2020-04-08 22:47:13 +02:00
for i = 1 , WriteBytes do
if ( i > 7 ) then
cmd = ( "hf legic wrbl o %02x d %s " ): format ( i - 1 , padString ( bytes [ i ]))
2019-03-09 10:34:43 +01:00
print ( acgreen .. cmd .. acoff )
core.console ( cmd )
core.clearCommandBuffer ()
2020-04-08 22:47:13 +02:00
elseif ( i == 7 ) then
if ( writeDCF ) then
-- write DCF in reverse order (requires 'mosci-patch')
cmd = ( 'hf legic wrbl o 05 d %s%s' ): format ( padString ( bytes [ i - 1 ]), padString ( bytes [ i ]))
print ( acgreen .. cmd .. acoff )
core.console ( cmd )
core.clearCommandBuffer ()
else
print ( acgreen .. "skip byte 0x05-0x06 - DCF" .. acoff )
end
2019-03-09 10:34:43 +01:00
elseif ( i == 6 ) then
print ( acgreen .. "skip byte 0x05 - will be written next step" .. acoff )
else
print ( acgreen .. "skip byte 0x00-0x04 - unwritable area" .. acoff )
end
utils.Sleep ( 0.2 )
end
end
2016-03-20 19:25:48 +01:00
end
--- File I/O ---
---
-- read file into virtual-tag
2019-01-26 19:10:29 +01:00
local function readFile ( filename )
2019-03-09 10:34:43 +01:00
print ( accyan )
local bytes = {}
local tag = {}
if file_check ( filename ) == false then
2019-05-14 11:42:58 -04:00
return oops ( "input file: " .. acyellow .. filename .. acoff .. " not found" )
2019-03-09 10:34:43 +01:00
end
2018-11-11 01:18:14 +01:00
2019-03-09 10:34:43 +01:00
bytes = getInputBytes ( filename )
2018-11-11 01:18:14 +01:00
2019-03-09 10:34:43 +01:00
if bytes == false then return oops ( 'couldnt get input bytes' ) end
2017-07-30 09:17:48 +02:00
2019-03-09 10:34:43 +01:00
-- 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 )
2018-11-11 01:18:14 +01:00
2019-03-09 10:34:43 +01:00
return tag
2016-03-20 19:25:48 +01:00
end
2019-05-14 11:54:25 +02:00
local function save_BIN ( data , filename )
local outfile
local counter = 1
2020-04-08 22:47:13 +02:00
local ext = ".bin"
local fn = filename .. ext
2019-05-14 17:13:29 +02:00
2019-05-14 11:54:25 +02:00
-- Make sure we don't overwrite a file
while file_check ( fn ) do
2020-04-08 22:47:13 +02:00
fn = filename .. ext : gsub ( ext , "-" .. tostring ( counter ) .. ext )
2019-05-14 11:54:25 +02:00
counter = counter + 1
end
2019-05-14 17:13:29 +02:00
2019-05-14 11:54:25 +02:00
outfile = io.open ( fn , 'wb' )
local i = 1
2019-05-14 17:13:29 +02:00
while data [ i ] do
local byte = string.char ( tonumber ( data [ i ], 16 ))
outfile : write ( byte )
2019-05-14 11:54:25 +02:00
i = i + 1
end
outfile : close ()
2019-05-14 17:13:29 +02:00
return fn , # data
2019-05-14 11:54:25 +02:00
end
2017-05-17 18:52:30 +02:00
---
2016-03-20 19:25:48 +01:00
-- write bytes to file
function writeFile ( bytes , filename )
2020-04-08 22:47:13 +02:00
local emlext = ".eml"
if ( filename ~= 'MyLegicClone' ) then
if ( file_check ( filename .. emlext )) then
local answer = confirm ( " \n the output-file " .. filename .. emlext .. " already exists! \n this will delete the previous content! \n continue?" )
2019-03-09 10:34:43 +01:00
if not answer then return print ( "user abort" ) end
end
end
local line
local bcnt = 0
2020-04-08 22:47:13 +02:00
local fho , err = io.open ( filename .. emlext , "w" )
2019-03-09 10:34:43 +01:00
if err then
2020-04-08 22:47:13 +02:00
return oops ( "OOps ... failed to open output-file " .. filename .. emlext )
2019-03-09 10:34:43 +01:00
end
2019-05-14 11:54:25 +02:00
2019-03-09 10:34:43 +01:00
bytes = xorBytes ( bytes , bytes [ 5 ])
2019-05-14 11:42:58 -04:00
2019-03-09 10:34:43 +01:00
for i = 1 , # bytes do
if ( bcnt == 0 ) then
2020-04-08 22:47:13 +02:00
line = padString ( bytes [ i ])
2019-03-09 10:34:43 +01:00
elseif ( bcnt <= 7 ) then
2020-04-08 22:47:13 +02:00
line = line .. " " .. padString ( bytes [ i ])
2019-03-09 10:34:43 +01:00
end
if ( bcnt == 7 ) then
-- write line to new file
fho : write ( line .. " \n " )
-- reset counter & line
bcnt = - 1
line = ""
end
bcnt = bcnt + 1
end
fho : close ()
2019-05-14 11:42:58 -04:00
2019-05-14 11:54:25 +02:00
-- save binary
2019-05-14 17:13:29 +02:00
local fn_bin , fn_bin_num = save_BIN ( bytes , filename )
2019-05-14 11:42:58 -04:00
2020-04-08 22:47:13 +02:00
print ( " \n wrote " .. acyellow .. ( # bytes * 3 ) .. acoff .. " bytes to " .. acyellow .. filename .. emlext .. acoff )
2019-05-14 11:42:58 -04:00
2019-05-14 17:13:29 +02:00
if fn_bin and fn_bin_num then
print ( " \n wrote " .. acyellow .. fn_bin_num .. acoff .. " bytes to BINARY file " .. acyellow .. fn_bin .. acoff )
end
2019-05-14 11:42:58 -04:00
2019-03-09 10:34:43 +01:00
return true
2016-03-20 19:25:48 +01:00
end
2020-04-08 22:47:13 +02:00
---
-- read from pm3 into virtual-tag
function readFromPM3 ()
local tag , bytes , infile
--infile="legic.temp"
infile = os.tmpname ()
core.console ( "hf legic dump f " .. infile )
tag = readFile ( infile .. ".bin" )
os.remove ( infile )
os.remove ( infile .. ".bin" )
os.remove ( infile .. ".eml" )
os.remove ( infile .. ".json" )
return tag
end
2016-03-20 19:25:48 +01:00
--- Map related ---
2017-05-17 18:52:30 +02:00
---
2016-03-20 19:25:48 +01:00
-- make tagMap
2019-01-26 19:10:29 +01:00
local function makeTagMap ()
2019-03-09 10:34:43 +01:00
local tagMap = {}
if ( # tagMap == 0 ) then
tagMap [ 'name' ] = input ( accyan .. "enter Name for this Map: " .. acoff , "newTagMap" )
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 )
return tagMap
2017-05-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
---
-- save mapping to file
2019-01-26 19:10:29 +01:00
local function saveTagMap ( map , filename )
2019-05-14 11:42:58 -04:00
if # filename > 0 then
if file_check ( filename ) then
local answer = confirm ( " \n the output-file " .. acyellow .. filename .. acoff .. " alredy exists! \n this will delete the previous content! \n continue?" )
2019-03-09 10:34:43 +01:00
if not answer then return print ( "user abort" ) end
end
end
2017-05-17 18:52:30 +02:00
2019-03-09 10:34:43 +01:00
local line
local fho , err = io.open ( filename , "w" )
2019-05-14 11:42:58 -04:00
if err then oops ( "OOps ... faild to open output-file " .. acyellow .. filename .. acoff ) end
2017-05-17 18:52:30 +02:00
2019-03-09 10:34:43 +01: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
2016-03-20 19:25:48 +01:00
end
---
-- toggle higligh
2019-01-26 19:10:29 +01:00
local function toggleHighlight ( tbl )
2019-03-09 10:34:43 +01:00
if ( tbl [ 'highlight' ]) then
tbl [ 'highlight' ] = false
else
tbl [ 'highlight' ] = true
end
return tbl
2016-03-20 19:25:48 +01:00
end
---
-- return table od seqence-string
2019-01-26 19:10:29 +01:00
local function seqstr2tbl ( seqstr )
2019-03-09 10:34:43 +01:00
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
2016-03-20 19:25:48 +01:00
end
---
-- return sequence-string from table
2019-01-26 19:10:29 +01:00
local function tbl2seqstr ( seqtbl )
2019-03-09 10:34:43 +01:00
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
2016-03-20 19:25:48 +01:00
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
2019-05-14 11:42:58 -04:00
if not file_check ( filename ) then
return oops ( "input file: " .. acyellow .. filename .. acoff .. " not found" )
2019-03-09 10:34:43 +01:00
else
local fhi , err = io.open ( filename )
while true do
line = fhi : read ()
if line == nil then
2017-05-17 18:52:30 +02:00
break
2016-03-20 19:25:48 +01:00
else
2019-05-14 11:42:58 -04:00
fields = split ( line )
2016-03-20 19:25:48 +01:00
end
2019-05-14 11:42:58 -04:00
if ( # fields == 2 ) then
if ( fields [ 1 ] == 'offset' ) then
offset = tonumber ( fields [ 2 ], 10 )
2016-03-20 19:25:48 +01:00
end
-- map-name
2017-05-17 18:52:30 +02:00
map [ fields [ 1 ]] = fields [ 2 ]
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
if ( temp [ 'start' ] > 22 ) then
temp [ 'start' ] = temp [ 'start' ] + offset
temp [ 'end' ] = temp [ 'end' ] + offset
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
temp [ 'seq' ][ k ] = tonumber ( v , 10 )
end
2016-03-20 19:25:48 +01:00
table.insert ( map.crc8 , temp )
end
2019-03-09 10:34:43 +01:00
end
fhi : close ()
end
2016-03-20 19:25:48 +01:00
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-17 18:52:30 +02:00
temp = ""
2016-03-20 19:25:48 +01:00
for k2 , v2 in pairs ( tagMap.crc8 [ n ]) do
if ( istable ( v2 )) then
temp = temp .. tbl2seqstr ( v2 )
end
2017-05-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
end
end
return res
end
---
-- edit existing Map
function editTagMap ( tag , tagMap )
local t = [[
2017-05-17 18:52:30 +02:00
Data: dm = show dr = dump raw
2016-03-20 19:25:48 +01:00
Mappings: im = insert am = add rm = remove
2017-05-17 18:52:30 +02:00
CRC8: ac8 = add sc8 = show rc8 = remove
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
repeat
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
elseif ( x == 'rc8' ) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
elseif ( string.sub ( x , 1 , 3 ) == 'sc8' ) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
if ( string.len ( x ) >= 9 ) then
2016-03-20 19:25:48 +01:00
pos = tonumber ( string.sub ( x , 5 , 8 ), 10 )
2017-05-17 18:52:30 +02:00
x = string.sub ( x , 9 , string.len ( x ))
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
elseif ( check4MapCrc8 ( i , tagMap )) then
2016-03-20 19:25:48 +01:00
if ( checkMapCrc8 ( tagMap , bytes , isPosCrc8 ( tagMap , i ) ) ) then
io.write ( "" .. acgreen )
2017-05-17 18:52:30 +02:00
else
2016-03-20 19:25:48 +01:00
io.write ( "" .. acred )
end
2017-05-17 18:52:30 +02:00
else
io.write ( "" .. acoff )
2016-03-20 19:25:48 +01:00
end
-- highlighted mapping
if ( check4Highlight ( i , tagMap )) then io.write ( "" .. acmagenta ) end
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
io.write ( bytes [ i ])
2017-05-17 18:52:30 +02:00
if ( i % 8 == 0 ) then io.write ( " \n " )
2016-03-20 19:25:48 +01:00
else io.write ( " " ) end
end
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
io.write ( " \n " .. acoff )
end
---
-- show bytes used for crc-calculation
function getSequences ( bytes , seqstr )
2017-08-13 15:06:30 +02: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-20 19:25:48 +01:00
local res = ""
if ( # seqs > 0 ) then
for k , v in pairs ( seqs ) do
local seq = split ( v , '-' )
2017-08-13 15:06:30 +02:00
if ( # seq >= 2 ) then
for i = seq [ 1 ], seq [ 2 ] do
res = res .. bytes [ i ] .. " "
2016-03-20 19:25:48 +01:00
end
end
2017-08-13 15:06:30 +02:00
if ( string.len ( res ) > 0 ) then res = res .. " " end
2016-03-20 19:25:48 +01: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 )
2019-05-14 11:42:58 -04:00
local res = false
2016-03-20 19:25:48 +01:00
for _ , v in pairs ( tagMap.mappings ) do
if ( addr >= v [ 'start' ] and addr <= v [ 'end' ] ) then
2019-05-14 11:42:58 -04:00
res = v [ 'highlight' ]
2016-03-20 19:25:48 +01:00
end
end
return res
end
---
-- add interactive mapping
function addMapping ( tag , tagMap , x )
2017-08-13 15:06:30 +02:00
if ( type ( x ) ~= "number" ) then x = # tagMap.mappings + 1 end
local bytes = tagToBytes ( tag )
2019-05-14 11:42:58 -04:00
local myMapping = {}
2017-08-13 15:06:30 +02: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-17 18:52:30 +02:00
table.insert ( tagMap.mappings , x , myMapping )
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
return tagMap
2016-03-20 19:25:48 +01:00
end
---
-- select a mapping from a tagmap
function selectTableEntry ( table , action )
2017-08-13 15:06:30 +02:00
if ( type ( action ) ~= "string" ) then action = "select number of item:" end
2016-03-20 19:25:48 +01: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
2019-03-09 10:34:43 +01:00
-- 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 )
2016-03-20 19:25:48 +01:00
--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-17 18:52:30 +02:00
if ( WRC > WRP ) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
end
print ( # segs .. " Segments mapped" )
else
oops ( "autoMapSegments failed: no Segments found" )
end
return tagMap
end
2017-05-17 18:52:30 +02:00
---
2016-03-20 19:25:48 +01:00
-- map all token data
function mapTokenData ( tagMap , mname , mstart , mend , mhigh )
--if ( not mhigh ) then mhigh=false end
2019-05-14 11:42:58 -04:00
local myMapping = {}
myMapping [ 'name' ] = mname
myMapping [ 'start' ] = mstart
myMapping [ 'end' ] = mend
myMapping [ 'highlight' ] = mhigh
2017-05-17 18:52:30 +02:00
table.insert ( tagMap.mappings , myMapping )
2016-03-20 19:25:48 +01: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 09:33:21 +02:00
if ( tag.Type == "SAM" and tag.raw == '9f' ) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
-- credential (end-user tag)
2016-06-22 09:33:21 +02:00
if ( tag.Type == "SAM" and tag.raw == '9f' ) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
-- Master Token specific
2016-06-22 09:33:21 +02:00
elseif ( tag.Type ~= "SAM" ) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-06-22 09:33:21 +02: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-20 19:25:48 +01:00
end
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
return res
2019-05-14 11:42:58 -04:00
else print ( acred .. "no valid Tag in dumpCDF" .. acoff ) end
2016-03-20 19:25:48 +01:00
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-17 18:52:30 +02:00
if ( ( istable ( tag.SEG [ i ])) and tag.Type == "SAM" and tag.raw == "9f" ) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
if ( tag.SEG [ i ]. kgh ) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
return res
2016-03-20 19:25:48 +01:00
else
2019-05-14 11:42:58 -04:00
return print ( acred .. "Segment not found" .. acoff )
2016-03-20 19:25:48 +01: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
2019-03-09 10:34:43 +01:00
if ( # header == 0 ) then
return res
else
return ( header .. " #" .. ( tend - tstart + 1 ) .. " \n " .. res )
end
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
test = ""
-- display decoded/known stuff
print ( " \n ------------------------------" )
print ( "Tag-ID: \t\t " .. uid )
2017-05-17 18:52:30 +02:00
print ( "Stamp: \t\t " .. stamp )
2016-03-20 19:25:48 +01: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-17 18:52:30 +02: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-20 19:25:48 +01: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-17 18:52:30 +02: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-20 19:25:48 +01: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-17 18:52:30 +02: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-20 19:25:48 +01: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-17 18:52:30 +02: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-20 19:25:48 +01:00
print ( string.format ( "Balance: \t\t %3.2f" , balance / 100 ) .. " " .. "(" .. compareCrc ( balancecrc , tag.SEG [ seg ]. data [ 34 ]) .. ")" )
2017-05-17 18:52:30 +02: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-20 19:25:48 +01:00
end
---
-- dump Legic-Cash data
function dumpLegicCash ( tag , x )
2018-11-11 01:18:14 +01:00
2019-03-09 10:34:43 +01:00
if istable ( tag.SEG [ x ]) == false then return end
2018-11-11 01:18:14 +01:00
2016-03-20 19:25:48 +01: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 09:17:48 +02:00
2019-03-09 10:34:43 +01:00
if istable ( tag.SEG [ x ]) == false then return end
2018-11-11 01:18:14 +01:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02: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-20 19:25:48 +01:00
print ()
2017-05-17 18:52:30 +02:00
print ( " \t\t yet unknown: " .. tag.SEG [ x ]. data [ 45 ])
2016-03-20 19:25:48 +01: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 --
2016-02-28 14:50:49 +01:00
---
2016-03-01 07:07:56 +01:00
-- 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 15:06:30 +02:00
ttype = ttype .. k .. ") " .. v .. " "
2016-03-20 19:25:48 +01:00
end
2017-08-13 15:06:30 +02: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-01 07:07:56 +01:00
else print ( "Token-Type '" .. mt.Type [ mtq ] .. "' selected" ) end
2017-08-13 15:06:30 +02:00
local raw = calcHeaderRaw ( mt.WRP [ mtq ], mt.WRC [ mtq ], mt.RD [ mtq ])
local mtCRC = "00"
2017-05-17 18:52:30 +02:00
2017-08-13 15:06:30 +02:00
bytes = { "01" , "02" , "03" , "04" , "cb" , string.sub ( mt.DCF [ mtq ], 0 , 2 ), string.sub ( mt.DCF [ mtq ], 3 ), raw ,
2016-03-01 07:07:56 +01:00
"00" , "00" , "00" , "00" , "00" , "00" , "00" , "00" ,
"00" , "00" , "00" , "00" , "00" , "00" }
2017-08-13 15:06:30 +02:00
if ( mtq == 1 ) then
for i = 0 , # mt.Segment do
2016-03-01 07:07:56 +01:00
table.insert ( bytes , mt.Segment [ i ])
end
2017-08-13 15:06:30 +02:00
bytes [ 9 ] = "ff"
2016-03-20 19:25:48 +01:00
end
2016-03-01 07:07:56 +01:00
-- fill bytes
2017-08-13 15:06:30 +02:00
for i = # bytes , 1023 do table.insert ( bytes , "00" ) end
2016-03-01 07:07:56 +01:00
-- if Master-Token -> calc Master-Token-CRC
2017-08-13 15:06:30 +02:00
if ( mtq > 1 ) then bytes [ 22 ] = calcMtCrc ( bytes ) end
2018-11-11 01:18:14 +01:00
2017-08-13 15:06:30 +02:00
local tempTag = createTagTable ()
2016-03-01 07:07:56 +01:00
-- remove segment if MasterToken
2017-08-13 15:06:30 +02:00
if ( mtq > 1 ) then tempTag.SEG [ 0 ] = nil end
2018-11-11 01:18:14 +01:00
2016-03-01 07:07:56 +01:00
return bytesToTag ( bytes , tempTag )
2016-03-20 19:25:48 +01:00
end
2017-05-17 18:52:30 +02:00
---
2016-03-01 07:07:56 +01:00
-- edit token-data
function editTag ( tag )
-- for simulation it makes sense to edit everything
2017-08-13 15:06:30 +02:00
local edit_sim = "MCD MSN0 MSN1 MSN2 MCC DCFl DCFh WRP WRC RD"
2016-03-01 07:07:56 +01:00
-- on real tags it makes only sense to edit DCF, WRP, WRC, RD
2017-08-13 15:06:30 +02:00
local edit_real = "DCFl DCFh WRP WRC RD"
2016-03-20 19:25:48 +01:00
if ( confirm ( acyellow .. "do you want to edit non-writeable values (e.g. for simulation)?" .. acoff )) then
2017-08-13 15:06:30 +02:00
edit_tag = edit_sim
else edit_tag = edit_real end
2017-05-17 18:52:30 +02:00
2016-03-01 07:07:56 +01:00
if ( istable ( tag )) then
for k , v in pairs ( tag ) do
2017-08-13 15:06:30 +02: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-02-28 14:50:49 +01:00
end
end
2017-05-17 18:52:30 +02:00
2017-08-13 15:06:30 +02:00
if ( tag.Type == "SAM" ) then ttype = "Header" ; else ttype = "Stamp" ; end
2016-03-20 19:25:48 +01:00
if ( confirm ( acyellow .. "do you want to edit " .. ttype .. " Data?" .. acoff )) then
2016-03-01 07:07:56 +01:00
-- master-token specific
2017-08-13 15:06:30 +02:00
if ( istable ( tag.Bck ) == false ) then
2016-03-01 07:07:56 +01: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 15:06:30 +02:00
tag.data [ i ] = input ( ttype .. i + 1 .. ": " , tag.data [ i ])
2017-05-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
else
2017-05-17 18:52:30 +02:00
--- on credentials byte7 should always be 9f and byte8 ff
2016-03-01 07:07:56 +01:00
-- on Master-Token not (even on SAM63/64 not)
-- tag.SSC=input(ttype.."0: ", tag.SSC)
for i = 0 , # tag.data do
2017-08-13 15:06:30 +02:00
tag.data [ i ] = input ( ttype .. i .. ": " , tag.data [ i ])
2016-03-20 19:25:48 +01:00
end
end
end
2017-05-17 18:52:30 +02:00
2017-08-13 15:06:30 +02:00
bytes = tagToBytes ( tag )
2017-05-17 18:52:30 +02:00
2016-03-01 07:07:56 +01:00
--- check data-consistency (calculate tag.raw)
2017-08-13 15:06:30 +02:00
bytes [ 8 ] = calcHeaderRaw ( tag.WRP , tag.WRC , tag.RD )
2017-05-17 18:52:30 +02:00
2016-03-01 07:07:56 +01: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 15:06:30 +02:00
if ( tag.Type ~= "SAM" or bytes [ 6 ] .. bytes [ 7 ] ~= "60ea" ) then
2016-03-01 07:07:56 +01:00
-- calc new Master-Token crc
2017-08-13 15:06:30 +02:00
bytes [ 22 ] = calcMtCrc ( bytes )
2016-03-01 07:07:56 +01:00
else
-- ensure tag.SSC set to 'ff' on credential-token (SAM)
2017-08-13 15:06:30 +02:00
bytes [ 9 ] = 'ff'
2016-03-01 07:07:56 +01: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 15:06:30 +02:00
bytes [ 21 ] = '00'
bytes [ 22 ] = '00'
2016-03-20 19:25:48 +01:00
end
2017-05-17 18:52:30 +02:00
2017-08-13 15:06:30 +02:00
tag = bytesToTag ( bytes , tag )
2016-02-28 14:50:49 +01:00
end
end
---
2016-03-01 07:07:56 +01:00
-- calculates header-byte (addr 0x07)
function calcHeaderRaw ( wrp , wrc , rd )
2017-08-13 15:06:30 +02: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 07:07:56 +01:00
return res
2016-02-28 14:50:49 +01:00
end
2017-05-17 18:52:30 +02:00
---
2016-03-20 19:25:48 +01:00
-- determine TagType (bits 0..6 of DCFlow)
function getTokenType ( DCFl )
--[[
2017-05-17 18:52:30 +02:00
0x00– 0x2f IAM
0x30– 0x6f SAM
2016-03-20 19:25:48 +01: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
2016-02-28 14:50:49 +01:00
end
2016-03-20 19:25:48 +01:00
---
-- clear beackup-area of a virtual tag
function clearBackupArea ( tag )
for i = 1 , # tag.Bck do
tag.Bck [ i ] = '00'
end
return tag
end
--- Segment related --
2016-02-28 14:50:49 +01: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-17 18:52:30 +02:00
if ( bytes [ start ]) then
local i
2016-02-28 14:50:49 +01:00
-- #index
2019-03-09 10:34:43 +01:00
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)
2016-02-28 14:50:49 +01:00
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 ]}
2019-03-09 10:34:43 +01:00
-- 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 ]
2016-02-28 14:50:49 +01:00
-- 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-17 18:52:30 +02:00
else return false ;
2016-02-28 14:50:49 +01:00
end
end
2016-03-20 19:25:48 +01:00
---
2017-05-17 18:52:30 +02:00
-- get index, start-aadr, length and content
2016-03-20 19:25:48 +01:00
function getSegmentStats ( bytes )
local sStats = {}
local sValid , sLast , sLen , sStart , x
sStart = 23
x = 0
repeat
local s = {}
2019-03-09 10:34:43 +01:00
-- 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)
2016-03-20 19:25:48 +01:00
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 14:50:49 +01:00
---
2016-03-01 07:07:56 +01:00
-- regenerate segment-header (after edit)
function regenSegmentHeader ( segment )
local seg = segment
local raw = segment.raw
2016-03-20 19:25:48 +01:00
local i
2016-03-01 07:07:56 +01: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-20 19:25:48 +01: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 07:07:56 +01:00
-- WRP
raw [ 3 ] = ( "%02x" ): format ( bbit ( "0x" .. ( "%02x" ): format ( seg.WRP ), 0 , 8 ))
-- WRC + RD
2016-03-20 19:25:48 +01:00
raw [ 4 ] = ( "%02x" ): format ( tonumber (( seg.WRC * 16 ) + ( seg.RD * 128 ), 10 ))
2016-03-01 07:07:56 +01: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-20 19:25:48 +01: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 07:07:56 +01:00
for i = ( seg.len - 5 ), # seg.data - 1 do
table.remove ( seg.data )
2016-03-20 19:25:48 +01:00
end
2016-03-01 07:07:56 +01:00
elseif ( # seg.data < ( seg.len - 5 )) then
print ( "current payload: " .. # seg.data .. " - desired payload: " .. seg.len - 5 )
2016-03-20 19:25:48 +01: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 07:07:56 +01:00
table.insert ( seg.data , '00' )
2016-03-20 19:25:48 +01:00
end
2016-02-28 14:50:49 +01:00
end
2016-03-01 07:07:56 +01:00
return seg
end
2016-02-28 14:50:49 +01:00
---
-- 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-20 19:25:48 +01:00
tag.SEG [ index ][ k ] = tonumber ( input ( accyan .. k .. acoff .. ": " , v ), 10 )
2016-02-28 14:50:49 +01:00
end
end
else print ( "Segment with Index: " .. ( "%02d" ): format ( index ) .. " not found in Tag" )
return false
end
2017-05-17 18:52:30 +02:00
regenSegmentHeader ( tag.SEG [ index ])
2016-02-28 14:50:49 +01:00
print ( " \n " .. dumpSegment ( tag , index ) .. " \n " )
return tag
end
---
-- edit Segment Data
function editSegmentData ( data )
2019-03-09 10:34:43 +01:00
io.write ( " \n " )
if istable ( data ) == false then print ( "no Segment-Data found" ) end
2017-07-30 09:17:48 +02:00
2019-03-09 10:34:43 +01:00
local lc = check4LegicCash ( data )
2017-07-30 09:17:48 +02:00
2016-02-28 14:50:49 +01:00
for i = 0 , # data - 1 do
2019-03-09 10:34:43 +01:00
data [ i ] = input ( accyan .. "Data" .. i .. acoff .. ": " , data [ i ])
2017-05-17 18:52:30 +02:00
end
2019-03-09 10:34:43 +01:00
if ( lc ) then
data = fixLegicCash ( data )
end
return data
2016-02-28 14:50:49 +01:00
end
---
-- list available segmets in virtual tag
function segmentList ( tag )
local i
2017-05-17 18:52:30 +02:00
local res = ""
2016-02-28 14:50:49 +01: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-17 18:52:30 +02:00
if ( istable ( tag.SEG [ 0 ])) then
2016-02-28 14:50:49 +01: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-17 18:52:30 +02:00
2016-02-28 14:50:49 +01: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-20 19:25:48 +01:00
-- get only the stamp-bytes of a segment
2016-03-06 13:26:13 +01:00
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-17 18:52:30 +02:00
-- there a no stamps longer than 7 bytes & they are write-protected by default , and I have not seen user-credntials
2016-03-06 13:26:13 +01:00
-- with stamps smaller 3 bytes (except: Master-Token)
2017-05-17 18:52:30 +02:00
-- WRP -> Read/Write Protection
2016-03-06 13:26:13 +01: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 ]
end
2017-05-17 18:52:30 +02:00
if ( bytes ) then
2016-03-06 13:26:13 +01:00
stamp = str2bytes ( stamp )
return stamp
else return stamp end
end
2016-03-20 19:25:48 +01:00
---
-- edit stamp of a segment
2016-03-06 13:26:13 +01:00
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 )
end
2016-03-20 19:25:48 +01:00
---
-- autoselect special/known segments
2016-03-06 13:26:13 +01:00
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-17 18:52:30 +02:00
repeat
2016-03-06 13:26:13 +01:00
io.write ( ". " )
x = x - 1
res = check43rdPartyCash1 ( uid , tag.SEG [ x ]. data )
until ( res or x == 0 )
2017-05-17 18:52:30 +02:00
end
2016-03-06 13:26:13 +01:00
-- Legic-Cash Segment
if ( s == "legiccash" ) then
2017-05-17 18:52:30 +02:00
repeat
2016-03-06 13:26:13 +01: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-17 18:52:30 +02:00
-- nothing found
io.write ( acyellow .. "no Segment found \n " .. acoff )
return - 1
2016-03-06 13:26:13 +01:00
end
2016-03-20 19:25:48 +01: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
end
end
---
-- edit uid 3rd party cash
function edit3rdUid ( mapid , uid , data )
mapid = ( "%06x" ): format ( tonumber ( mapid , 10 ))
data [ 46 ] = string.sub ( mapid , 1 , 2 )
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
---
-- 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 )
end
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-17 18:52:30 +02:00
end
return tag
2016-03-20 19:25:48 +01:00
end
---
-- 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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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 )
end
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
return fixLegicCash ( data )
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
io.write ( accyan .. "Legic-Cash Segment detected " .. acoff )
return true
end
end
end
end
end
return false
end
---
-- 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-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
end
return false
end
--- CRC related ---
---
-- build segmentCrc credentials
2017-05-17 18:52:30 +02:00
function segmentCrcCredentials ( tag , segid )
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
function kghCrcCredentials ( tag , segid )
2016-03-20 19:25:48 +01: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
---
-- calculate Master-Token crc
2017-05-17 18:52:30 +02:00
function calcMtCrc ( bytes )
2016-03-20 19:25:48 +01: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
---
-- 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-17 18:52:30 +02:00
-- calcuate kghCRC for a given segment
2016-03-20 19:25:48 +01: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
---
2017-07-30 09:17:48 +02:00
-- check all segment-crc
2016-03-20 19:25:48 +01: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
else return print ( acyellow .. "Master-Token / unsegmented Tag" .. acoff ) end
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-17 18:52:30 +02:00
if ( tag.SEG [ i ]. kgh ) then
2016-03-20 19:25:48 +01:00
tag.SEG [ i ]. data [ # tag.SEG [ i ]. data - 1 ] = crc
end
end
end
end
---
-- validate segmentCRC for a given segment
function checkSegmentCrc ( tag , segid )
local data = segmentCrcCredentials ( tag , segid )
2017-05-17 18:52:30 +02:00
if (( "%02x" ): format ( utils.Crc8Legic ( data )) == tag.SEG [ segid ]. crc ) then
2016-03-20 19:25:48 +01:00
return true
end
return false
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-17 18:52:30 +02:00
if (( "%02x" ): format ( utils.Crc8Legic ( data )) == tag.SEG [ segid ]. data [ tag.SEG [ segid ]. len - 5 - 1 ]) then return true ; end
2016-03-20 19:25:48 +01:00
else return false ; end
else oops ( acred .. "'Kaba Group header' detected but no Segment-Data found" .. ansocolors.reset ) end
end
---
-- helptext for modify-mode
function modifyHelp ()
local t = [[
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
File I/O rs => remove Segment
----------------- cc => check Segment-CRC
2020-04-08 22:47:13 +02:00
lf => load bin File ck => check KGH
sf => save eml/bin File ds => dump Segments
2017-05-17 18:52:30 +02:00
xf => xor to File
Virtual Tags tagMap (partial) known Segments
2016-03-20 19:25:48 +01:00
-------------------------------- --------------------- ---------------------------
2017-05-17 18:52:30 +02: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-20 19:25:48 +01:00
tt => switch mainTag & backupTag lm => load map from file d3p => dump 3rd-Party-Cash
di => dump mainTag sm => save map to file e3p => edit 3rd-Party-Cash
2017-05-17 18:52:30 +02:00
do => dump backupTag
2016-03-20 19:25:48 +01:00
h => this help q => quit
2017-05-17 18:52:30 +02:00
]]
2016-03-20 19:25:48 +01:00
return t
end
2017-05-17 18:52:30 +02:00
---
2016-03-20 19:25:48 +01:00
-- modify Tag (interactive)
function modifyMode ()
local i , backupTAG , outTAG , inTAG , outfile , infile , sel , segment , bytes , outbytes , tagMap
2017-05-17 18:52:30 +02:00
2016-03-20 19:25:48 +01:00
actions = {
---
-- helptext
2017-05-17 18:52:30 +02:00
[ "h" ] = function ( x )
print ( " Version: " .. version );
2016-03-20 19:25:48 +01: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 "" ))
end ,
---
-- read real Tag with PM3 into virtual 'mainTAG'
2017-05-17 18:52:30 +02:00
[ "rt" ] = function ( x )
inTAG = readFromPM3 ();
--actions.di()
2016-03-20 19:25:48 +01:00
end ,
---
-- write content of virtual 'mainTAG' to real Tag with PM3
2017-05-17 18:52:30 +02:00
[ "wt" ] = function ( x )
2016-03-20 19:25:48 +01:00
writeToTag ( inTAG )
end ,
---
2017-05-17 18:52:30 +02:00
-- copy mainTAG to backupTAG
[ "ct" ] = function ( x )
print ( accyan .. "copy mainTAG to backupTAG" .. acoff )
2016-03-20 19:25:48 +01:00
backupTAG = deepCopy ( inTAG )
end ,
---
-- copy backupTAG to mainTAG
2017-05-17 18:52:30 +02:00
[ "tc" ] = function ( x )
2016-03-20 19:25:48 +01:00
print ( accyan .. "copy backupTAG to mainTAG" .. acoff )
inTAG = deepCopy ( backupTAG )
end ,
---
-- toggle between mainTAG and backupTAG
2017-05-17 18:52:30 +02:00
[ "tt" ] = function ( x )
2016-03-20 19:25:48 +01: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 )
end ,
---
-- load file into mainTAG
2017-05-17 18:52:30 +02:00
[ "lf" ] = function ( x )
2018-11-11 01:18:14 +01:00
if ( type ( x ) == 'string' and file_check ( x )) then
2019-03-09 10:34:43 +01:00
filename = x
2017-07-30 09:17:48 +02:00
else
2019-03-09 10:34:43 +01:00
filename = input ( "enter filename: " , "legic.temp" )
end
2016-03-20 19:25:48 +01:00
inTAG = readFile ( filename )
-- 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-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
end ,
---
-- save values of mainTAG to a file (xored with MCC of mainTAG)
2017-05-17 18:52:30 +02:00
[ "sf" ] = function ( x )
2019-05-14 11:42:58 -04:00
if istable ( inTAG ) then
2020-04-08 22:47:13 +02:00
outfile = input ( "enter filename:" , "hf-legic-" .. inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2 )
2019-05-14 11:42:58 -04:00
bytes = tagToBytes ( inTAG )
2016-03-20 19:25:48 +01:00
--bytes=xorBytes(bytes, inTAG.MCC)
2020-04-08 22:47:13 +02:00
if ( bytes ) then
2016-03-20 19:25:48 +01:00
writeFile ( bytes , outfile )
end
end
end ,
---
2017-05-17 18:52:30 +02:00
-- save values of mainTAG to a file (xored with 'specific' MCC)
[ "xf" ] = function ( x )
2019-05-14 11:42:58 -04:00
if istable ( inTAG ) then
2020-04-08 22:47:13 +02:00
outfile = input ( "enter filename:" , "hf-legic-" .. inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2 )
2019-05-14 11:42:58 -04:00
crc = input ( "enter new crc: ('00' for a plain dump)" , inTAG.MCC )
print ( "obfuscate with: " .. crc )
2016-03-20 19:25:48 +01:00
bytes = tagToBytes ( inTAG )
bytes [ 5 ] = crc
2017-05-17 18:52:30 +02:00
if ( bytes ) then
2016-03-20 19:25:48 +01:00
writeFile ( bytes , outfile )
end
end
end ,
---
-- dump mainTAG (and all Segments)
2017-05-17 18:52:30 +02:00
[ "di" ] = function ( x )
if ( istable ( inTAG )) then
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
io.write ( accyan .. "in Segment index: " .. inTAG.SEG [ i ]. index .. acoff .. " \n " )
2016-03-20 19:25:48 +01:00
elseif ( check4LegicCash ( inTAG.SEG [ i ]. data )) then
io.write ( accyan .. "in Segment index: " .. inTAG.SEG [ i ]. index .. acoff .. " \n " )
2017-05-17 18:52:30 +02:00
lc = true ;
2016-03-20 19:25:48 +01:00
lci = inTAG.SEG [ i ]. index ;
end
end
end
2017-05-17 18:52:30 +02:00
print ( " \n " .. dumpTag ( inTAG ) .. " \n " )
2016-03-20 19:25:48 +01:00
if ( lc ) then actions [ "dlc" ]( lci ) end
lc = false
2017-05-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
end ,
---
-- dump backupTAG (and all Segments)
[ "do" ] = function ( x ) if ( istable ( backupTAG )) then print ( " \n " .. dumpTag ( backupTAG ) .. " \n " ) end end ,
---
-- create a empty tagMap
2017-05-17 18:52:30 +02:00
[ "mm" ] = function ( x )
2016-03-20 19:25:48 +01:00
-- clear existing tagMap and init
2017-05-17 18:52:30 +02:00
if ( istable ( inTAG )) then
2016-03-20 19:25:48 +01:00
tagMap = makeTagMap ()
end
end ,
---
-- edit a tagMap
2017-05-17 18:52:30 +02: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-20 19:25:48 +01:00
else return
2017-05-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
end
2017-05-17 18:52:30 +02:00
if ( istable ( tagMap ) == false ) then actions [ 'mm' ]() end
2016-03-20 19:25:48 +01:00
-- edit
tagMap = editTagMap ( inTAG , tagMap )
end ,
---
-- save a tagMap
2017-05-17 18:52:30 +02:00
[ "sm" ] = function ( x )
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
else
2016-03-20 19:25:48 +01:00
print ( acyellow .. "no mappings in tagMap!" .. acoff )
end
2017-05-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
end ,
---
-- load a tagMap
2017-05-17 18:52:30 +02:00
[ "lm" ] = function ( x )
2019-05-14 11:42:58 -04:00
tagMap = loadTagMap ( input ( accyan .. "enter filename:" .. acoff , "Legic.map" ))
2016-03-20 19:25:48 +01:00
end ,
---
-- dump single segment
2017-05-17 18:52:30 +02:00
[ "ds" ] = function ( x )
2018-11-11 01:18:14 +01:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2019-03-09 10:34:43 +01:00
sel = tonumber ( x , 10 )
2018-11-11 01:18:14 +01:00
else
2019-03-09 10:34:43 +01:00
sel = selectSegment ( inTAG )
end
2017-05-17 18:52:30 +02:00
if ( sel ) then print ( " \n " .. ( dumpSegment ( inTAG , sel ) or acred .. "no Segments available" ) .. acoff .. " \n " ) end
2016-03-20 19:25:48 +01:00
end ,
---
-- edit segment header
2017-05-17 18:52:30 +02:00
[ "es" ] = function ( x )
2016-03-20 19:25:48 +01:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then sel = tonumber ( x , 10 )
else sel = selectSegment ( inTAG ) end
2017-05-17 18:52:30 +02:00
if ( sel ) then
2016-03-20 19:25:48 +01:00
if ( istable ( inTAG.SEG [ 0 ])) then
inTAG = editSegment ( inTAG , sel )
inTAG.SEG [ sel ] = regenSegmentHeader ( inTAG.SEG [ sel ])
2019-03-09 10:34:43 +01:00
else
print ( acyellow .. "no Segments in Tag" .. acoff )
end
2016-03-20 19:25:48 +01:00
end
end ,
---
-- add segment
2017-05-17 18:52:30 +02:00
[ "as" ] = function ( x )
2016-03-20 19:25:48 +01:00
if ( istable ( inTAG.SEG [ 0 ])) then
inTAG = addSegment ( inTAG )
inTAG.SEG [ # inTAG.SEG - 1 ] = regenSegmentHeader ( inTAG.SEG [ # inTAG.SEG - 1 ])
2017-05-17 18:52:30 +02:00
inTAG.SEG [ # inTAG.SEG ] = regenSegmentHeader ( inTAG.SEG [ # inTAG.SEG ])
2016-03-20 19:25:48 +01:00
else print ( accyan .. "Master-Token / unsegmented Tag!" .. acoff )
end
end ,
---
-- remove segment
2017-05-17 18:52:30 +02:00
[ "rs" ] = function ( x )
2016-03-20 19:25:48 +01: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
inTAG = delSegment ( inTAG , sel )
for i = 0 , # inTAG.SEG do
inTAG.SEG [ i ] = regenSegmentHeader ( inTAG.SEG [ i ])
end
end
end ,
---
-- edit data-portion of single segment
2017-05-17 18:52:30 +02:00
[ "ed" ] = function ( x )
2016-03-20 19:25:48 +01:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then sel = tonumber ( x , 10 )
else sel = selectSegment ( inTAG ) end
2017-05-17 18:52:30 +02:00
if ( istable ( inTAG.SEG [ sel ])) then
inTAG.SEG [ sel ]. data = editSegmentData ( inTAG.SEG [ sel ]. data )
2016-03-20 19:25:48 +01:00
end
end ,
---
-- edit Tag (MCD, MSN, MCC etc.)
2017-05-17 18:52:30 +02:00
[ "et" ] = function ( x )
2016-03-20 19:25:48 +01:00
if ( istable ( inTAG )) then
editTag ( inTAG )
end
end ,
---
-- make (dummy) Token
[ "mt" ] = function ( x ) inTAG = makeToken (); actions.di () end ,
---
-- fix segment-crc on single segment
2017-05-17 18:52:30 +02:00
[ "ts" ] = function ( x )
2016-03-20 19:25:48 +01:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then sel = tonumber ( x , 10 )
else sel = selectSegment ( inTAG ) end
2017-05-17 18:52:30 +02:00
regenSegmentHeader ( inTAG.SEG [ sel ])
2016-03-20 19:25:48 +01:00
end ,
---
2017-05-17 18:52:30 +02:00
-- toggle kgh-crc-flag on a single segment
[ "tk" ] = function ( x )
2016-03-20 19:25:48 +01:00
if ( istable ( inTAG ) and istable ( inTAG.SEG [ 0 ])) then
2018-11-11 01:18:14 +01:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2019-03-09 10:34:43 +01:00
sel = tonumber ( x , 10 )
2018-11-11 01:18:14 +01:00
else
2019-03-09 10:34:43 +01:00
sel = selectSegment ( inTAG )
end
if ( inTAG.SEG [ sel ]. kgh ) then
inTAG.SEG [ sel ]. kgh = false
else
inTAG.SEG [ sel ]. kgh = true
end
2016-03-20 19:25:48 +01:00
end
end ,
---
-- calculate LegicCrc8
[ "k" ] = function ( x )
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2017-05-17 18:52:30 +02:00
print (( "%02x" ): format ( utils.Crc8Legic ( x )))
2016-03-20 19:25:48 +01:00
end
end ,
---
-- noop
[ "xb" ] = function ( x )
end ,
---
2017-05-17 18:52:30 +02:00
-- print string for LegicCrc8-calculation about single segment
[ "xc" ] = function ( x )
2016-03-20 19:25:48 +01:00
if ( istable ( inTAG ) and istable ( inTAG.SEG [ 0 ])) then
2017-07-30 09:17:48 +02:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2019-03-09 10:34:43 +01:00
sel = tonumber ( x , 10 )
2017-07-30 09:17:48 +02:00
else
2019-03-09 10:34:43 +01:00
sel = selectSegment ( inTAG )
end
2017-05-17 18:52:30 +02:00
print ( "k " .. kghCrcCredentials ( inTAG , sel ))
end
2016-03-20 19:25:48 +01:00
end ,
---
-- fix legic-cash checksums
2017-05-17 18:52:30 +02:00
[ "flc" ] = function ( x )
2018-11-11 01:18:14 +01:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2019-03-09 10:34:43 +01:00
x = tonumber ( x , 10 )
2017-07-30 09:17:48 +02:00
else
2019-03-09 10:34:43 +01:00
x = selectSegment ( inTAG )
end
2016-03-20 19:25:48 +01:00
inTAG.SEG [ x ]. data = fixLegicCash ( inTAG.SEG [ x ]. data )
end ,
---
-- edit legic-cash values fixLegicCash(data)
2017-05-17 18:52:30 +02:00
[ "elc" ] = function ( x )
2016-03-20 19:25:48 +01:00
x = autoSelectSegment ( inTAG , "legiccash" )
inTAG.SEG [ x ]. data = editLegicCash ( inTAG.SEG [ x ]. data )
end ,
---
-- dump legic-cash human-readable
2017-05-17 18:52:30 +02:00
[ "dlc" ] = function ( x )
2016-03-20 19:25:48 +01:00
-- if segment index was user defined
2017-05-17 18:52:30 +02:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2016-03-20 19:25:48 +01:00
x = tonumber ( x , 10 )
print ( string.format ( "User-Selected Index %02d" , x ))
2017-07-30 09:17:48 +02:00
else
2016-03-20 19:25:48 +01:00
-- or try to find match
2019-03-09 10:34:43 +01:00
x = autoSelectSegment ( inTAG , "legiccash" )
end
2016-03-20 19:25:48 +01:00
-- dump it
dumpLegicCash ( inTAG , x )
end ,
---
-- dump 3rd-party-cash-segment
[ "d3p" ] = function ( x )
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
-- if segment index was user defined
2017-05-17 18:52:30 +02:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2016-03-20 19:25:48 +01:00
x = tonumber ( x , 10 )
print ( string.format ( "User-Selected Index %02d" , x ))
2017-07-30 09:17:48 +02:00
else
2016-03-20 19:25:48 +01:00
-- or try to find match
2019-03-09 10:34:43 +01:00
x = autoSelectSegment ( inTAG , "3rdparty" )
end
2016-03-20 19:25:48 +01: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 ,
---
-- dump 3rd-party-cash-segment (raw blocks and checksums over 'known areas')
[ "r3p" ] = function ( x )
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
-- if segment index was user defined
2017-05-17 18:52:30 +02:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2016-03-20 19:25:48 +01:00
x = tonumber ( x , 10 )
print ( string.format ( "User-Selected Index %02d" , x ))
2017-07-30 09:17:48 +02:00
else
2016-03-20 19:25:48 +01:00
-- or try to find match
2019-03-09 10:34:43 +01:00
x = autoSelectSegment ( inTAG , "3rdparty" )
end
2016-03-20 19:25:48 +01:00
print3rdPartyCash1 ( inTAG , x )
end ,
---
-- edit 3rd-party-cash-segment values (Balance, Mapping-UID, Stamp)
2017-05-17 18:52:30 +02:00
[ "e3p" ] = function ( x )
2016-03-20 19:25:48 +01:00
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
-- if segment index was user defined
2017-05-17 18:52:30 +02:00
if ( type ( x ) == "string" and string.len ( x ) > 0 ) then
2016-03-20 19:25:48 +01:00
x = tonumber ( x , 10 )
print ( string.format ( "User-Selected Index %02d" , x ))
2018-11-11 01:18:14 +01:00
2017-07-30 09:17:48 +02:00
else
2016-03-20 19:25:48 +01:00
-- or try to find match
2019-03-09 10:34:43 +01:00
x = autoSelectSegment ( inTAG , "3rdparty" )
end
2016-03-20 19:25:48 +01:00
if ( istable ( inTAG ) and istable ( inTAG.SEG [ x ]) and inTAG.SEG [ x ]. len == 100 ) then
inTAG = edit3rdPartyCash1 ( inTAG , x )
dump3rdPartyCash1 ( inTAG , x )
end
end ,
---
-- force fixing 3rd-party-checksums
2017-05-17 18:52:30 +02:00
[ "f3p" ] = function ( x )
2017-07-30 09:17:48 +02:00
if ( type ( x ) == "string" and string.len ( x ) >= 2 ) then
2019-03-09 10:34:43 +01:00
x = tonumber ( x , 10 )
else
x = selectSegment ( inTAG )
end
2017-05-17 18:52:30 +02:00
if ( istable ( inTAG.SEG [ x ])) then
2016-03-20 19:25:48 +01:00
local uid = inTAG.MCD .. inTAG.MSN0 .. inTAG.MSN1 .. inTAG.MSN2
inTAG.SEG [ x ]. data = fix3rdPartyCash1 ( uid , inTAG.SEG [ x ]. data )
2017-05-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
end ,
---
2017-05-17 18:52:30 +02:00
-- get stamp from single segment
2016-03-20 19:25:48 +01:00
[ "gs" ] = function ( x )
2018-11-11 01:18:14 +01:00
if ( type ( x ) == "string" and string.len ( x ) >= 2 ) then
2019-03-09 10:34:43 +01:00
x = tonumber ( x , 10 )
2017-07-30 09:17:48 +02:00
else
2019-03-09 10:34:43 +01:00
x = selectSegment ( inTAG )
end
2016-03-20 19:25:48 +01:00
local stamp = getSegmentStamp ( inTAG.SEG [ x ])
print ( "Stamp : " .. stamp )
stamp = str2bytes ( stamp )
2019-07-23 21:40:01 +02:00
print ( "length: " ..# stamp )
2016-03-20 19:25:48 +01:00
end ,
---
-- calculate crc16
2017-05-17 18:52:30 +02:00
[ "c6" ] = function ( x ) local crc16 = string.format ( "%4.04x" , utils.Crc16 ( x ))
2016-03-20 19:25:48 +01:00
print ( string.sub ( crc16 , 0 , 2 ) .. " " .. string.sub ( crc16 , 3 , 4 ))
end ,
---
-- 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-17 18:52:30 +02:00
[ "cb" ] = function ( x )
2016-03-20 19:25:48 +01:00
if ( istable ( inTAG )) then
print ( accyan .. "purge BackupArea" .. acoff )
2017-05-17 18:52:30 +02:00
inTAG = clearBackupArea ( inTAG )
end
end ,
2016-03-20 19:25:48 +01: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-17 18:52:30 +02:00
[ "tac" ] = function ( x )
if ( colored_output ) then
2016-03-20 19:25:48 +01:00
colored_output = false
else
colored_output = true
2017-05-17 18:52:30 +02:00
end
2016-03-20 19:25:48 +01:00
load_colors ( colored_output )
end ,
}
2017-05-17 18:52:30 +02:00
repeat
2019-05-18 17:53:08 +02:00
-- default message / prompt
2016-03-20 19:25:48 +01:00
ic = input ( "Legic command? ('h' for help - 'q' for quit)" , "h" )
-- command actions decisions (first match, longer commands before shorter)
if ( type ( actions [ string.lower ( string.sub ( ic , 0 , 3 ))]) == 'function' ) then
actions [ string.lower ( string.sub ( ic , 0 , 3 ))]( string.sub ( ic , 5 ))
elseif ( type ( actions [ string.lower ( string.sub ( ic , 0 , 2 ))]) == 'function' ) then
actions [ string.lower ( string.sub ( ic , 0 , 2 ))]( string.sub ( ic , 4 ))
elseif ( type ( actions [ string.lower ( string.sub ( ic , 0 , 1 ))]) == 'function' ) then
actions [ string.lower ( string.sub ( ic , 0 , 1 ))]( string.sub ( ic , 3 ))
2018-11-11 01:18:14 +01:00
else
2019-03-09 10:34:43 +01:00
actions.h ( '' )
end
2016-03-20 19:25:48 +01:00
until ( string.sub ( ic , 0 , 1 ) == "q" )
end
---
-- main function
2016-02-28 14:50:49 +01:00
function main ( args )
2016-03-20 19:25:48 +01:00
-- set init colors/switch (can be toggled with 'tac' => 'toggle ansicolors')
load_colors ( colored_output )
2019-03-09 10:34:43 +01:00
if ( # args == 0 ) then modifyMode () end
2016-02-28 14:50:49 +01:00
--- variables
2016-03-06 13:26:13 +01:00
local inTAG , backupTAG , outTAG , outfile , interactive , crc , ofs , cfs , dfs
2019-03-09 10:34:43 +01:00
-- just a spacer for better readability
2016-02-28 14:50:49 +01:00
print ()
--- parse arguments
2019-03-09 10:34:43 +01:00
for o , a in getopt.getopt ( args , 'hrmi:do:c:' ) do
2016-02-28 14:50:49 +01:00
-- display help
if o == "h" then return help (); end
-- read tag from PM3
if o == "r" then inTAG = readFromPM3 () end
-- input file
2019-03-09 10:34:43 +01:00
if o == "i" then inTAG = readFile ( a ) end
2017-05-17 18:52:30 +02:00
-- dump virtual-Tag
2016-02-28 14:50:49 +01:00
if o == "d" then dfs = true end
-- interacive modifying
2018-11-11 01:18:14 +01:00
if o == "m" then
2019-03-09 10:34:43 +01:00
interactive = true
modifyMode ()
end
2016-02-28 14:50:49 +01:00
-- xor (e.g. for clone or plain file)
2018-11-11 01:18:14 +01:00
if o == "c" then
2019-03-09 10:34:43 +01:00
cfs = true
crc = a
end
2016-02-28 14:50:49 +01:00
-- output file
2019-03-09 10:34:43 +01:00
if o == "o" then
outfile = a
ofs = true
end
2016-02-28 14:50:49 +01:00
end
2017-05-17 18:52:30 +02:00
2016-02-28 14:50:49 +01:00
-- file conversion (output to file)
2019-03-09 10:34:43 +01:00
if ofs == false then return end
2018-11-11 01:18:14 +01:00
2016-02-28 14:50:49 +01:00
-- dump infile / tag-read
2017-05-17 18:52:30 +02:00
if ( dfs ) then
print ( "-----------------------------------------" )
2016-02-28 14:50:49 +01:00
print ( dumpTag ( inTAG ))
end
2017-07-30 09:17:48 +02:00
2016-02-28 14:50:49 +01:00
bytes = tagToBytes ( inTAG )
2017-05-17 18:52:30 +02:00
if ( cfs ) then
2016-03-01 07:07:56 +01:00
-- xor willl be done in function writeFile
-- with the value of byte[5]
2017-05-17 18:52:30 +02:00
bytes [ 5 ] = crc
2016-02-28 14:50:49 +01:00
end
2017-07-30 09:17:48 +02:00
2016-02-28 14:50:49 +01:00
-- write to outfile
2017-05-17 18:52:30 +02:00
if ( bytes ) then
2016-02-28 14:50:49 +01:00
writeFile ( bytes , outfile )
2017-05-17 18:52:30 +02:00
--- read real tag into virtual tag
2016-03-01 07:07:56 +01:00
-- inTAG=readFromPM3() end
--- or simply use the bytes that where wriiten
2016-02-28 14:50:49 +01:00
inTAG = bytesToTag ( bytes , inTAG )
-- show new content
2017-05-17 18:52:30 +02:00
if ( dfs ) then
2016-02-28 14:50:49 +01:00
print ( "-----------------------------------------" )
2017-05-17 18:52:30 +02:00
print ( dumpTag ( inTAG ))
2016-02-28 14:50:49 +01:00
end
end
2017-05-17 18:52:30 +02:00
2016-02-28 14:50:49 +01:00
end
2016-03-20 19:25:48 +01:00
---
-- script start
2018-11-11 01:18:14 +01:00
main ( args )