2021-05-03 22:14:09 +02:00
local cmds = require ( 'commands' )
local getopt = require ( 'getopt' )
local utils = require ( 'utils' )
local json = require ( 'dkjson' )
local ac = require ( 'ansicolors' )
copyright = ''
author = "Christian Herrmann"
2023-01-08 19:27:41 +01:00
version = 'v1.0.1'
2021-05-03 22:14:09 +02:00
desc = [[
This script loads a json format file, with the field "data" and a hexbyte array of data. Ie t55x7 dump,
it tries to identify which system based on block1, and detect block0 settings.
2021-05-05 21:04:48 +02:00
The script returns a file with the new identification added, in json format. The output is save in 'dumpdata.json'
2021-05-03 22:14:09 +02:00
]]
example = [[
script run lf_ident_json -i lf_t55xx.json
]]
usage = [[
2023-01-08 19:27:41 +01:00
script run lf_ident_json.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
2021-05-03 22:14:09 +02:00
]]
arguments = [[
-h : this help
2021-05-05 21:04:48 +02:00
-i : infile ( .json format )
2021-05-03 22:14:09 +02:00
]]
-- Some globals
local DEBUG = false
2021-05-05 21:04:48 +02:00
string.startswith = function ( self , str )
2021-05-03 22:14:09 +02:00
return self : find ( '^' .. str ) ~= nil
end
2021-05-05 21:04:48 +02:00
---
2021-05-03 22:14:09 +02:00
-- A debug printout-function
local function dbg ( args )
2021-06-04 21:56:47 +02:00
if not DEBUG then return end
2021-05-03 22:14:09 +02:00
if type ( args ) == 'table' then
2021-06-04 21:56:47 +02:00
local i = 1
2021-05-03 22:14:09 +02:00
while args [ i ] do
dbg ( args [ i ])
2021-06-04 21:56:47 +02:00
i = i + 1
end
else
2021-05-03 22:14:09 +02:00
print ( '###' , args )
2021-06-04 21:56:47 +02:00
end
2021-05-05 21:04:48 +02:00
end
---
2021-05-03 22:14:09 +02:00
-- This is only meant to be used when errors occur
local function oops ( err )
print ( 'ERROR:' , err )
core.clearCommandBuffer ()
return nil , errr
end
2021-05-05 21:04:48 +02:00
---
2021-05-03 22:14:09 +02:00
-- Usage help
local function help ()
print ( copyright )
print ( author )
print ( version )
2021-06-04 21:56:47 +02:00
print ( desc )
2021-05-03 22:14:09 +02:00
print ( ac.cyan .. 'Usage' .. ac.reset )
print ( usage )
print ( ac.cyan .. 'Arguments' .. ac.reset )
print ( arguments )
print ( ac.cyan .. 'Example usage' .. ac.reset )
2021-06-04 21:56:47 +02:00
print ( example )
2021-05-03 22:14:09 +02:00
end
---
-- Exit message
local function exitMsg ( msg )
print ( string.rep ( '--' , 20 ) )
print ( string.rep ( '--' , 20 ) )
print ( msg )
print ()
end
2021-05-05 21:04:48 +02:00
--- loads a json formatted text file with
2021-05-03 22:14:09 +02:00
--
-- @param input the file containing the json-dump (defaults to dumpdata.json)
local function load_json ( input )
2021-06-04 21:56:47 +02:00
input = input or 'dumpdata.json'
local infile = io.open ( input , "rb" )
if not infile then return oops ( string.format ( "Could not read file %s" , tostring ( input ))) end
2021-05-05 21:04:48 +02:00
2021-06-04 21:56:47 +02:00
-- Read file
local t = infile : read ( "*all" )
io.close ( infile )
2021-05-03 22:14:09 +02:00
2021-06-04 21:56:47 +02:00
local obj , pos , err = json.decode ( t , 1 , nil )
if err then return oops ( string.format ( "importing json file failed. %s" , err )) end
2021-05-03 22:14:09 +02:00
2021-06-04 21:56:47 +02:00
print ( string.format ( 'loaded file %s' , input ))
return obj
2021-05-03 22:14:09 +02:00
end
--
2021-05-05 21:04:48 +02:00
-- Save
2021-05-03 22:14:09 +02:00
local function save_json ( data , filename )
2021-06-04 21:56:47 +02:00
filename = filename or 'dumpdata.json'
local outfile = io.open ( filename , "w" )
if not outfile then return oops ( string.format ( "Could not write to file %s" , tostring ( filename ))) end
outfile : write ( data )
io.close ( outfile )
return filename
2021-05-03 22:14:09 +02:00
end
2021-05-05 21:04:48 +02:00
local function encode ( blocks )
2021-06-04 21:56:47 +02:00
return json.encode ( blocks , { indent = true })
2021-05-03 22:14:09 +02:00
end
--
-- map config blocks
local function getDefault ( block0 )
2021-06-04 21:56:47 +02:00
block0 = block0 : upper ()
2021-05-03 22:14:09 +02:00
2023-06-21 18:45:59 +02:00
local T55X7_DEFAULT_CONFIG_BLOCK = '000880E8' --// compat mode, RF/32, manchester, STT, 7 data blocks
2021-06-04 21:56:47 +02:00
local T55X7_RAW_CONFIG_BLOCK = '000880E0' --// compat mode, RF/32, manchester, 7 data blocks
local T55X7_EM_UNIQUE_CONFIG_BLOCK = '00148040' --// emulate em4x02/unique - compat mode, manchester, RF/64, 2 data blocks
-- FDXB requires data inversion and BiPhase 57 is simply BipHase 50 inverted, so we can either do it using the modulation scheme or the inversion flag
-- we've done both below to prove that it works either way, and the modulation value for BiPhase 50 in the Atmel data sheet of binary "10001" (17) is a typo,
-- and it should actually be "10000" (16)
--local T55X7_FDXB_CONFIG_BLOCK 903F8080 // emulate fdx-b - xtended mode, biPhase ('57), RF/32, 4 data blocks
local T55X7_FDXB_CONFIG_BLOCK = '903F0082' --// emulate fdx-b - xtended mode, biPhase ('50), invert data, RF/32, 4 data blocks
local T55X7_HID_26_CONFIG_BLOCK = '00107060' --// hid 26 bit - compat mode, FSK2a, RF/50, 3 data blocks
local T55X7_PYRAMID_CONFIG_BLOCK = '00107080' --// Pyramid 26 bit - compat mode, FSK2a, RF/50, 4 data blocks
local T55X7_INDALA_64_CONFIG_BLOCK = '00081040' --// emulate indala 64 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 2 data block
local T55X7_INDALA_224_CONFIG_BLOCK = '000810E0' --// emulate indala 224 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 7 data block
local T55X7_GUARDPROXII_CONFIG_BLOCK = '00150060' --// Direct modulation, Biphase, RF/64, 3 data blocks
local T55X7_VIKING_CONFIG_BLOCK = '00088040' --// compat mode, manchester, RF/32, 2 data blocks
local T55X7_NORALYS_CONFIG_BLOCK = '00088C6A' --// NORALYS (KCP3000) -- compat mode, manchester, inverse, RF/32, STT, 3 data blocks
local T55X7_IOPROX_CONFIG_BLOCK = '00147040' --// HID FSK2a, RF/64, 2 data blocks
local T55X7_PRESCO_CONFIG_BLOCK = '00088088' --// manchester, RF/32, STT, 5 data blocks
local T5555_DEFAULT_CONFIG_BLOCK = '6001F004' --// ask, manchester, RF/64, 2 data blocks?
local T55X7_STARPROX = '00088C42' --// manchester, inverse, RF/32, 2 data blocks
local T55X7_VISA2K_CONFIG_BLOCK = '00148068' --// VISA2000 - manchester, RF/64, STT, 3 data blocks
local T55X7_SECURAKEY_CONFIG_BLOCK = 'F00C8060' --// Securakey - manchester, RF/40, 3 data blocks
local T55X7_ST = 'F0088058' --// manchester, RF/32, STT, pwd, 2 data blocks
2021-05-03 22:14:09 +02:00
2021-06-04 21:56:47 +02:00
if block0 == T55X7_DEFAULT_CONFIG_BLOCK then return 'T55X7_DEFAULT_CONFIG_BLOCK :: compat mode, manchester, RF/32, STT, 7 data blocks'
elseif block0 == T55X7_RAW_CONFIG_BLOCK then return 'T55X7_RAW_CONFIG_BLOCK :: compat mode, manchester, RF/32, 7 data blocks'
elseif block0 == T55X7_EM_UNIQUE_CONFIG_BLOCK then return 'T55X7_EM_UNIQUE_CONFIG_BLOCK :: emulate em4x02/unique - compat mode, manchester, RF/64, 2 data blocks'
elseif block0 == T55X7_FDXB_CONFIG_BLOCK then return 'T55X7_FDXB_CONFIG_BLOCK :: emulate fdx-b - xtended mode, BiPhase (50, invert data, RF/32, 4 data blocks'
elseif block0 == T55X7_PYRAMID_CONFIG_BLOCK then return 'T55X7_PYRAMID_CONFIG_BLOCK :: Pyramid 26 bit - compat mode, FSK2a, RF/50, 4 data blocks'
elseif block0 == T55X7_HID_26_CONFIG_BLOCK then return 'T55X7_HID_26_CONFIG_BLOCK :: hid 26 bit - compat mode, FSK2a, RF/50, 3 data blocks'
elseif block0 == T55X7_INDALA_64_CONFIG_BLOCK then return 'T55X7_INDALA_64_CONFIG_BLOCK :: emulate indala 64 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 2 data blocks'
elseif block0 == T55X7_INDALA_224_CONFIG_BLOCK then return 'T55X7_INDALA_224_CONFIG_BLOCK :: emulate indala 224 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 7 data blocks'
elseif block0 == T55X7_GUARDPROXII_CONFIG_BLOCK then return 'T55X7_GUARDPROXII_CONFIG_BLOCK :: biphase, direct modulation, RF/64, 3 data blocks'
elseif block0 == T55X7_VIKING_CONFIG_BLOCK then return 'T55X7_VIKING_CONFIG_BLOCK :: compat mode, manchester, RF/32, 2 data blocks'
elseif block0 == T55X7_NORALYS_CONFIG_BLOCK then return 'T55X7_NORALYS_CONFIG_BLOCK :: NORALYS (KCP3000) -- compat mode, manchester, inverse, RF/32, STT, 3 data blocks'
elseif block0 == T55X7_IOPROX_CONFIG_BLOCK then return 'T55X7_IOPROX_CONFIG_BLOCK :: HID FSK2a, RF/64, 2 data blocks'
elseif block0 == T55X7_PRESCO_CONFIG_BLOCK then return 'T55X7_PRESCO_CONFIG_BLOCK :: manchester, RF/32, STT, 5 data blocks'
elseif block0 == T5555_DEFAULT_CONFIG_BLOCK then return 'T5555_DEFAULT_CONFIG_BLOCK :: ask, manchester, RF/64, 2 data blocks?'
elseif block0 == T55X7_STARPROX then return 'T55X7_STARPROX :: manchester, inverse, RF/32, 2 data blocks'
elseif block0 == T55X7_VISA2K_CONFIG_BLOCK then return 'T55X7_VISA2K_CONFIG_BLOCK :: manchester, RF/64, STT, 3 data blocks'
elseif block0 == T55X7_SECURAKEY_CONFIG_BLOCK then return 'T55X7_SECURAKEY_CONFIG_BLOCK :: manchester, RF/40, 3 data blocks'
else return 'unknown configblock' .. ' ' .. block0
end
2021-05-03 22:14:09 +02:00
end
--
-- map first block0 with name
local function getConfigBlock ( block )
2021-06-04 21:56:47 +02:00
block = block : lower ()
2021-05-03 22:14:09 +02:00
local result = nil
if block : startswith ( "f20000" ) then
2021-06-04 21:56:47 +02:00
return '00088C42' , 'Card is a Viking / Starprox'
end
if block : startswith ( '9522' ) then
return '00088048' , 'Card is an unknown badge'
end
if block : startswith ( '56495332' ) then
return '00148068' , 'Card is VISA2000'
end
if block : startswith ( '1d555955' ) then
return '00107060' , 'Card is HID Prox, (Prastel MTAG, sold by ABMatic)'
end
if block : startswith ( 'bb0214ff' ) or block : startswith ( 'bb0314ff' ) then
return '00088C6A' , 'Card is Noralsy Blue, KCP3000'
end
--#If the block starts with ff8/9/a/b/c
if block : find ( '^(ff[8-9a-c])' ) then
dbg ( '#This is a regular EM 410 tag, using a FF pattern (from FF8 to FFF)' )
dbg ( '#Covering from tag 1 to tag id 9FFFFFFFFF' )
return '00148040' , 'Old rectangular Noralsy'
end
if block : startswith ( '011db' ) then
return '00107060' , 'Card is AWID'
end
if block : startswith ( 'f98c7038' ) then
return '00150060' , 'Card is Guard All/ verex'
end
if block : startswith ( 'ffff0000' ) then
return '00158040' , 'Card is Jablotron'
end
if block : startswith ( '10d00000' ) then
return '00088088' , 'Card is Presco'
end
if block : startswith ( '00010101' ) then
return '00107080' , 'Card is Pyramid'
end
2021-05-05 21:04:48 +02:00
2021-06-04 21:56:47 +02:00
return result , 'unknown tag'
2021-05-03 22:14:09 +02:00
end
2021-05-05 21:04:48 +02:00
--
2021-05-03 22:14:09 +02:00
-- The main entry point
function main ( args )
print ( string.rep ( '--' , 20 ) )
print ( string.rep ( '--' , 20 ) )
print ()
2021-05-05 21:04:48 +02:00
if # args == 0 then return help () end
2021-05-03 22:14:09 +02:00
2021-06-04 21:56:47 +02:00
local lines
local out = {}
-- Read the parameters
for o , a in getopt.getopt ( args , 'hi:' ) do
if o == "h" then return help () end
if o == "i" then lines = load_json ( a ) end
end
2021-05-05 21:04:48 +02:00
2021-06-04 21:56:47 +02:00
--for i = 1, #data do
for _ , i in pairs ( lines ) do
2021-05-05 21:04:48 +02:00
2021-06-04 21:56:47 +02:00
local index = 0
local one = {}
for ix = 1 , # i.data , 8 do
one [ 'blk_' .. index ] = i.data : sub ( ix , ix + 7 )
index = index + 1
end
2021-05-03 22:14:09 +02:00
2021-06-04 21:56:47 +02:00
local mconf , msg = getConfigBlock ( one [ "blk_1" ])
one [ "identification" ] = msg
one [ "config_desc" ] = getDefault ( one [ "blk_0" ])
2021-05-05 21:04:48 +02:00
2021-06-04 21:56:47 +02:00
if msg : find ( 'badge' ) then
print ( msg , i.data )
end
table.insert ( out , one )
end
save_json ( encode ( out ) , nil )
2021-05-03 22:14:09 +02:00
end
2021-05-05 21:04:48 +02:00
main ( args )