]> git.zerfleddert.de Git - proxmark3-svn/blob - client/scripts/mfkeys.lua
Added undec to un-decimate data on the client side, so we can use all those sweet...
[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 packets = {}
90 while remaining > 0 do
91 local n,data = remaining, nil
92 if remaining > 85 then n = 85 end
93 local data = table.concat(keys,"",start,n)
94 --print("data",data)
95 --print("data len", #data)
96 print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n))
97 local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS,
98 arg1 = blockNo,
99 arg2 = keyType,
100 arg3 = n,
101 data = data}
102 local status = checkCommand(command)
103 if status then return status, blockNo end
104 start = start+n+1
105 remaining = remaining - n
106 end
107 return nil
108 end
109
110 -- A function to display the results
111 local function displayresults(results)
112 local sector, blockNo, keyA, keyB,_
113
114 print("________________________________________")
115 print("|Sector|Block| A | B |")
116 print("|--------------------------------------|")
117
118 for sector,_ in pairs(results) do
119 blockNo, keyA, keyB = unpack(_)
120
121 print(("| %3d | %3d |%s|%s|"):format(sector, blockNo, keyA, keyB ))
122 end
123 print("|--------------------------------------|")
124
125 end
126 -- A little helper to place an item first in the list
127 local function placeFirst(akey, list)
128 akey = akey:lower()
129 if list[1] == akey then
130 -- Already at pole position
131 return list
132 end
133 local result = {akey}
134 --print(("Putting '%s' first"):format(akey))
135 for i,v in ipairs(list) do
136 if v ~= akey then
137 result[#result+1] = v
138 end
139 end
140 return result
141 end
142 local function dumptofile(results)
143 local sector, blockNo, keyA, keyB,_
144
145 if utils.confirm("Do you wish to save the keys to dumpfile?") then
146 local destination = utils.input("Select a filename to store to", "dumpkeys.bin")
147 local file = io.open(destination, "w")
148 if file == nil then
149 print("Could not write to file ", destination)
150 return
151 end
152
153 local key_a = ""
154 local key_b = ""
155
156 for sector,_ in pairs(results) do
157 blockNo, keyA, keyB = unpack(_)
158 key_a = key_a .. bin.pack("H",keyA);
159 key_b = key_b .. bin.pack("H",keyB);
160 end
161 file:write(key_a)
162 file:write(key_b)
163 file:close()
164 end
165 end
166
167
168 local function main( args)
169
170 print(desc);
171
172 result, err = reader.read1443a()
173 if not result then
174 print(err)
175 return
176 end
177 print(("Found a %s tag"):format(result.name))
178
179
180 core.clearCommandBuffer()
181 local blockNo
182 local keyType = 0 -- A=0, B=1
183 local numSectors = 16
184
185 if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k
186 -- IFARE Classic 4K offers 4096 bytes split into forty sectors,
187 -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors.
188 numSectors = 40
189 elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
190 -- 1K offers 1024 bytes of data storage, split into 16 sector
191 numSectors = 16
192 elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k
193 -- MIFARE Classic mini offers 320 bytes split into five sectors.
194 numSectors = 5
195 elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k"
196 numSectors = 32
197 else
198 print("I don't know how many sectors there are on this type of card, defaulting to 16")
199 end
200
201 result = {}
202 for sector=1,numSectors,1 do
203
204 --[[
205 The mifare Classic 1k card has 16 sectors of 4 data blocks each.
206 The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
207 8 sectors consist of 16 data blocks.
208 --]]
209 local blockNo = sector * 4 -1
210
211 if sector > 32 then
212 blockNo = 32*4+ (sector-32)*16 -1
213 end
214
215 local keyA = checkBlock(blockNo, keys, 0)
216 if keyA then keys = placeFirst(keyA, keys) end
217 keyA = keyA or ""
218
219 local keyB = checkBlock(blockNo, keys, 1)
220 if keyB then keys = placeFirst(keyB, keys) end
221 keyB = keyB or ""
222
223 result[sector] = {blockNo, keyA, keyB }
224
225 -- Check if user aborted
226 if core.ukbhit() then
227 print("Aborted by user")
228 break
229 end
230 end
231 displayresults(result)
232 dumptofile(result)
233 end
234
235 main( args)
236
Impressum, Datenschutz