Merge pull request #2629 from pingu2211/hf-mifare-refacor
[RRG-proxmark3.git] / client / luascripts / hf_14b_calypso.lua
blob52f98cc9262d9b1779c1763722a4aede377414f2
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.5'
11 desc = [[
12 This is a script to communicate with a CALYSPO / 14443b tag using the '14b raw' commands
14 example = [[
15 script run hf_14b_calypso -b 11223344
18 usage = [[
19 script run hf_14b_calypso -h -b
21 arguments = [[
22 h this helptext
23 b raw bytes to send
26 --[[
27 This script communicates with /armsrc/iso14443b.c,
28 Check there for details about data format and how commands are interpreted on the
29 device-side.
32 local PM3_SUCCESS = 0
34 --[[-- iceman, todo: return payload from ISO14b APDU is a struct now. iso14b_raw_apdu_response_t
35 typedef struct {
36 uint8_t response_byte;
37 uint16_t datalen;
38 uint8_t data[];
39 } PACKED iso14b_raw_apdu_response_t;
40 --]]
42 local function calypso_parse(result)
43 if result.Length >= 0 then
44 local response_byte = string.sub(result.Data, 0, 1);
45 local datalen = string.sub(result.Data, 2, 5);
46 local d = string.sub(result.Data, 6, datalen * 2);
47 return {
48 response_byte = response_byte,
49 datalen = datalen,
50 data = d
51 }, nil
52 end
53 return nil, "calypso_parse failed"
54 end
55 ---
56 -- A debug printout-function
57 local function dbg(args)
58 if not DEBUG then return end
59 if type(args) == 'table' then
60 local i = 1
61 while args[i] do
62 dbg(args[i])
63 i = i+1
64 end
65 else
66 print('###', args)
67 end
68 end
69 ---
70 -- This is only meant to be used when errors occur
71 local function oops(err)
72 print('ERROR: ', err)
73 lib14b.disconnect()
74 return nil, err
75 end
76 ---
77 -- Usage help
78 local function help()
79 print(copyright)
80 print(author)
81 print(version)
82 print(desc)
83 print(ansicolors.cyan..'Usage'..ansicolors.reset)
84 print(usage)
85 print(ansicolors.cyan..'Arguments'..ansicolors.reset)
86 print(arguments)
87 print(ansicolors.cyan..'Example usage'..ansicolors.reset)
88 print(example)
89 end
91 -- helper function, give current count of items in lua-table.
92 local function tablelen(T)
93 local count = 0
94 for _ in pairs(T) do count = count + 1 end
95 return count
96 end
97 ---
98 -- helper function, gives a sorted table from table t,
99 -- order can be a separate sorting-order function.
100 local function spairs(t, order)
101 -- collect the keys
102 local keys = {}
103 for k in pairs(t) do keys[#keys+1] = k end
105 -- if order function given, sort by it by passing the table and keys a, b,
106 -- otherwise just sort the keys
107 if order then
108 table.sort(keys, function(a,b) return order(t, a, b) end)
109 else
110 table.sort(keys)
113 -- return the iterator function
114 local i = 0
115 return function()
116 i = i + 1
117 if keys[i] then
118 return keys[i], t[keys[i]]
123 -- Sends a usbpackage , "hf 14b raw"
124 -- if it reads the response, it converts it to a lua object "Command" first and the Data is cut to correct length.
125 local function calypso_send_cmd_raw(data, ignoreresponse )
127 local flags = lib14b.ISO14B_COMMAND.ISO14B_APDU
129 data = data or ""
130 -- LEN of data, half the length of the ASCII-string hex string
131 -- 2 bytes flags
132 -- 4 bytes timeout
133 -- 2 bytes raw len
134 -- n bytes raw
136 local flags_str = ('%04x'):format(utils.SwapEndianness(('%04x'):format(flags), 16))
137 local time_str = ('%08x'):format(0)
138 local rawlen_str = ('%04x'):format(utils.SwapEndianness(('%04x'):format(( 8 + #data/2)), 16))
139 local senddata = ('%s%s%s%s'):format(flags_str, time_str, rawlen_str,data)
140 local c = Command:newNG{cmd = cmds.CMD_HF_ISO14443B_COMMAND, data = senddata}
141 local result, err = c:sendNG(ignoreresponse, 2000)
142 if result and result.status == PM3_SUCCESS then
143 return calypso_parse(result)
144 else
145 err = 'No response from card'
147 return result, err
150 -- calypso_card_num : Reads card number from ATR and
151 -- writes it in the tree in decimal format.
152 local function calypso_card_num(card)
153 if not card then return end
154 local card_num = tonumber( card.uid:sub(1, 8), 16)
155 print('')
156 print('Card UID ' ..ansicolors.green..card.uid:format('%x')..ansicolors.reset)
157 print('Card Number ' ..ansicolors.green..string.format('%u', card_num)..ansicolors.reset)
158 print('-----------------------')
161 -- analyse CALYPSO apdu status bytes.
162 local function calypso_apdu_status(apdu)
163 -- last two is CRC
164 -- next two is APDU status bytes.
165 local mess = 'FAIL'
166 local sw = apdu:sub( #apdu - 7 , #apdu - 4)
167 desc, err = iso7816.tostring(sw)
168 --print ('SW', sw, desc, err )
169 local status = ( sw == '9000' )
170 return status, desc, err
173 local CLA = '94'
174 local _calypso_cmds = {
176 -- Break down of command bytes:
177 -- A4 = select
178 -- Master File 3F00
179 -- 0x3F = master file
180 -- 0x00 = master file id, is constant to 0x00.
182 -- DF Dedicated File 38nn
183 -- can be seen as directories
184 -- 0x38
185 -- 0xNN id
186 -- ["01.Select ICC file"] = '0294 a4 080004 3f00 0002',
188 -- EF Elementary File
189 -- EF1 Pin file
190 -- EF2 Key file
191 -- Grey Lock file
192 -- Electronic deposit file
193 -- Electronic Purse file
194 -- Electronic Transaction log file
196 ['01.Select ICC file'] = CLA..'a4 080004 3f00 0002',
197 ['02.ICC'] = CLA..'b2 01 041d',
198 ['03.Select EnvHol file'] = CLA..'a4 080004 2000 2001',
199 ['04.EnvHol1'] = CLA..'b2 01 041d',
200 ['05.Select EvLog file'] = CLA..'a4 080004 2000 2010',
201 ['06.EvLog1'] = CLA..'b2 01 041d',
202 ['07.EvLog2'] = CLA..'b2 02 041d',
203 ['08.EvLog3'] = CLA..'b2 03 041d',
204 ['09.Select ConList file']= CLA..'a4 080004 2000 2050',
205 ['10.ConList'] = CLA..'b2 01 041d',
206 ['11.Select Contra file'] = CLA..'a4 080004 2000 2020',
207 ['12.Contra1'] = CLA..'b2 01 041d',
208 ['13.Contra2'] = CLA..'b2 02 041d',
209 ['14.Contra3'] = CLA..'b2 03 041d',
210 ['15.Contra4'] = CLA..'b2 04 041d',
211 ['16.Select Counter file']= CLA..'a4 080004 2000 2069',
212 ['17.Counter'] = CLA..'b2 01 041d',
213 ['18.Select SpecEv file'] = CLA..'a4 080004 2000 2040',
214 ['19.SpecEv1'] = CLA..'b2 01 041d',
218 -- The main entry point
219 function main(args)
221 print( string.rep('--',20) )
222 print( string.rep('--',20) )
223 print()
225 local data, apdu, flags, uid, cid, result, err, card
226 -- Read the parameters
227 for o, a in getopt.getopt(args, 'h') do
228 if o == 'h' then return help() end
229 if o == 'b' then bytes = a end
232 -- lib14b.connect()
234 -- Select 14b tag.
235 card, err = lib14b.waitFor14443b()
236 if not card then return oops(err) end
238 calypso_card_num(card)
239 cid = card.cid
241 --[[
242 NAME VALUE APDU_POS
243 PCB 0x0A 0
244 CID 0x00 1
245 CLA 0x94 2
246 SELECT FILE 0xA4 3
247 READ FILE 0xB2 3
248 P1 4
249 P2 5
250 LEN_
251 0 1 2 3 4 5 6 7
252 apdu = '02 94 a4 08 00 04 3f 00 00 02' --select ICC file
253 DF_NAME = "1TIC.ICA"
254 --]]
255 --for i = 1,10 do
256 --result, err = calypso_send_cmd_raw('0294a40800043f000002',false) --select ICC file
257 for i, apdu in spairs(_calypso_cmds) do
258 print('>> '..ansicolors.yellow..i..ansicolors.reset)
259 apdu = apdu:gsub('%s+', '')
260 obj, err = calypso_send_cmd_raw(apdu, false)
261 if err then
262 print('<< '..err)
263 else
264 if obj.data then
265 local status, desc, err = calypso_apdu_status(obj.data)
266 local d = data:sub(3, (obj.datalen - 8))
267 if status then
268 print('<< '..d..' ('..ansicolors.green..'ok'..ansicolors.reset..')')
269 else
270 print('<< '..d..' '..ansicolors.red..err..ansicolors.reset )
272 else
273 print('<< no answer')
277 lib14b.disconnect()
280 -- a simple selftest function, tries to convert
281 function selftest()
282 DEBUG = true
283 dbg('Performing test')
284 dbg('Tests done')
286 -- Flip the switch here to perform a sanity check.
287 -- It read a nonce in two different ways, as specified in the usage-section
288 if '--test'==args then
289 selftest()
290 else
291 -- Call the main
292 main(args)