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