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