added more keys (@equipter)
[RRG-proxmark3.git] / client / luascripts / hf_14b_mobib.lua
blobeda33f48f3ec5eee9ce9cb01b23a6c8977e7fd47
1 local cmds = require('commands')
2 local getopt = require('getopt')
3 local lib14b = require('read14b')
4 local utils = require('utils')
5 local iso7816 = require('7816_error')
6 local ansicolors = require('ansicolors')
8 copyright = ''
9 author = 'Iceman'
10 version = 'v1.0.2'
11 desc = [[
12 This is a script to communicate with a MOBIB tag using the '14b raw' commands
14 example = [[
15 script run hf_14b_mobib
16 script run hf_14b_mobib -b 11223344
19 usage = [[
20 script run hf_14b_mobib -h -b
22 arguments = [[
23 h this helptext
24 b raw bytes to send
27 --[[
28 This script communicates with /armsrc/iso14443b.c,
29 Check there for details about data format and how commands are interpreted on the
30 device-side.
33 local function mobib_parse(result)
34 if result.Oldarg0 >= 0 then
35 local len = result.Oldarg0 * 2
36 if len > 0 then
37 d = string.sub(result.Data, 0, len);
38 return d, nil
39 end
40 end
41 return nil, "mobib_parse failed"
42 end
43 ---
44 -- A debug printout-function
45 local function dbg(args)
46 if not DEBUG then return end
47 if type(args) == 'table' then
48 local i = 1
49 while args[i] do
50 dbg(args[i])
51 i = i+1
52 end
53 else
54 print('###', args)
55 end
56 end
57 ---
58 -- This is only meant to be used when errors occur
59 local function oops(err)
60 print('ERROR: ', err)
61 lib14b.disconnect()
62 return nil, err
63 end
64 ---
65 -- Usage help
66 local function help()
67 print(copyright)
68 print(author)
69 print(version)
70 print(desc)
71 print(ansicolors.cyan..'Usage'..ansicolors.reset)
72 print(usage)
73 print(ansicolors.cyan..'Arguments'..ansicolors.reset)
74 print(arguments)
75 print(ansicolors.cyan..'Example usage'..ansicolors.reset)
76 print(example)
77 end
79 -- helper function, give current count of items in lua-table.
80 local function tablelen(T)
81 local count = 0
82 for _ in pairs(T) do count = count + 1 end
83 return count
84 end
85 ---
86 -- helper function, gives a sorted table from table t,
87 -- order can be a seperate sorting-order function.
88 local function spairs(t, order)
89 -- collect the keys
90 local keys = {}
91 for k in pairs(t) do keys[#keys+1] = k end
93 -- if order function given, sort by it by passing the table and keys a, b,
94 -- otherwise just sort the keys
95 if order then
96 table.sort(keys, function(a,b) return order(t, a, b) end)
97 else
98 table.sort(keys)
99 end
101 -- return the iterator function
102 local i = 0
103 return function()
104 i = i + 1
105 if keys[i] then
106 return keys[i], t[keys[i]]
111 -- Sends a usbpackage , "hf 14b raw"
112 -- if it reads the response, it converts it to a lua object "Command" first and the Data is cut to correct length.
113 local function mobib_send_cmd_raw(data, ignoreresponse )
114 local flags = lib14b.ISO14B_COMMAND.ISO14B_APDU
115 data = data or ""
116 -- LEN of data, half the length of the ASCII-string hex string
117 -- 2 bytes flags
118 -- 4 bytes timeout
119 -- 2 bytes raw len
120 -- n bytes raw
121 local flags_str = ('%04x'):format(utils.SwapEndianness(('%04x'):format(flags), 16))
122 local time_str = ('%08x'):format(0)
123 local rawlen_str = ('%04x'):format(utils.SwapEndianness(('%04x'):format(( 8 + #data/2)), 16))
124 local senddata = ('%s%s%s%s'):format(flags_str, time_str, rawlen_str,data)
125 local c = Command:newNG{cmd = cmds.CMD_HF_ISO14443B_COMMAND, data = senddata}
127 local result, err = c:sendNG(ignoreresponse, 2000)
128 if result then
129 if result.Oldarg0 >= 0 then
130 return mobib_parse(result)
131 else
132 err = 'card response failed'
134 else
135 err = 'No response from card'
137 return result, err
140 -- mobib_card_num : Reads card number from ATR and
141 -- writes it in the tree in decimal format.
142 local function mobib_card_num(card)
143 if not card then return end
144 local card_num = tonumber( card.uid:sub(1,8),16 )
145 print('')
146 print('Card UID ' ..ansicolors.green..card.uid:format('%x')..ansicolors.reset)
147 print('Card Number ' ..ansicolors.green..string.format('%u', card_num)..ansicolors.reset)
148 print('-----------------------')
151 -- analyse CALYPSO apdu status bytes.
152 local function mobib_apdu_status(apdu)
153 -- last two is CRC
154 -- next two is APDU status bytes.
155 local mess = 'FAIL'
156 local sw = apdu:sub( #apdu-7, #apdu-4)
157 desc, err = iso7816.tostring(sw)
158 --print ('SW', sw, desc, err )
159 local status = ( sw == '9000' )
160 return status, desc, err
163 local CLA = '00'
164 local _calypso_cmds = {
165 ['01.SELECT AID 1TIC.ICA'] = CLA..'a4 0400 08 315449432e494341',
166 ['02.Select ICC file a'] = CLA..'a4 0000 02 3f00',
167 ['03.Select ICC file b'] = CLA..'a4 0000 02 0002',
168 ['04.ICC'] = CLA..'b2 0104 1d',
169 ['05.Select Holder file'] = CLA..'a4 0000 02 3f1c',
170 ['06.Holder1'] = CLA..'b2 0104 1d',
171 ['07.Holder2'] = CLA..'b2 0204 1d',
172 ['08.Select EnvHol file a'] = CLA..'a4 0000 00',
173 ['09.Select EnvHol file b'] = CLA..'a4 0000 02 2000',
174 ['10.Select EnvHol file c'] = CLA..'a4 0000 02 2001',
175 ['11.EnvHol1'] = CLA..'b2 0104 1d',
176 ['11.EnvHol2'] = CLA..'b2 0204 1d',
177 ['12.Select EvLog file'] = CLA..'a4 0000 02 2010',
178 ['13.EvLog1'] = CLA..'b2 0104 1d',
179 ['14.EvLog2'] = CLA..'b2 0204 1d',
180 ['15.EvLog3'] = CLA..'b2 0304 1d',
181 ['16.Select ConList file'] = CLA..'a4 0000 02 2050',
182 ['17.ConList'] = CLA..'b2 0104 1d',
183 ['18.Select Contra file'] = CLA..'a4 0000 02 2020',
184 ['19.Contra1'] = CLA..'b2 0104 1d',
185 ['20.Contra2'] = CLA..'b2 0204 1d',
186 ['21.Contra3'] = CLA..'b2 0304 1d',
187 ['22.Contra4'] = CLA..'b2 0404 1d',
188 ['23.Contra5'] = CLA..'b2 0504 1d',
189 ['24.Contra6'] = CLA..'b2 0604 1d',
190 ['25.Contra7'] = CLA..'b2 0704 1d',
191 ['26.Contra8'] = CLA..'b2 0804 1d',
192 ['27.Contra9'] = CLA..'b2 0904 1d',
193 ['28.ContraA'] = CLA..'b2 0a04 1d',
194 ['29.ContraB'] = CLA..'b2 0b04 1d',
195 ['30.ContraC'] = CLA..'b2 0c04 1d',
196 ['31.Select Counter file'] = CLA..'a4 0000 02 2069',
197 ['32.Counter'] = CLA..'b2 0104 1d',
198 ['33.Select LoadLog file a'] = CLA..'a4 0000 00',
199 ['34.Select LoadLog file b'] = CLA..'a4 0000 02 1000',
200 ['35.Select LoadLog file c'] = CLA..'a4 0000 02 1014',
201 ['36.LoadLog'] = CLA..'b2 0104 1d',
202 ['37.Select Purcha file'] = CLA..'a4 0000 02 1015',
203 ['38.Purcha1'] = CLA..'b2 0104 1d',
204 ['39.Purcha2'] = CLA..'b2 0204 1d',
205 ['40.Purcha3'] = CLA..'b2 0304 1d',
206 ['41.Select SpecEv file a'] = CLA..'a4 0000 00',
207 ['42.Select SpecEv file b'] = CLA..'a4 0000 02 2000',
208 ['43.Select SpecEv file c'] = CLA..'a4 0000 02 2040',
209 ['44.SpecEv1'] = CLA..'b2 0104 1d',
210 ['45.SpecEv2'] = CLA..'b2 0204 1d',
211 ['46.SpecEv3'] = CLA..'b2 0304 1d',
212 ['47.SpecEv4'] = CLA..'b2 0404 1d',
216 -- The main entry point
217 function main(args)
219 print( string.rep('--',20) )
220 print( string.rep('--',20) )
221 print()
223 local data, apdu, flags, uid, cid, result, err, card
224 -- Read the parameters
225 for o, a in getopt.getopt(args, 'h') do
226 if o == 'h' then return help() end
227 if o == 'b' then bytes = a end
230 -- lib14b.connect()
232 -- Select 14b tag.
233 card, err = lib14b.waitFor14443b()
234 if not card then return oops(err) end
236 mobib_card_num(card)
237 cid = card.cid
239 for i, apdu in spairs(_calypso_cmds) do
240 print('>> '..ansicolors.yellow..i..ansicolors.reset)
241 apdu = apdu:gsub('%s+', '')
242 data, err = mobib_send_cmd_raw(apdu , false)
243 if err then
244 print('<< '..err)
245 else
246 if data then
247 local status, desc, err = mobib_apdu_status(data)
248 local d = data:sub(3, (#data - 8))
249 if status then
250 print('<< '..d..' ('..ansicolors.green..'ok'..ansicolors.reset..')')
251 else
252 print('<< '..d..' '..ansicolors.red..err..ansicolors.reset )
254 else
255 print('<< no answer')
259 lib14b.disconnect()
262 -- a simple selftest function, tries to convert
263 function selftest()
264 DEBUG = true
265 dbg('Performing test')
266 dbg('Tests done')
268 -- Flip the switch here to perform a sanity check.
269 -- It read a nonce in two different ways, as specified in the usage-section
270 if '--test'==args then
271 selftest()
272 else
273 -- Call the main
274 main(args)