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')
 
  19 ("This script implements check keys. It utilises a large list of default keys (currently %d keys).\
 
  20 If you want to add more, just put them inside mf_default_keys.lua. "):format(#keys)
 
  22 local TIMEOUT = 10000 -- 10 seconds
 
  24 local function checkCommand(command)
 
  26         --print("Sending this command : " .. tostring(command))
 
  27         local usbcommand = command:getBytes()
 
  28         core.SendCommand(usbcommand)
 
  29         local result = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
 
  31                 local count,cmd,arg0 = bin.unpack('LL',result)
 
  33                         local count,arg1,arg2,data = bin.unpack('LLH511',result,count)
 
  37                         --print("Key not found...")
 
  41                 print("Timeout while waiting for response. Increase TIMEOUT in keycheck.lua to wait longer")
 
  42                 return nil, "Timeout while waiting for device to respond"
 
  47 function checkBlock(blockNo, keys, keyType)
 
  48         -- The command data is only 512 bytes, each key is 6 bytes, meaning that we can send max 85 keys in one go. 
 
  49         -- If there's more, we need to split it up
 
  50         local start, remaining= 1, #keys
 
  52         while remaining > 0 do
 
  53                 local n,data = remaining, nil
 
  54                 if remaining > 85 then n = 85 end
 
  55                 local data = table.concat(keys,"",start,n)
 
  57                 --print("data len", #data)
 
  58                 print(("Testing block %d, keytype %d, with %d keys"):format(blockNo, keyType, n))
 
  59                 local command = Command:new{cmd = cmds.CMD_MIFARE_CHKKEYS, 
 
  64                 local status = checkCommand(command)
 
  65                 if status then return status, blockNo end
 
  67                 remaining = remaining - n
 
  72 -- A function to display the results
 
  73 local function displayresults(results)
 
  74         local sector, blockNo, keyA, keyB,_
 
  76         print("________________________________________")
 
  77         print("|Sector|Block|     A      |      B     |")
 
  78         print("|--------------------------------------|")
 
  80         for sector,_ in pairs(results) do
 
  81                 blockNo, keyA, keyB = unpack(_)
 
  83                 print(("| %3d  | %3d |%s|%s|"):format(sector, blockNo, keyA, keyB ))
 
  85         print("|--------------------------------------|")
 
  88 -- A little helper to place an item first in the list
 
  89 local function placeFirst(akey, list)
 
  91         if list[1] == akey then 
 
  92                 -- Already at pole position
 
  96         --print(("Putting '%s' first"):format(akey))
 
  97         for i,v in ipairs(list) do
 
 105 local function main()
 
 109         result, err = reader.read1443a()
 
 114         print(("Found a %s tag"):format(result.name))
 
 117         core.clearCommandBuffer()
 
 119         local keyType = 0 -- A=0, B=1
 
 124                 The mifare Classic 1k card has 16 sectors of 4 data blocks each. The
 
 125                 first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
 
 126                 8 sectors consist of 16 data blocks. 
 
 128                 local blockNo = sector * 4 -1 
 
 131                         blockNo = 32*4+ (sector-32)*16 -1
 
 134                 local keyA = checkBlock(blockNo, keys, 0)
 
 135                 if keyA then keys  = placeFirst(keyA, keys) end
 
 138                 local keyB = checkBlock(blockNo, keys, 1)
 
 139                 if keyB then keys  = placeFirst(keyB, keys) end
 
 142                 result[sector] = {blockNo, keyA, keyB }
 
 144                 -- Check if user aborted
 
 145                 if core.ukbhit() then
 
 146                         print("Aborted by user")
 
 150         displayresults(result)