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')
12 This is a script to communicate with a MOBIB tag using the '14b raw' commands
15 script run hf_14b_mobib
16 script run hf_14b_mobib -b 11223344
20 script run hf_14b_mobib -h -b
28 This script communicates with /armsrc/iso14443b.c,
29 Check there for details about data format and how commands are interpreted on the
33 -- iceman, todo: return payload from ISO14b APDU is a struct now. iso14b_raw_apdu_response_t
34 local function mobib_parse(result
)
35 if result
.Length
>= 0 then
36 local response_byte
= string.sub(result
.Data
, 0, 1);
37 local datalen
= string.sub(result
.Data
, 2, 5);
38 local d
= string.sub(result
.Data
, 6, datalen
* 2);
40 response_byte
= response_byte
,
45 return nil, "mobib_parse failed"
48 -- A debug printout-function
49 local function dbg(args
)
50 if not DEBUG
then return end
51 if type(args
) == 'table' then
62 -- This is only meant to be used when errors occur
63 local function oops(err
)
75 print(ansicolors
.cyan
..'Usage'..ansicolors
.reset
)
77 print(ansicolors
.cyan
..'Arguments'..ansicolors
.reset
)
79 print(ansicolors
.cyan
..'Example usage'..ansicolors
.reset
)
83 -- helper function, give current count of items in lua-table.
84 local function tablelen(T
)
86 for _
in pairs(T
) do count
= count
+ 1 end
90 -- helper function, gives a sorted table from table t,
91 -- order can be a separate sorting-order function.
92 local function spairs(t
, order
)
95 for k
in pairs(t
) do keys
[#keys
+1] = k
end
97 -- if order function given, sort by it by passing the table and keys a, b,
98 -- otherwise just sort the keys
100 table.sort(keys
, function(a
,b
) return order(t
, a
, b
) end)
105 -- return the iterator function
110 return keys
[i
], t
[keys
[i]]
115 -- Sends a usbpackage , "hf 14b raw"
116 -- if it reads the response, it converts it to a lua object "Command" first and the Data is cut to correct length.
117 local function mobib_send_cmd_raw(data
, ignoreresponse
)
118 local flags
= lib14b
.ISO14B_COMMAND
.ISO14B_APDU
120 -- LEN of data, half the length of the ASCII-string hex string
125 local flags_str
= ('%04x'):format(utils
.SwapEndianness(('%04x'):format(flags
), 16))
126 local time_str
= ('%08x'):format(0)
127 local rawlen_str
= ('%04x'):format(utils
.SwapEndianness(('%04x'):format(( 8 + #data
/2)), 16))
128 local senddata
= ('%s%s%s%s'):format(flags_str
, time_str
, rawlen_str
,data
)
129 local c
= Command
:newNG
{cmd
= cmds
.CMD_HF_ISO14443B_COMMAND
, data
= senddata
}
131 local result
, err
= c
:sendNG(ignoreresponse
, 2000)
132 if result
and result
.status
== PM3_SUCCESS
then
133 return mobib_parse(result
)
135 err
= 'No response from card'
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 )
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
)
154 -- next two is APDU status bytes.
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
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
219 print( string.rep('--',20) )
220 print( string.rep('--',20) )
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
233 card
, err
= lib14b
.waitFor14443b()
234 if not card
then return oops(err
) end
239 for i
, apdu
in spairs(_calypso_cmds
) do
240 print('>> '..ansicolors
.yellow
..i
..ansicolors
.reset
)
241 apdu
= apdu
:gsub('%s+', '')
242 obj
, err
= mobib_send_cmd_raw(apdu
, false)
247 local status
, desc
, err
= mobib_apdu_status(obj
.data
)
248 local d
= data
:sub(3, (obj
.datalen
- 8))
250 print('<< '..d
..' ('..ansicolors
.green
..'ok'..ansicolors
.reset
..')')
252 print('<< '..d
..' '..ansicolors
.red
..err
..ansicolors
.reset
)
255 print('<< no answer')
262 -- a simple selftest function, tries to convert
265 dbg('Performing test')
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