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