text
[RRG-proxmark3.git] / client / luascripts / hf_mf_uidkeycalc_mizip.lua
blobb2a0992d5debd3268058c96bc300913919ed86b6
1 local bin = require('bin')
2 local getopt = require('getopt')
3 local lib14a = require('read14a')
4 local utils = require('utils')
5 local ansicolors = require('ansicolors')
7 copyright = ''
8 author = 'Iceman'
9 version = 'v1.0.2'
10 desc = [[
11 This script calculates mifare keys based on uid diversification for mizip.
12 Algo not found by me.
14 example = [[
15 -- if called without, it reads tag uid
16 script run hf_mf_uidkeycalc-mizip
19 script run hf_mf_uidkeycalc-mizip -u 11223344
21 usage = [[
22 script run hf_mf_uidkeycalc-mizip -h -u <uid>
24 arguments = [[
25 -h : this help
26 -u <UID> : UID
28 local DEBUG = true
29 local bxor = bit32.bxor
30 local _xortable = {
31 --[[ sector key A/B, 6byte xor
32 --]]
33 {1, '09125a2589e5', 'F12C8453D821'},
34 {2, 'AB75C937922F', '73E799FE3241'},
35 {3, 'E27241AF2C09', 'AA4D137656AE'},
36 {4, '317AB72F4490', 'B01327272DFD'},
38 ---
39 -- A debug printout-function
40 local function dbg(args)
41 if not DEBUG then return end
42 if type(args) == 'table' then
43 local i = 1
44 while args[i] do
45 dbg(args[i])
46 i = i+1
47 end
48 else
49 print('###', args)
50 end
51 end
52 ---
53 -- This is only meant to be used when errors occur
54 local function oops(err)
55 print('ERROR: ', err)
56 core.clearCommandBuffer()
57 return nil, err
58 end
59 ---
60 -- Usage help
61 local function help()
62 print(copyright)
63 print(author)
64 print(version)
65 print(desc)
66 print(ansicolors.cyan..'Usage'..ansicolors.reset)
67 print(usage)
68 print(ansicolors.cyan..'Arguments'..ansicolors.reset)
69 print(arguments)
70 print(ansicolors.cyan..'Example usage'..ansicolors.reset)
71 print(example)
72 end
74 -- Exit message
75 local function exitMsg(msg)
76 print( string.rep('--',20) )
77 print( string.rep('--',20) )
78 print(msg)
79 print()
80 end
82 -- dumps all keys to file
83 local function dumptofile(uid, keys)
84 dbg('dumping keys to file')
86 if utils.confirm('Do you wish to save the keys to dumpfile?') then
87 local filename = ('hf-mf-%s-key.bin'):format(uid);
88 local destination = utils.input('Select a filename to store to', filename)
89 local file = io.open(destination, 'wb')
90 if file == nil then
91 print('Could not write to file ', destination)
92 return
93 end
95 -- Mifare Mini has 5 sectors,
96 local key_a = ''
97 local key_b = ''
99 for sector = 0, #keys do
100 local keyA, keyB = table.unpack(keys[sector])
101 key_a = key_a .. bin.pack('H', keyA);
102 key_b = key_b .. bin.pack('H', keyB);
104 file:write(key_a)
105 file:write(key_b)
106 file:close()
110 -- key bytes to string
111 local function keyStr(p1, p2, p3, p4, p5, p6)
112 return string.format('%02X%02X%02X%02X%02X%02X',p1, p2, p3, p4, p5, p6)
115 -- create key
116 local function calckey(uid, xorkey, keytype)
117 local p1,p2,p3,p4,p5,p6
118 print("calckey()")
119 if keytype == 'A' then
120 p1 = bxor( uid[1], xorkey[1])
121 p2 = bxor( uid[2], xorkey[2])
122 p3 = bxor( uid[3], xorkey[3])
123 p4 = bxor( uid[4], xorkey[4])
124 p5 = bxor( uid[1], xorkey[5])
125 p6 = bxor( uid[2], xorkey[6])
126 else
127 p1 = bxor( uid[3], xorkey[1])
128 p2 = bxor( uid[4], xorkey[2])
129 p3 = bxor( uid[1], xorkey[3])
130 p4 = bxor( uid[2], xorkey[4])
131 p5 = bxor( uid[3], xorkey[5])
132 p6 = bxor( uid[4], xorkey[6])
134 return keyStr(p1,p2,p3,p4,p5,p6)
137 -- print keys
138 local function printKeys(keys)
139 print('|---|----------------|---|----------------|---|')
140 print('|sec|key A |res|key B |res|')
141 print('|---|----------------|---|----------------|---|')
142 for sector = 0, #keys do
143 local keyA, keyB = table.unpack(keys[sector])
144 print(('|%03d| %s | %s | %s | %s |'):format(sector, keyA, 1, keyB, 1))
146 print('|---|----------------|---|----------------|---|')
149 -- create a full set of keys
150 local function createKeys(uid)
151 local uidbytes = utils.ConvertHexToBytes(uid)
153 local k = {}
154 k[0] = { keyStr(0xA0,0xA1,0xA2,0xA3,0xA4,0xA5), keyStr(0xB4,0xC1,0x32,0x43,0x9e,0xef) }
156 for _, v in pairs(_xortable) do
157 local keyA = calckey(uidbytes, utils.ConvertHexToBytes(v[2]), 'A')
158 local keyB = calckey(uidbytes, utils.ConvertHexToBytes(v[3]), 'B')
159 k[v[1]] = { keyA, keyB }
161 return k
164 -- main
165 local function main(args)
167 print( string.rep('==', 30) )
168 print()
170 local uid = '11223344'
171 local useUID = false
173 -- Arguments for the script
174 for o, a in getopt.getopt(args, 'hu:') do
175 if o == 'h' then return help() end
176 if o == 'u' then uid = a ; useUID = true end
179 if useUID then
180 -- uid string checks
181 if uid == nil then return oops('empty uid string') end
182 if #uid == 0 then return oops('empty uid string') end
183 if #uid ~= 8 then return oops('uid wrong length. Should be 4 hex bytes') end
184 else
185 -- GET TAG UID
186 local tag, err = lib14a.read(false, true)
187 if not tag then return oops(err) end
188 core.clearCommandBuffer()
190 -- simple tag check
191 if 0x09 ~= tag.sak then
192 if 0x4400 ~= tag.atqa then
193 return oops(('[!] found tag %s :: looking for Mifare Mini 0.3k'):format(tag.name))
196 uid = tag.uid
199 print('|UID|', uid)
201 local keys, err = createKeys( uid )
202 printKeys( keys )
203 dumptofile( uid, keys )
206 main(args)