+ end
+ -- write data to file
+ if (taglen > 0) then
+ WriteBytes = utils.input(acyellow.."enter number of bytes to write?"..acoff, taglen)
+ -- load file into pm3-buffer
+ if (type(filename)~="string") then filename=input(acyellow.."filename to load to pm3-buffer?"..acoff,"legic.temp") end
+ cmd = 'hf legic load '..filename
+ core.console(cmd)
+ -- write pm3-buffer to Tag
+ for i=0, WriteBytes do
+ if ( i<5 or i>6) then
+ cmd = ('hf legic write 0x%02x 0x01'):format(i)
+ core.console(cmd)
+ --print(cmd)
+ elseif (i == 6) then
+ -- write DCF in reverse order (requires 'mosci-patch')
+ cmd = 'hf legic write 0x05 0x02'
+ print(acgreen..cmd..acoff)
+ core.console(cmd)
+ --print(cmd)
+ else
+ print(acgreen.."skip byte 0x05 - will be written next step"..acoff)
+ end
+ utils.Sleep(0.2)
+ end
+ end
+end
+
+--- File I/O ---
+---
+-- read file into virtual-tag
+function readFile(filename)
+ print(accyan)
+ local bytes = {}
+ local tag = {}
+ if (file_check(filename)==false) then
+ return oops("input file: "..filename.." not found")
+ else
+ bytes = getInputBytes(filename)
+ if (bytes == false) then return oops('couldnt get input bytes')
+ else
+ -- make plain bytes
+ bytes = xorBytes(bytes,bytes[5])
+ 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)
+ end
+ end
+ return tag
+end
+
+---
+-- write bytes to file
+function writeFile(bytes, filename)
+ if (filename~='MylegicClone.hex') then
+ if (file_check(filename)) then
+ local answer = confirm("\nthe output-file "..filename.." alredy exists!\nthis will delete the previous content!\ncontinue?")
+ if (answer==false) then return print("user abort") end
+ end
+ end
+ local line
+ local bcnt=0
+ local fho,err = io.open(filename, "w")
+ if err then oops("OOps ... faild to open output-file ".. filename) end
+ bytes=xorBytes(bytes, bytes[5])
+ for i = 1, #bytes do
+ if (bcnt == 0) then
+ line=bytes[i]
+ elseif (bcnt <= 7) then
+ line=line.." "..bytes[i]
+ end
+ if (bcnt == 7) then
+ -- write line to new file
+ fho:write(line.."\n")
+ -- reset counter & line
+ bcnt=-1
+ line=""
+ end
+ bcnt=bcnt+1
+ end
+ fho:close()
+ print("\nwrote ".. #bytes .." bytes to " .. filename)
+ return true
+end
+
+--- Map related ---
+---
+-- make tagMap
+function makeTagMap()
+ 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
+end
+
+---
+-- save mapping to file
+function saveTagMap(map, filename)
+ if (string.len(filename)>0) then
+ if (file_check(filename)) then
+ local answer = confirm("\nthe output-file "..filename.." alredy exists!\nthis will delete the previous content!\ncontinue?")
+ if (answer==false) then return print("user abort") end
+ end
+ end
+
+ local line
+ local fho,err = io.open(filename, "w")
+ if err then oops("OOps ... faild to open output-file ".. filename) end
+
+ -- write line to new file
+ for k, v in pairs(map) do
+ if (istable(v)) then
+ for k2, v2 in pairs(v) do
+ if (k=='mappings') then
+ fho:write(k..","..k2..","..v2['name']..","..v2['start']..","..v2['end']..","..((v2['highlight']) and "1" or "0").."\n")
+ elseif (k=="crc8") then
+ local tmp=""
+ tmp=k..","..k2..","..v2['name']..","..v2['pos']..","
+ tmp=tmp..tbl2seqstr(v2['seq'])
+ fho:write(tmp.."\n")
+ end
+ end
+ else
+ fho:write(k..","..v.."\n")
+ end
+ end
+ fho:close()
+ return true
+end
+
+---
+-- toggle higligh
+function toggleHighlight(tbl)
+ if (tbl['highlight']) then tbl['highlight']=false
+ else tbl['highlight']=true end
+ return tbl
+end
+
+---
+-- return table od seqence-string
+function seqstr2tbl(seqstr)
+ local s=split(seqstr)
+ local res={}
+ if (#s>=1) then
+ for sk, sv in pairs(s) do
+ s2=split(sv, '-')
+ if(#s2==2) then
+ table.insert(res, s2[1])
+ table.insert(res, s2[2])
+ end
+ end
+ end
+ return res
+end
+
+---
+-- return sequence-string from table
+function tbl2seqstr(seqtbl)
+ local res=""
+ if (istable(seqtbl)) then
+ for sk, sv in pairs(seqtbl) do
+ res=res..sv..((sk%2==0) and "," or "-")
+ end
+ if (string.sub(res, string.len(res))==",") then
+ res=string.sub(res, 1, string.len(res)-1)
+ end
+ end
+ return res
+end
+
+---
+-- read map-file into map
+function loadTagMap(filename)
+ local map={mappings={}, crc8={}, crc16={}}
+ local m=0
+ local c=0
+ local line, fields
+ local temp={}
+ local offset=0
+ if (file_check(filename)==false) then
+ return oops("input file: "..filename.." not found")
+ else
+ local fhi,err = io.open(filename)
+ while true do
+ line = fhi:read()
+ if line == nil then
+ break
+ else
+ fields=split(line)
+ end
+ if (#fields==2) then
+ if (fields[1]=='offset') then
+ offset=tonumber(fields[2],10)
+ end
+ -- map-name
+ map[fields[1]]=fields[2]
+ 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)
+ if(temp['start']>22) then
+ temp['start']=temp['start']+offset
+ temp['end']=temp['end']+offset
+ 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
+ temp['seq'][k]=tonumber(v, 10)
+ end
+ table.insert(map.crc8, temp)
+ end
+ end
+ fhi:close()
+ end
+ return map
+end
+
+---
+-- dump tagMap (mappings only)
+function dumpTagMap(tag, tagMap)
+ if(#tagMap.mappings>0) then
+ bytes=tagToBytes(tag)
+ local temp
+ local lastend=0
+ -- start display mappings
+ for k, v in pairs(tagMap.mappings) do
+ if ((lastend+1)<v['start']) then
+ print("...")
+ end
+ if (isPosCrc8(tagMap, v['start'])>0) then
+ if ( checkMapCrc8(tagMap, bytes, isPosCrc8(tagMap, v['start']) ) ) then
+ io.write("("..("%04d"):format(v['start']).."-"..("%04d"):format(v['end'])..") "..acgreen..v['name']..acoff..":")
+ else
+ io.write("("..("%04d"):format(v['start']).."-"..("%04d"):format(v['end'])..") "..acred..v['name']..acoff..":")
+ end
+ else
+ io.write("("..("%04d"):format(v['start']).."-"..("%04d"):format(v['end'])..") "..((v['highlight']) and acmagenta or acyellow)..v['name']..acoff..":")
+ end
+ temp=""
+ for i=((string.len(v['name']))/10), 2 do
+ temp=temp.."\t"
+ end
+ for i=v['start'], v['end'] do
+ temp=temp..bytes[i].." "
+ end
+ print(temp)
+ lastend=v['end']
+ end
+ end
+end
+
+---
+--
+function isPosCrc8(tagMap, pos)
+ local res=0
+ if (#tagMap.crc8>0) then
+ for k, v in pairs(tagMap.crc8) do
+ if(v['pos']==pos) then res=k end
+ end
+ end
+ return res
+end
+
+---
+-- check mapped crc
+function checkMapCrc8(tagMap, bytes, n)
+ local res=false
+ if (#tagMap.crc8>0) then
+ if(istable(tagMap.crc8[n])) then
+ temp=""
+ for k2, v2 in pairs(tagMap.crc8[n]) do
+ if (istable(v2)) then
+ temp=temp..tbl2seqstr(v2)
+ end
+ end
+ local tempres=""
+ local tempres=getSequences(bytes, temp)
+ tempres=("%02x"):format(utils.Crc8Legic(tempres))
+ if (bytes[tagMap.crc8[n]['pos']]==tempres) then
+ res=true
+ end
+ end
+ end
+ return res
+end
+
+---
+-- edit existing Map
+function editTagMap(tag, tagMap)
+ local t = [[
+ Data: dm = show dr = dump raw
+Mappings: im = insert am = add rm = remove
+ CRC8: ac8 = add sc8 = show rc8 = remove
+ : q = exit h = Help
+ ]]
+ --if(#tagMap.mappings==0) then oops("no mappings in tagMap"); return tagMap end
+ print("tagMap edit-mode submenu")
+ repeat
+ 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)
+ elseif (x=='rc8') then
+ 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
+ elseif (string.sub(x, 1, 3)=='sc8') then
+ local bytes=tagToBytes(tag)
+ local res, pos
+ -- trigger manually by sc8 <'4digit' checkadd> <'seqeuence-string'>
+ -- e.g.: sc8 0027 1-4,23-36
+ if (string.len(x)>=9) then
+ pos=tonumber(string.sub(x, 5, 8), 10)
+ x=string.sub(x, 9, string.len(x))
+ 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)
+ elseif (check4MapCrc8(i, tagMap)) then
+ if ( checkMapCrc8(tagMap, bytes, isPosCrc8(tagMap, i) ) ) then
+ io.write(""..acgreen)
+ else
+ io.write(""..acred)
+ end
+ else
+ io.write(""..acoff)
+ end
+ -- highlighted mapping
+ if (check4Highlight(i, tagMap)) then io.write(""..acmagenta) end
+
+ io.write(bytes[i])
+ if (i%8==0) then io.write("\n")
+ else io.write(" ") end
+ end
+
+ io.write("\n"..acoff)
+end
+
+---
+-- show bytes used for crc-calculation
+function getSequences(bytes, seqstr)
+ 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, ',')
+ local res = ""
+ if(#seqs>0) then
+ for k, v in pairs(seqs) do
+ local seq = split(v,'-')
+ if (#seq>=2) then
+ for i=seq[1], seq[2] do
+ res=res..bytes[i].." "
+ end
+ end
+ if(string.len(res)>0) then res=res.." " end
+ end
+ else
+ oops("no sequence found in '"..seqstr.."'")
+ end
+ return res
+end
+
+---
+-- check if byte-addr is a know crc
+function check4MapCrc8(addr, tagMap)
+ local res=false
+ for i=1, #tagMap.crc8 do
+ if (addr == tagMap.crc8[i]['pos']) then
+ res=true
+ end
+ end
+ return res
+end
+
+---
+-- check if byte-addr is a know crc
+function check4MapCrc16(addr, tagMap)
+ local res=false
+ for i=1, #tagMap.crc16 do
+ if (addr == tagMap.crc16[i]['pos']) then
+ res=true
+ end
+ end
+ return res
+end
+
+---
+-- check if byte is mapped or not
+function check4MappedByte(addr, tagMap)
+ local res=false
+ for _, v in pairs(tagMap.mappings) do
+ if (addr >= v['start'] and addr <= v['end'] ) then
+ res= true
+ end
+ end
+ return res
+end
+
+---
+-- check if byte is highlighted or not
+function check4Highlight(addr, tagMap)
+ local res=false
+ for _, v in pairs(tagMap.mappings) do
+ if (addr >= v['start'] and addr <= v['end'] ) then
+ res= v['highlight']
+ end
+ end
+ return res
+end
+
+---
+-- add interactive mapping
+function addMapping(tag, tagMap, x)
+ if (type(x)~="number") then x=#tagMap.mappings+1 end
+ local bytes=tagToBytes(tag)
+ local myMapping={}
+ 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")
+ table.insert(tagMap.mappings, x, myMapping)
+ 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
+ return tagMap
+end
+
+---
+-- select a mapping from a tagmap
+function selectTableEntry(table, action)
+ if (type(action)~="string") then action="select number of item:" end
+ for k, v in pairs(table) do
+ print(accyan..k..acoff.."\t-> "..accyan..v['name']..acoff)
+ end
+ local res = tonumber(input(action , 0), 10)
+ if (istable(table[res])) then
+ return res
+ else
+ return false
+ end
+end
+
+---
+-- map all segments
+function mapAllSegments(tag, tagMap)
+ local bytes=tagToBytes(tag)
+ local WRP,WRC,WRPC
+ segs=getSegmentStats(bytes)
+ if (istable(segs)) then
+ for k, v in pairs(segs) do
+ -- wrp (write proteted) = byte 2
+ WRP = tonumber(bytes[v['start']+2],16)
+ -- wrc (write control) - bit 4-6 of byte 3
+ WRC = tonumber(bbit("0x"..bytes[v['start']+3],4,3),16)
+ --tagMap=mapTokenData(tagMap, 'Segment '..("%02d"):format(v['index']).." HDR", v['start'], v['start']+3)
+ tagMap=mapTokenData(tagMap, 'Segment '..("%02d"):format(v['index']).." CRC", v['start']+4, v['start']+4, true)
+ table.insert(tagMap.crc8, {name = 'Segment '..("%02d"):format(v['index']).." CRC", pos=v['start']+4, seq={1,4,v['start'],v['start']+3}} )
+ if(WRC>WRP) then
+ 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)
+
+ end
+ print(#segs.." Segments mapped")
+ else
+ oops("autoMapSegments failed: no Segments found")
+ end
+ return tagMap
+end
+
+---
+-- map all token data
+function mapTokenData(tagMap, mname, mstart, mend, mhigh)
+ --if ( not mhigh ) then mhigh=false end
+ local myMapping={}
+ myMapping['name'] =mname
+ myMapping['start']=mstart
+ myMapping['end'] =mend
+ myMapping['highlight']=mhigh
+ table.insert(tagMap.mappings, myMapping)
+ 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.."\nCDF: System Area"..acoff
+ res= res.."\n"..dumpCDF(tag)
+ -- segments (user-token area)
+ if(tag.Type=="SAM") then
+ res = res..acyellow.."\n\nADF: 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")
+
+ -- credential (end-user tag)
+ if (tag.Type=="SAM") then
+ res = res.."Remaining Header Area\n"
+ for i=0, (#tag.data) do
+ res = res..tag.data[i].." "
+ end
+ res = res.."\nBackup Area\n"
+ for i=0, (#tag.Bck) do
+ res = res..tag.Bck[i].." "
+ end
+ res = res.."\nTime Area\n"
+ for i=0, (#tag.MTC) do
+ res = res..tag.MTC[i].." "
+ end
+
+ -- Master Token specific
+ else
+ res = res .."Master-Token Area\nStamp: "
+ res= res..tag.SSC.." "
+ for i=0, tag.Stamp_len-2 do
+ res = res..tag.data[i].." "
+ end
+ res=res.."\nunused 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.."\nMaster-Token CRC: "
+ res = res ..tag.MTC[1].." ("..((tag.MTC[1]==mtcrc) and "valid" or "error")..")"
+ end
+ return res
+ else print("no valid Tag in dumpCDF") end
+end
+
+---
+-- dump single segment
+function dumpSegment(tag, index)
+ local i=index
+ local i2
+ local dp=0 --data-position in table
+ local res="" --result
+ local raw="" --raw-header
+ -- segment
+ if ( (istable(tag.SEG[i])) and tag.Type=="SAM") then
+ if (istable(tag.SEG[i].raw)) then
+ for k,v in pairs(tag.SEG[i].raw) do
+ raw=raw..v.." "
+ end
+ end
+
+ -- segment header
+ res = res..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=""
+
+
+ -- WRC protected
+ if ((tag.SEG[i].WRC>0)) then
+ res = res .."\nWRC 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
+
+ -- WRP mprotected
+ if (tag.SEG[i].WRP>tag.SEG[i].WRC) then
+ res = res .."\nRemaining 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
+
+ -- payload
+ if (#tag.SEG[i].data-dp>0) then
+ res = res .."\nRemaining segment payload:\n"
+ for i2=dp, #tag.SEG[i].data-2 do
+ res = res..tag.SEG[i].data[dp].." "
+ dp=dp+1
+ end
+ if (tag.SEG[i].kgh) then
+ res = res..tag.SEG[i].data[dp].." (KGH: "..(checkKghCrc(tag, i) and acgreen.."valid" or acred.."error") ..acoff..")"
+ else res = res..tag.SEG[i].data[dp] end
+ end
+ dp=0
+ return res
+ else
+ return print("Segment not found")
+ 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
+ if (string.len(header)==0) then return res
+ else return (header.." #"..(tend-tstart+1).."\n"..res) end
+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)
+
+ test=""
+ -- display decoded/known stuff
+ print("\n------------------------------")
+ print("Tag-ID:\t\t "..uid)
+ print("Stamp:\t\t "..stamp)
+ print("UID-Mapping: \t\t"..("%06d"):format(tonumber(tag.SEG[seg].data[46]..tag.SEG[seg].data[47]..tag.SEG[seg].data[48], 16)))
+ 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])..")")
+ 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])..")")
+ 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])..")")
+
+ 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])..")")
+ 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])..")")
+ 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])..")")
+ 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("------------------------------")
+ print(string.format("Balance:\t\t %3.2f", balance/100).." ".."("..compareCrc(balancecrc, tag.SEG[seg].data[34])..")")
+ 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")
+end
+
+---
+-- dump Legic-Cash data
+function dumpLegicCash(tag, x)
+ if (istable(tag.SEG[x])) then
+ io.write("in Segment "..tag.SEG[x].index.." :\n")
+ print("--------------------------------\n\tLegic-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
+end
+
+---
+-- raw 3rd-party
+function print3rdPartyCash1(tag, x)
+ if (istable(tag.SEG[x])) then
+ local uid=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
+ print("\n\t\tStamp : "..dumpTable(tag.SEG[x].data, "", 0 , 2))
+ print("\t\tBlock 0: "..dumpTable(tag.SEG[x].data, "", 3 , 18))
+ print()
+ print("\t\tBlock 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\tBlock 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\tBlock 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\tyet unknown: "..tag.SEG[x].data[38])
+ print()
+ print("\t\tHisatory 1: "..dumpTable(tag.SEG[x].data, "", 39, 40))
+ print("\t\tHisatory 2: "..dumpTable(tag.SEG[x].data, "", 41, 42))
+ print("\t\tHisatory 3: "..dumpTable(tag.SEG[x].data, "", 43, 44))
+ print()
+ print("\t\tyet unknown: "..tag.SEG[x].data[45])
+ print()
+ print("\t\tKGH-UID HEX: "..dumpTable(tag.SEG[x].data, "", 46, 48))
+ print("\t\tBlock 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\tBlock 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\tBlock 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\tBlock 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\tBlock 8: "..dumpTable(tag.SEG[x].data, "", 90, 94))
+ end
+end
+
+--- Token related --
+---
+-- make token
+function makeToken()
+ local mt={
+ ['Type'] = {"SAM", "SAM63", "SAM64", "IAM", "GAM"},
+ ['DCF'] = {"60ea", "31fa", "30fa", "80fa", "f0fa"},
+ ['WRP'] = {"15", "2", "2", "2", "2"},
+ ['WRC'] = {"01", "02", "02", "00", "00"},
+ ['RD'] = {"01", "00", "00", "00", "00"},
+ ['Stamp'] = {"00", "00", "00", "00", "00"},
+ ['Segment'] = {"0d", "c0", "04", "00", "be", "01", "02", "03", "04", "01", "02", "03", "04"}
+ }
+ ttype=""
+ for k, v in pairs(mt.Type) do
+ ttype=ttype..k..") "..v.." "
+ end
+ 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!")
+ else print("Token-Type '"..mt.Type[mtq].."' selected") end
+ local raw=calcHeaderRaw(mt.WRP[mtq], mt.WRC[mtq], mt.RD[mtq])
+ local mtCRC="00"
+
+ bytes={"01", "02", "03", "04", "cb", string.sub(mt.DCF[mtq], 0, 2), string.sub(mt.DCF[mtq], 3), raw,
+ "00", "00", "00", "00", "00", "00", "00", "00",
+ "00", "00", "00", "00", "00", "00"}
+ if (mtq==1) then
+ for i=0, #mt.Segment do
+ table.insert(bytes, mt.Segment[i])
+ end
+ bytes[9]="ff"
+ end
+ -- fill bytes
+ for i=#bytes, 1023 do table.insert(bytes, "00") end
+ -- if Master-Token -> calc Master-Token-CRC
+ if (mtq>1) then bytes[22]=calcMtCrc(bytes) end
+ local tempTag=createTagTable()
+ -- remove segment if MasterToken
+ if (mtq>1) then tempTag.SEG[0]=nil end
+ return bytesToTag(bytes, tempTag)
+end
+
+---
+-- edit token-data
+function editTag(tag)
+ -- for simulation it makes sense to edit everything
+ local edit_sim="MCD MSN0 MSN1 MSN2 MCC DCFl DCFh WRP WRC RD"
+ -- on real tags it makes only sense to edit DCF, WRP, WRC, RD
+ local edit_real="DCFl DCFh WRP WRC RD"
+ if (confirm(acyellow.."do you want to edit non-writeable values (e.g. for simulation)?"..acoff)) then
+ edit_tag=edit_sim
+ else edit_tag=edit_real end
+
+ if(istable(tag)) then
+ for k,v in pairs(tag) do
+ if(type(v)~="table" and type(v)~="boolean" and string.find(edit_tag, k)) then
+ tag[k]=input("value for: "..accyan..k..acoff, v)
+ end
+ end
+
+ if (tag.Type=="SAM") then ttype="Header"; else ttype="Stamp"; end
+ if (confirm(acyellow.."do you want to edit "..ttype.." Data?"..acoff)) then
+ -- master-token specific
+ if(istable(tag.Bck)==false) then
+ -- 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
+ tag.data[i]=input(ttype.. i+1 ..": ", tag.data[i])
+ end
+ else
+ --- on credentials byte7 should always be 9f and byte8 ff
+ -- on Master-Token not (even on SAM63/64 not)
+ -- tag.SSC=input(ttype.."0: ", tag.SSC)
+ for i=0, #tag.data do
+ tag.data[i]=input(ttype.. i ..": ", tag.data[i])
+ end
+ end
+ end
+
+ bytes=tagToBytes(tag)
+
+ --- check data-consistency (calculate tag.raw)
+ bytes[8]=calcHeaderRaw(tag.WRP, tag.WRC, tag.RD)
+