2 This is an example of Lua-scripting within proxmark3. This is a lua-side
3 implementation of hf mf chk
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
9 Copyright (C) 2013 m h swende <martin at swende.se>
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')
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)
23 local TIMEOUT = 10000 -- 10 seconds
25 --[[This may be moved to a separate library at some point]]
29 -- Asks the user for Yes or No
30 confirm = function(message, ...)
32 message = message .. " [y]/[n] ?"
37 if answer == 'Y' or answer == "y" then
39 elseif answer == 'N' or answer == 'n' then
45 -- Asks the user for input
46 input = function (message , default)
48 if default ~= nil then
49 message = message .. " (default: ".. default.. " )"
51 message = message .." \n > "
55 if answer == '' then answer = default end
62 local function checkCommand(command)
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)
69 local count,cmd,arg0 = bin.unpack('LL',result)
71 local count,arg1,arg2,data = bin.unpack('LLH511',result,count)
75 --print("Key not found...")
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"
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
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)
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,
102 local status = checkCommand(command)
103 if status then return status, blockNo end
105 remaining = remaining - n
110 -- A function to display the results
111 local function displayresults(results)
112 local sector, blockNo, keyA, keyB,_
114 print("________________________________________")
115 print("|Sector|Block| A | B |")
116 print("|--------------------------------------|")
118 for sector,_ in pairs(results) do
119 blockNo, keyA, keyB = unpack(_)
121 print(("| %3d | %3d |%s|%s|"):format(sector, blockNo, keyA, keyB ))
123 print("|--------------------------------------|")
126 -- A little helper to place an item first in the list
127 local function placeFirst(akey, list)
129 if list[1] == akey then
130 -- Already at pole position
133 local result = {akey}
134 --print(("Putting '%s' first"):format(akey))
135 for i,v in ipairs(list) do
137 result[#result+1] = v
142 local function dumptofile(results)
143 local sector, blockNo, keyA, keyB,_
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")
149 print("Could not write to file ", destination)
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);
168 local function main( args)
172 result, err = reader.read1443a()
177 print(("Found a %s tag"):format(result.name))
180 core.clearCommandBuffer()
182 local keyType = 0 -- A=0, B=1
183 local numSectors = 16
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.
189 elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
190 -- 1K offers 1024 bytes of data storage, split into 16 sector
192 elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k
193 -- MIFARE Classic mini offers 320 bytes split into five sectors.
195 elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k"
198 print("I don't know how many sectors there are on this type of card, defaulting to 16")
202 for sector=1,numSectors,1 do
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.
209 local blockNo = sector * 4 -1
212 blockNo = 32*4+ (sector-32)*16 -1
215 local keyA = checkBlock(blockNo, keys, 0)
216 if keyA then keys = placeFirst(keyA, keys) end
219 local keyB = checkBlock(blockNo, keys, 1)
220 if keyB then keys = placeFirst(keyB, keys) end
223 result[sector] = {blockNo, keyA, keyB }
225 -- Check if user aborted
226 if core.ukbhit() then
227 print("Aborted by user")
231 displayresults(result)