Merge pull request #1327 from Pondorasti/patch-1
[RRG-proxmark3.git] / client / luascripts / lf_em4100_bulk.lua
blob87d8bc91bfd1c41fcbf827cde9b5cf3064248d85
1 local getopt = require('getopt')
2 local utils = require('utils')
3 local ac = require('ansicolors')
5 copyright = ''
6 author = "Christian Herrmann"
7 version = 'v1.0.2'
8 desc = [[
9 Perform bulk EM410x enrollment of T5577 RFID tags. It keeps track of last card id used.
10 If called with -s, this value resets "session".
12 if press <enter> it defaults to Y, which writes a ID.
13 Any other input char will exit the script.
15 You can supply a password, which will set the config block / block 7 on the T5577.
17 The verify option will issue a 'lf em 410x reader' command, so you can manually verify
18 that the write worked.
21 example = [[
22 -- resets and start enrolling EM410x id 11CC334455
23 script run lf_em4100_bulk.lua -s 11CC334455
25 -- continue enrolling from where last iteration
26 script run lf_em4100_bulk.lua -c
28 -- reset and start enrolling from 11223344,
29 -- protecting the tag with password 010203
30 -- and verify the em id write.
31 script run lf_em4100_bulk.lua -s 1122334455 -p 01020304 -v
33 usage = [[
34 script run lf_en4100_bulk.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
36 arguments = [[
37 -h : this help
38 -c : continue from last card number used
39 -p : Password protecting the T5577.
40 -s : starting card number
41 -v : verify write by executing a `lf em 410x reader`
44 -- Some globals
45 local DEBUG = false
46 local ENROLL_STATUS_FN = 'lf_em4100_status.txt'
47 ---
48 -- A debug printout-function
49 local function dbg(args)
50 if not DEBUG then return end
51 if type(args) == 'table' then
52 local i = 1
53 while args[i] do
54 dbg(args[i])
55 i = i+1
56 end
57 else
58 print('###', args)
59 end
60 end
61 ---
62 -- This is only meant to be used when errors occur
63 local function oops(err)
64 print('ERROR:', err)
65 core.clearCommandBuffer()
66 return nil, errr
67 end
68 ---
69 -- Usage help
70 local function help()
71 print(copyright)
72 print(author)
73 print(version)
74 print(desc)
75 print(ac.cyan..'Usage'..ac.reset)
76 print(usage)
77 print(ac.cyan..'Arguments'..ac.reset)
78 print(arguments)
79 print(ac.cyan..'Example usage'..ac.reset)
80 print(example)
81 end
82 ---
83 -- Exit message
84 local function exitMsg(msg)
85 print( string.rep('--',20) )
86 print( string.rep('--',20) )
87 print(msg)
88 print()
89 end
90 ---
92 local function readfile()
93 local f = io.open(ENROLL_STATUS_FN, "r")
94 if f == nil then
95 return nil, string.format("Could not read file %s", ENROLL_STATUS_FN)
96 end
97 local t = f:read("*all")
98 f:close()
99 local cn_hi = tonumber(t:sub(1, 2), 16)
100 local cn_low = tonumber(t:sub(3, 10), 16)
101 print(('Using EM4100 ID '..ac.green..'%02X%08X'..ac.reset..' from `'..ac.yellow..'%s'..ac.reset..'`'):format(cn_hi, cn_low, ENROLL_STATUS_FN))
102 return cn_hi, cn_low
106 local function writefile(cn_hi, cn_low)
107 local f = io.open(ENROLL_STATUS_FN, "w")
108 if f == nil then
109 return nil, string.format("Could not write to file %s", ENROLL_STATUS_FN)
111 f:write(("%02X%08X\n"):format(cn_hi, cn_low))
112 f:close()
113 print(('Wrote EM4100 ID '..ac.green..'%02X%08X'..ac.reset..' to `'..ac.yellow..'%s'..ac.reset..'`'):format(cn_hi, cn_low, ENROLL_STATUS_FN))
114 return true, 'Ok'
118 -- main
119 local function main(args)
121 print( string.rep('--',20) )
122 print( string.rep('--',20) )
123 print()
125 if #args == 0 then return help() end
127 local shall_verify = false
128 local shall_continue = false
129 local got_pwd = false
130 local startid = ''
131 local ipwd = ''
134 for o, a in getopt.getopt(args, 'cp:s:hv') do
135 if o == 'h' then return help() end
136 if o == 'c' then shall_continue = true end
137 if o == 's' then startid = a end
138 if o == 'p' then
139 ipwd = a
140 got_pwd = true
142 if o == 'v' then shall_verify = true end
145 -- if reset/start over, check -s
146 if not shall_continue then
147 if startid == nil then return oops('empty card number string') end
148 if #startid == 0 then return oops('empty card number string') end
149 if #startid ~= 10 then return oops('card number wrong length. Must be 5 hex bytes') end
152 if got_pwd then
153 if ipwd == nil then return oops('empty password') end
154 if #ipwd == 0 then return oops('empty password') end
155 if #ipwd ~= 8 then return oops('password wrong length. Must be 4 hex bytes') end
158 core.console('clear')
159 print(ac.red..'disable hints for less output'..ac.reset)
160 core.console('pref set hint --off')
161 print('')
163 local hi = tonumber(startid:sub(1, 2), 16)
164 local low = tonumber(startid:sub(3, 10), 16)
165 local pwd = tonumber(ipwd, 16)
167 if got_pwd then
168 print(('Will protect T5577 with password '..ac.green..'%08X'..ac.reset):format(pwd))
171 if shall_verify then
172 print('Will verify write afterwards')
175 if shall_continue then
176 print('Continue enrolling from last save')
177 hi, low = readfile()
178 else
179 print('reset & starting enrolling from refresh')
182 local template = 'EM4100 ID '..ac.green..'%02X%08X'..ac.reset
183 for i = low, low + 10000, 1 do
184 print('')
185 print( string.rep('--',20) )
186 local msg = (template):format(hi, i)
187 local ans = utils.input(msg, 'y'):lower()
188 if ans == 'y' then
189 core.console( ('lf em 410x clone --id %02X%08X'):format(hi, i) )
190 -- print ( ('lf em 410x clone --id %02X%08X'):format(hi, i) )
192 if got_pwd then
193 core.console('lf t55 detect')
194 core.console(('lf t55 protect -n %08x'):format(pwd))
197 if shall_verify then
198 core.console('lf em 410x reader')
200 else
201 print(ac.red..'User aborted'..ac.reset)
202 low = i
203 break
206 writefile(hi, low)
208 print('enabling hints again')
209 core.console('pref set hint --on')
212 main(args)