1 local cmds = require('commands')
2 local getopt = require('getopt')
3 local bin = require('bin')
4 local lib14a = require('read14a')
5 local utils = require('utils')
6 local md5 = require('md5')
10 2. script run tnp3 -k aabbccddeeff
13 usage = "script run tnp3 -k <key>"
15 This script will try to dump the contents of a Mifare TNP3xxx card.
16 It will need a valid KeyA in order to find the other keys and decode the card.
19 -k <key> - Sector 0 Key A.
22 local hashconstant = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
24 local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
25 local DEBUG = true -- the debug flag
29 -- A debug printout-function
35 if type(args) == "table" then
46 -- This is only meant to be used when errors occur
54 print("Example usage")
60 print( string.rep('--',20) )
61 print( string.rep('--',20) )
66 local function show(data)
68 local formatString = ("H%d"):format(string.len(data))
69 local _,hexdata = bin.unpack(formatString, data)
70 dbg("Hexdata" , hexdata)
74 local function readdumpkeys(infile)
75 t = infile:read("*all")
77 local len,hex = bin.unpack(("H%d"):format(len),t)
82 local function waitCmd()
83 local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
85 local count,cmd,arg0 = bin.unpack('LL',response)
87 local count,arg1,arg2,data = bin.unpack('LLH511',response,count)
90 return nil, "Couldn't read block.."
93 return nil, "No response from device"
96 local function main(args)
98 print( string.rep('--',20) )
99 print( string.rep('--',20) )
105 local cmdReadBlockString = 'hf mf rdbl %d A %s'
106 local input = "dumpkeys.bin"
108 -- Arguments for the script
109 for o, a in getopt.getopt(args, 'hk:') do
110 if o == "h" then return help() end
111 if o == "k" then keyA = a end
114 -- validate input args.
115 keyA = keyA or '4b0b20107ccb'
116 if #(keyA) ~= 12 then
117 return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA))
120 result, err = lib14a.read1443a(false)
125 print((' Found tag : %s'):format(result.name))
127 core.clearCommandBuffer()
129 if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
130 print('This is not a TNP3xxx tag. aborting.')
135 print(('Using keyA : %s'):format(keyA))
136 print( string.rep('--',20) )
138 print('Trying to find other keys. ')
139 --core.console( ('hf mf nested 1 0 A %s d'):format(keyA) )
141 -- Reading found keys file
142 local infile = io.open(input, "rb")
143 if infile == nil then
144 return oops('Could not read file ', input)
146 local akeys = readdumpkeys(infile):sub(0,12*16)
148 --print( ('KEYS: %s'):format(akeys))
150 print('Reading data need to dump data')
153 cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA}
154 err = core.SendCommand(cmd:getBytes())
155 if err then return oops(err) end
156 local block0, err = waitCmd()
157 if err then return oops(err) end
160 cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1,arg2 = 0,arg3 = 0, data = keyA}
161 local err = core.SendCommand(cmd:getBytes())
162 if err then return oops(err) end
163 local block1, err = waitCmd()
164 if err then return oops(err) end
166 print('Dumping data')
169 print('BLOCK MD5 DECRYPTED ASCII' )
172 local keyPosStart = 0
174 for block = 0, numBlocks-1, 1 do
175 local b = (block+1)%4
177 keyPosStart = (math.floor( block / 4 ) * 12)+1
178 key = akeys:sub(keyPosStart, keyPosStart + 12 )
179 --print( ('%02d %s'):format(block, key))
181 cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = block ,arg2 = 0,arg3 = 0, data = key}
182 local err = core.SendCommand(cmd:getBytes())
183 if err then return oops(err) end
184 local blockdata, err = waitCmd()
185 if err then return oops(err) end
187 local base = ('%s%s%02d%s'):format(block0, block1, block, hashconstant)
188 local md5hash = md5.sumhexa(base)
189 local aestest = core.aes(md5hash, blockdata)
191 local _,hex = bin.unpack(("H%d"):format(16),aestest)
193 local hexascii = string.gsub(hex, '(%x%x)',
195 return string.char(tonumber(value, 16))
199 print( ('%02d :: %s :: %s :: %s :: %s'):format(block,key,md5hash,hex,hexascii) )
201 if core.ukbhit() then
202 print("aborted by user")