| 1 | local cmds = require('commands')\r |
| 2 | local getopt = require('getopt')\r |
| 3 | local bin = require('bin')\r |
| 4 | local lib14a = require('read14a')\r |
| 5 | local utils = require('utils')\r |
| 6 | \r |
| 7 | example =[[\r |
| 8 | 1. script run formatMifare\r |
| 9 | 2. script run formatMifare -k aabbccddeeff -n 112233445566 -a FF0780\r |
| 10 | ]]\r |
| 11 | author = "Iceman"\r |
| 12 | usage = "script run formatMifare -k <key>"\r |
| 13 | desc =[[\r |
| 14 | This script will generate 'hf mf wrbl' commands for each block to format a Mifare card.\r |
| 15 | \r |
| 16 | Alla datablocks gets 0x00\r |
| 17 | As default the script sets the keys A/B to 0xFFFFFFFFFFFF\r |
| 18 | and the access bytes will become 0x78,0x77,0x88\r |
| 19 | The GDB will become 0x00\r |
| 20 | \r |
| 21 | The script will skip the manufactoring block 0.\r |
| 22 | \r |
| 23 | Arguments:\r |
| 24 | -h - this help\r |
| 25 | -k <key> - the current six byte key with write access\r |
| 26 | -n <key> - the new key that will be written to the card\r |
| 27 | -a <access> - the new access bytes that will be written to the card\r |
| 28 | ]]\r |
| 29 | local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds\r |
| 30 | local DEBUG = true -- the debug flag\r |
| 31 | local CmdString = 'hf mf wrbl %d B %s %s'\r |
| 32 | local numBlocks = 64\r |
| 33 | local numSectors = 16\r |
| 34 | --- \r |
| 35 | -- A debug printout-function\r |
| 36 | function dbg(args)\r |
| 37 | if not DEBUG then\r |
| 38 | return\r |
| 39 | end\r |
| 40 | \r |
| 41 | if type(args) == "table" then\r |
| 42 | local i = 1\r |
| 43 | while result[i] do\r |
| 44 | dbg(result[i])\r |
| 45 | i = i+1\r |
| 46 | end\r |
| 47 | else\r |
| 48 | print("###", args)\r |
| 49 | end \r |
| 50 | end \r |
| 51 | --- \r |
| 52 | -- This is only meant to be used when errors occur\r |
| 53 | function oops(err)\r |
| 54 | print("ERROR: ",err)\r |
| 55 | end\r |
| 56 | --- \r |
| 57 | -- Usage help\r |
| 58 | function help()\r |
| 59 | print(desc)\r |
| 60 | print("Example usage")\r |
| 61 | print(example)\r |
| 62 | end\r |
| 63 | --\r |
| 64 | -- Exit message\r |
| 65 | function ExitMsg(msg)\r |
| 66 | print( string.rep('--',20) )\r |
| 67 | print( string.rep('--',20) )\r |
| 68 | print(msg)\r |
| 69 | print()\r |
| 70 | end\r |
| 71 | --\r |
| 72 | -- Read information from a card\r |
| 73 | function GetCardInfo()\r |
| 74 | result, err = lib14a.read14443a(false, true)\r |
| 75 | if not result then\r |
| 76 | print(err)\r |
| 77 | return\r |
| 78 | end\r |
| 79 | print(("Found: %s"):format(result.name))\r |
| 80 | \r |
| 81 | core.clearCommandBuffer()\r |
| 82 | \r |
| 83 | if 0x18 == result.sak then -- NXP MIFARE Classic 4k | Plus 4k\r |
| 84 | -- IFARE Classic 4K offers 4096 bytes split into forty sectors, \r |
| 85 | -- of which 32 are same size as in the 1K with eight more that are quadruple size sectors. \r |
| 86 | numSectors = 40\r |
| 87 | elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k\r |
| 88 | -- 1K offers 1024 bytes of data storage, split into 16 sector\r |
| 89 | numSectors = 16\r |
| 90 | elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k\r |
| 91 | -- MIFARE Classic mini offers 320 bytes split into five sectors.\r |
| 92 | numSectors = 5\r |
| 93 | elseif 0x10 == result.sak then -- NXP MIFARE Plus 2k\r |
| 94 | numSectors = 32\r |
| 95 | elseif 0x01 == result.sak then -- NXP MIFARE TNP3xxx 1K\r |
| 96 | numSectors = 16\r |
| 97 | else\r |
| 98 | print("I don't know how many sectors there are on this type of card, defaulting to 16")\r |
| 99 | end \r |
| 100 | --[[\r |
| 101 | The mifare Classic 1k card has 16 sectors of 4 data blocks each. \r |
| 102 | The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining\r |
| 103 | 8 sectors consist of 16 data blocks. \r |
| 104 | --]]\r |
| 105 | \r |
| 106 | -- Defaults to 16 * 4 = 64 - 1 = 63\r |
| 107 | numBlocks = numSectors * 4 - 1 \r |
| 108 | \r |
| 109 | if numSectors > 32 then\r |
| 110 | numBlocks = 32*4+ (numSectors-32)*16 -1\r |
| 111 | end\r |
| 112 | \r |
| 113 | end\r |
| 114 | \r |
| 115 | local function main(args)\r |
| 116 | \r |
| 117 | print( string.rep('--',20) )\r |
| 118 | print( string.rep('--',20) )\r |
| 119 | print()\r |
| 120 | \r |
| 121 | local OldKey \r |
| 122 | local NewKey\r |
| 123 | local Accessbytes\r |
| 124 | \r |
| 125 | -- Arguments for the script\r |
| 126 | for o, a in getopt.getopt(args, 'hk:n:a:') do\r |
| 127 | if o == "h" then return help() end \r |
| 128 | if o == "k" then OldKey = a end\r |
| 129 | if o == "n" then NewKey = a end\r |
| 130 | if o == "a" then Accessbytes = a end\r |
| 131 | end\r |
| 132 | \r |
| 133 | -- validate input args.\r |
| 134 | OldKey = OldKey or 'FFFFFFFFFFFF'\r |
| 135 | if #(OldKey) ~= 12 then\r |
| 136 | return oops( string.format('Wrong length of write key (was %d) expected 12', #OldKey))\r |
| 137 | end\r |
| 138 | \r |
| 139 | NewKey = NewKey or 'FFFFFFFFFFFF'\r |
| 140 | if #(NewKey) ~= 12 then\r |
| 141 | return oops( string.format('Wrong length of new key (was %d) expected 12', #NewKey))\r |
| 142 | end\r |
| 143 | \r |
| 144 | --Accessbytes = Accessbytes or '787788'\r |
| 145 | Accessbytes = Accessbytes or 'FF0780'\r |
| 146 | if #(Accessbytes) ~= 6 then\r |
| 147 | return oops( string.format('Wrong length of accessbytes (was %d) expected 12', #Accessbytes))\r |
| 148 | end\r |
| 149 | \r |
| 150 | GetCardInfo()\r |
| 151 | \r |
| 152 | -- Show info\r |
| 153 | print( string.format('Estimating number of blocks: %d', numBlocks))\r |
| 154 | print( string.format('Old key: %s', OldKey))\r |
| 155 | print( string.format('New key: %s', NewKey))\r |
| 156 | print( string.format('New Access: %s', Accessbytes))\r |
| 157 | print( string.rep('--',20) )\r |
| 158 | \r |
| 159 | -- Set new block data\r |
| 160 | local EMPTY_BL = string.rep('00',16)\r |
| 161 | local EMPTY_SECTORTRAIL = string.format('%s%s%s%s',NewKey,Accessbytes,'00',NewKey)\r |
| 162 | \r |
| 163 | dbg( string.format('New sector-trailer : %s',EMPTY_SECTORTRAIL))\r |
| 164 | dbg( string.format('New emptyblock: %s',EMPTY_BL))\r |
| 165 | dbg('')\r |
| 166 | \r |
| 167 | -- Ask\r |
| 168 | local dialogResult = utils.confirm("Do you want to erase this card")\r |
| 169 | if dialogResult == false then \r |
| 170 | return ExitMsg('Quiting it is then. Your wish is my command...')\r |
| 171 | end \r |
| 172 | \r |
| 173 | print( string.rep('--',20) )\r |
| 174 | \r |
| 175 | -- main loop\r |
| 176 | for block=0,numBlocks,1 do\r |
| 177 | \r |
| 178 | local reminder = (block+1) % 4\r |
| 179 | local cmd\r |
| 180 | if reminder == 0 then\r |
| 181 | cmd = CmdString:format(block, OldKey , EMPTY_SECTORTRAIL)\r |
| 182 | else\r |
| 183 | cmd = CmdString:format(block, OldKey , EMPTY_BL) \r |
| 184 | end \r |
| 185 | \r |
| 186 | if block ~= 0 then\r |
| 187 | print(cmd)\r |
| 188 | --core.console(cmd)\r |
| 189 | end\r |
| 190 | \r |
| 191 | if core.ukbhit() then\r |
| 192 | print("aborted by user")\r |
| 193 | break\r |
| 194 | end\r |
| 195 | end\r |
| 196 | end\r |
| 197 | \r |
| 198 | main(args) |