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')
17 -- Asks the user for input
18 local utils = require('utils')
21 local desc = ("This script implements check keys. \
22 It utilises a large list of default keys (currently %d keys).\
23 If you want to add more, just put them inside mf_default_keys.lua. "):format(#keys)
25 local TIMEOUT = 10000 -- 10 seconds
28 local function checkCommand(command)
30 --print("Sending this command : " .. tostring(command))
31 local usbcommand = command:getBytes()
32 core.SendCommand(usbcommand)
33 local result = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
35 local count,cmd,arg0 = bin.unpack('LL',result)
37 local count,arg1,arg2,data = bin.unpack('LLH511',result,count)
41 --print("Key not found...")
45 print("Timeout while waiting for response. Increase TIMEOUT in keycheck.lua to wait longer")
46 return nil, "Timeout while waiting for device to respond"
51 function checkBlock(blockNo, keys, keyType)
52 -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go.
53 -- If there's more, we need to split it up
54 local start, remaining= 1, #keys
55 local arg1 = bit32.bor(bit32.lshift(keyType, 8), blockNo)
57 while remaining > 0 do
58 local n,data = remaining, nil
59 if remaining > 85 then n = 85 end
60 local data = table.concat(keys,"",start,n)
62 --print("data len", #data)
63 print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n))
64 local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS,
69 local status = checkCommand(command)
70 if status then return status, blockNo end
72 remaining = remaining - n
77 -- A function to display the results
78 local function displayresults(results)
79 local sector, blockNo, keyA, keyB,_
81 print("________________________________________")
82 print("|Sector|Block| A | B |")
83 print("|--------------------------------------|")
85 for sector,_ in pairs(results) do
86 blockNo, keyA, keyB = unpack(_)
88 print(("| %3d | %3d |%s|%s|"):format(sector, blockNo, keyA, keyB ))
90 print("|--------------------------------------|")
93 -- A little helper to place an item first in the list
94 local function placeFirst(akey, list)
96 if list[1] == akey then
97 -- Already at pole position
100 local result = {akey}
101 --print(("Putting '%s' first"):format(akey))
102 for i,v in ipairs(list) do
104 result[#result+1] = v
109 local function dumptofile(results)
110 local sector, blockNo, keyA, keyB,_
112 if utils.confirm("Do you wish to save the keys to dumpfile?") then
113 local destination = utils.input("Select a filename to store to", "dumpkeys.bin")
114 local file = io.open(destination, "w")
116 print("Could not write to file ", destination)
123 for sector,_ in pairs(results) do
124 blockNo, keyA, keyB = unpack(_)
125 key_a = key_a .. bin.pack("H",keyA);
126 key_b = key_b .. bin.pack("H",keyB);
135 local function main( args)
139 result, err = reader.read14443a(false, true)
144 print(("Found a %s tag"):format(result.name))
147 core.clearCommandBuffer()
149 local keyType = 0 -- A=0, B=1
150 local numSectors = 16
152 if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k
153 -- IFARE Classic 4K offers 4096 bytes split into forty sectors,
154 -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors.
156 elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
157 -- 1K offers 1024 bytes of data storage, split into 16 sector
159 elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k
160 -- MIFARE Classic mini offers 320 bytes split into five sectors.
162 elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k"
165 print("I don't know how many sectors there are on this type of card, defaulting to 16")
169 for sector=1,numSectors,1 do
172 The mifare Classic 1k card has 16 sectors of 4 data blocks each.
173 The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
174 8 sectors consist of 16 data blocks.
176 local blockNo = sector * 4 -1
179 blockNo = 32*4+ (sector-32)*16 -1
182 local keyA = checkBlock(blockNo, keys, 0)
183 if keyA then keys = placeFirst(keyA, keys) end
186 local keyB = checkBlock(blockNo, keys, 1)
187 if keyB then keys = placeFirst(keyB, keys) end
190 result[sector] = {blockNo, keyA, keyB }
192 -- Check if user aborted
193 if core.ukbhit() then
194 print("Aborted by user")
198 displayresults(result)