Adjust LUA scripts to new ISO14A_NO_RATS option
[proxmark3-svn] / client / scripts / mfkeys.lua
1 --[[
2 This is an example of Lua-scripting within proxmark3. This is a lua-side
3 implementation of hf mf chk
4
5 This code is licensed to you under the terms of the GNU GPL, version 2 or,
6 at your option, any later version. See the LICENSE.txt file for the text of
7 the license.
8
9 Copyright (C) 2013 m h swende <martin at swende.se>
10 --]]
11 -- Loads the commands-library
12 local cmds = require('commands')
13 -- Load the default keys
14 local keys = require('mf_default_keys')
15 -- Ability to read what card is there
16 local reader = require('read14a')
17
18
19 local desc =
20 ("This script implements check keys. It utilises a large list of default keys (currently %d keys).\
21 If you want to add more, just put them inside mf_default_keys.lua. "):format(#keys)
22
23 local TIMEOUT = 10000 -- 10 seconds
24
25 --[[This may be moved to a separate library at some point]]
26 local utils =
27 {
28 ---
29 -- Asks the user for Yes or No
30 confirm = function(message, ...)
31 local answer
32 message = message .. " [y]/[n] ?"
33 repeat
34 io.write(message)
35 io.flush()
36 answer=io.read()
37 if answer == 'Y' or answer == "y" then
38 return true
39 elseif answer == 'N' or answer == 'n' then
40 return false
41 end
42 until false
43 end,
44 ---
45 -- Asks the user for input
46 input = function (message , default)
47 local answer
48 if default ~= nil then
49 message = message .. " (default: ".. default.. " )"
50 end
51 message = message .." \n > "
52 io.write(message)
53 io.flush()
54 answer=io.read()
55 if answer == '' then answer = default end
56
57 return answer
58 end,
59 }
60
61
62 local function checkCommand(command)
63
64 --print("Sending this command : " .. tostring(command))
65 local usbcommand = command:getBytes()
66 core.SendCommand(usbcommand)
67 local result = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
68 if result then
69 local count,cmd,arg0 = bin.unpack('LL',result)
70 if(arg0==1) then
71 local count,arg1,arg2,data = bin.unpack('LLH511',result,count)
72 key = data:sub(1,12)
73 return key
74 else
75 --print("Key not found...")
76 return nil
77 end
78 else
79 print("Timeout while waiting for response. Increase TIMEOUT in keycheck.lua to wait longer")
80 return nil, "Timeout while waiting for device to respond"
81 end
82 end
83
84
85 function checkBlock(blockNo, keys, keyType)
86 -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go.
87 -- If there's more, we need to split it up
88 local start, remaining= 1, #keys
89 local arg1 = bit32.bor(bit32.lshift(keyType, 8), blockNo)
90 local packets = {}
91 while remaining > 0 do
92 local n,data = remaining, nil
93 if remaining > 85 then n = 85 end
94 local data = table.concat(keys,"",start,n)
95 --print("data",data)
96 --print("data len", #data)
97 print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n))
98 local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS,
99 arg1 = arg1,
100 arg2 = 1,
101 arg3 = n,
102 data = data}
103 local status = checkCommand(command)
104 if status then return status, blockNo end
105 start = start+n+1
106 remaining = remaining - n
107 end
108 return nil
109 end
110
111 -- A function to display the results
112 local function displayresults(results)
113 local sector, blockNo, keyA, keyB,_
114
115 print("________________________________________")
116 print("|Sector|Block| A | B |")
117 print("|--------------------------------------|")
118
119 for sector,_ in pairs(results) do
120 blockNo, keyA, keyB = unpack(_)
121
122 print(("| %3d | %3d |%s|%s|"):format(sector, blockNo, keyA, keyB ))
123 end
124 print("|--------------------------------------|")
125
126 end
127 -- A little helper to place an item first in the list
128 local function placeFirst(akey, list)
129 akey = akey:lower()
130 if list[1] == akey then
131 -- Already at pole position
132 return list
133 end
134 local result = {akey}
135 --print(("Putting '%s' first"):format(akey))
136 for i,v in ipairs(list) do
137 if v ~= akey then
138 result[#result+1] = v
139 end
140 end
141 return result
142 end
143 local function dumptofile(results)
144 local sector, blockNo, keyA, keyB,_
145
146 if utils.confirm("Do you wish to save the keys to dumpfile?") then
147 local destination = utils.input("Select a filename to store to", "dumpkeys.bin")
148 local file = io.open(destination, "w")
149 if file == nil then
150 print("Could not write to file ", destination)
151 return
152 end
153
154 local key_a = ""
155 local key_b = ""
156
157 for sector,_ in pairs(results) do
158 blockNo, keyA, keyB = unpack(_)
159 key_a = key_a .. bin.pack("H",keyA);
160 key_b = key_b .. bin.pack("H",keyB);
161 end
162 file:write(key_a)
163 file:write(key_b)
164 file:close()
165 end
166 end
167
168
169 local function main( args)
170
171 print(desc);
172
173 result, err = reader.read1443a(false, true)
174 if not result then
175 print(err)
176 return
177 end
178 print(("Found a %s tag"):format(result.name))
179
180
181 core.clearCommandBuffer()
182 local blockNo
183 local keyType = 0 -- A=0, B=1
184 local numSectors = 16
185
186 if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k
187 -- IFARE Classic 4K offers 4096 bytes split into forty sectors,
188 -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors.
189 numSectors = 40
190 elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
191 -- 1K offers 1024 bytes of data storage, split into 16 sector
192 numSectors = 16
193 elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k
194 -- MIFARE Classic mini offers 320 bytes split into five sectors.
195 numSectors = 5
196 elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k"
197 numSectors = 32
198 else
199 print("I don't know how many sectors there are on this type of card, defaulting to 16")
200 end
201
202 result = {}
203 for sector=1,numSectors,1 do
204
205 --[[
206 The mifare Classic 1k card has 16 sectors of 4 data blocks each.
207 The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
208 8 sectors consist of 16 data blocks.
209 --]]
210 local blockNo = sector * 4 -1
211
212 if sector > 32 then
213 blockNo = 32*4+ (sector-32)*16 -1
214 end
215
216 local keyA = checkBlock(blockNo, keys, 0)
217 if keyA then keys = placeFirst(keyA, keys) end
218 keyA = keyA or ""
219
220 local keyB = checkBlock(blockNo, keys, 1)
221 if keyB then keys = placeFirst(keyB, keys) end
222 keyB = keyB or ""
223
224 result[sector] = {blockNo, keyA, keyB }
225
226 -- Check if user aborted
227 if core.ukbhit() then
228 print("Aborted by user")
229 break
230 end
231 end
232 displayresults(result)
233 dumptofile(result)
234 end
235
236 main( args)
237
Impressum, Datenschutz