text
[RRG-proxmark3.git] / client / luascripts / hf_ntag_3d.lua
blob1ee21fe3774b600c9b790f80a62340ea8797b012
1 local getopt = require('getopt')
2 local lib14a = require('read14a')
3 local utils = require('utils')
4 local ansicolors = require('ansicolors')
6 copyright = 'Copyright (c) 2017 IceSQL AB. All rights reserved.'
7 author = "Christian Herrmann"
8 version = 'v1.0.6'
9 desc = [[
10 This script writes a empty template for 3D printing system onto a empty NTAG213 or MAGIC NTAG21*
12 Thanks to @jack for his invaluable input on some of the configuration.
14 example =[[
15 -- This will generate GOLD, PLA, TH, EU, 200m, tagbased uid.
16 script run hf_ntag-3d -c 46 -m 50 -p 5448 -s 4555 -l 200
18 -- This will generate GOLD, PLA, TH, EU, 200m, userbased uid.
19 script run hf_ntag-3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200
21 -- This will generate GOLD, PLA, TH, EU, 200m, userbased uid. and configure a MAGIC NTAG.
22 script run hf_ntag-3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 -1
24 usage = [[
25 script run hf_ntag-3d [-h] [-t] [-u <uid>] [-c <color>] [-m <material>] [-p <region>] [-s <region>] [-l <length>]
27 arguments = [[
28 -h : this help
29 -t : selftest
30 -u <UID> : UID
31 -c <COLOR> : color of filament
32 -m <MATERIAL> : material of filament
33 -p <REGION> : Manufacturer region
34 -s <REGION> : Sales region
35 -l <LENGTH> : Spool length. Use only 100,200,300. 300 has problems on OSX
38 local DEBUG = true
39 local TIMEOUT = 10000 -- 10 seconds
40 local bxor = bit32.bxor
41 local band = bit32.band
42 local rshift = bit32.rshift
44 local _regions = {
45 {'4742', 'GB'},
46 {'5457', 'TW'},
47 {'4555', 'EU'},
48 {'5553', 'US'},
49 {'454E', 'EN'},
50 {'4A50', 'JP'},
51 {'434E', 'CN'},
52 {'5448', 'TH'},
53 {'4153', 'AS'},
54 {'5246', 'RF'},
55 {'4746', 'GF'},
56 {'4341', 'CA'},
57 {'504D', 'PM'},
58 {'5044', 'PD'},
60 local _manufacturers = {
61 {'5457', 'TW'},
62 {'434E', 'CN'},
63 {'5448', 'TH'},
65 local _sales = {
66 {'4742', 'GB'},
67 {'4555', 'EU'},
68 {'5553', 'US'},
69 {'454E', 'EN'},
70 {'504D', 'PM'},
72 local _materials = {
73 {'20', 'Other material'},
74 {'41', 'ABS'},
75 {'46', 'Flexible TPE Tree'},
76 {'46', 'TPE'},
77 {'46', 'PVA'},
78 {'47', 'PETG'},
79 {'50', 'PLA'},
80 {'51', 'PLA'},
81 {'54', 'Tough PLA'},
82 {'55', 'UVCR'},
83 {'56', 'Water Soluble PVA'},
85 local _colors = {
86 {'30', 'Bronze'},
87 {'31', 'Silver'},
88 {'32', 'Clear Red'},
89 {'33', 'Clear'},
90 {'34', 'Bottle Green'},
91 {'35', 'Neon Magenta'},
92 {'36', 'SteelBlue'},
93 {'37', 'Sun Orange'},
94 {'38', 'Pearl White'},
95 {'39', 'Copper'},
96 {'41', 'Purple'},
97 {'42', 'Blue'},
98 {'43', 'Neon Tangerine'},
99 {'44', 'Viridity'},
100 {'45', 'Olivine'},
101 {'46', 'Gold'},
102 {'47', 'Green'},
103 {'48', 'Neon Green'},
104 {'49', 'Snow White'},
105 {'4A', 'Neon Yellow'},
106 {'4B', 'Black'},
107 {'4C', 'Violet'},
108 {'4D', 'Grape Purple'},
109 {'4E', 'Purpurine'},
110 {'4F', 'Clear Yellow'},
111 {'50', 'Clear Green'},
112 {'51', 'Clear Tangerine'},
113 {'52', 'Red'},
114 {'53', 'Cyber Yellow'},
115 {'54', 'Tangerine'},
116 {'55', 'Clear Blue'},
117 {'56', 'Clear Purple'},
118 {'57', 'White'},
119 {'58', 'Clear Magenta'},
120 {'59', 'Yellow'},
121 {'5A', 'Nature'},
125 local function find( arr, name )
126 if not name then return nil end
127 name = name:lower()
128 for k, v in pairs(arr) do
129 if ( v[2]:lower() == name or v[1]:lower() == name ) then
130 return v
133 return nil
137 local function list( arr, desc )
138 print ('Value\t'..desc)
139 print (string.rep('=', 20))
140 for k, v in pairs(arr) do
141 print(("%s\t%s"):format(v[1],v[2]))
145 -- A debug printout-function
146 local function dbg(args)
147 if not DEBUG then return end
148 if type(args) == 'table' then
149 local i = 1
150 while result[i] do
151 dbg(result[i])
152 i = i+1
154 else
155 print('###', args)
159 -- This is only meant to be used when errors occur
160 local function oops(err)
161 print('ERROR:', err)
162 core.clearCommandBuffer()
163 return nil, err
166 -- Usage help
167 local function help()
168 print(copyright)
169 print(author)
170 print(version)
171 print(desc)
172 print(ansicolors.cyan..'Usage'..ansicolors.reset)
173 print(usage)
174 print(ansicolors.cyan..'Arguments'..ansicolors.reset)
175 print(arguments)
176 print(ansicolors.cyan..'Example usage'..ansicolors.reset)
177 print(example)
180 -- Exit message
181 local function ExitMsg(msg)
182 print( string.rep('--',20) )
183 print( string.rep('--',20) )
184 print(msg)
185 print()
189 local function write_tag(uid, t)
191 print('Writing to tag')
192 core.console('hw dbg -0')
193 utils.Sleep(0.5)
195 local cmd = ''
196 local pwd, pack = core.keygen_algo_d(uid)
198 for i= 8, 23 do
199 cmd = ('hf mfu wrbl --blk %02d -d %s -k %08X'):format(i, t[i], pwd)
200 core.console(cmd)
203 --cfg1
204 core.console(('hf mfu wrbl --blk 42 -d %s -k %08X'):format(t[42], pwd))
205 --cfg0
206 core.console(('hf mfu wrbl --blk 41 -d %s -k %08X'):format(t[41], pwd))
207 --dynamic
208 core.console(('hf mfu wrbl --blk 40 -d %s -k %08X'):format(t[40], pwd))
210 core.console('hw dbg -1')
211 utils.Sleep(0.5)
212 print('Done')
215 -- configures a magic NTAG for NTAG213, with UID and PWD,PACK.
216 local function configure_magic_ntag(uid)
218 print('Configuring MAGIC NTAG')
219 -- Save the global args, those are *our* arguments
220 local myargs = args
222 local pwd, pack = core.keygen_algo_d(uid)
224 -- Set the arguments for hf_mfu_magicwrite script v1.0.8
225 -- -t 12 == configure NTAG213F
226 -- -u == set UID
227 -- -p == set pwd
228 -- -a == set pack
229 args =('-t 12 -u %s -p %08X -a %04X'):format(uid, pwd, pack)
230 require('hf_mfu_magicwrite')
232 -- Set back args. Not that it's used, just for the karma...
233 args = myargs
235 print('Done')
238 -- generates random hex numbers between 31-39
239 local function random_num_hex(length)
240 local str = ''
241 local i
242 for i = 1, length, 1 do
243 str = str..math.random(31, 39)
245 return str
249 local function nwo( val )
250 local b1 = band(val, 0xFF)
251 local b2 = band( rshift(val, 8), 0xFF)
252 local b3 = band( rshift(val, 16), 0xFF)
253 local b4 = band( rshift(val, 24), 0xFF)
254 return ('%02X%02X%02X%02X'):format(b1, b2, b3, b4)
257 -- NTAG213 template
258 local function template_NTAG213(uid, material, color, length, manufacture, sales)
259 local pwd, pack = core.keygen_algo_d(uid)
261 local m = tonumber(length, 10) * 1000
262 local m_str = nwo(m)
264 local t = {}
265 -- default empty file
266 for i = 0,42 do
267 t[i] = '00000000'
269 -- t[4] = '0103A00C' --
270 -- t[5] = '340300FE' --
271 -- 6,7
272 t[8] = '5A'..material..color..'00' -- 5A, material, color, 00
273 t[9] = '00'..random_num_hex(3) -- 00, three bytes serial number
274 t[10] = m_str -- total capacity
275 t[11] = m_str -- total capacity
276 t[12] = 'D2002D00' -- fixed
277 t[13] = manufacture..sales -- regioner,
278 t[14] = random_num_hex(4) -- serial number
279 -- 15,16
280 t[17] = '34000000' -- fixed
281 -- 18,19
282 -- remaining capacity of spool
283 t[20] = m_str
284 t[21] = nwo( bxor( m, 0x54321248))
285 t[22] = nwo( bxor( (m - 3876923 ), 0x31275455))
286 t[23] = nwo( bxor( (m + 6923923 ), 0x76235481))
287 -- 24-39
288 t[40] = '000000BD' --dynamic
289 t[41] = '07000008' --cfg0
290 t[42] = '80050000' --cfg1
291 t[43] = ('%08X'):format(pwd)
292 t[44] = ('%04X0000'):format(pack)
293 return t
296 -- outputs the called arguments
297 local function print_conf(uid, material, color, length, producer, sales )
298 print('Create tag as following')
299 print( string.rep('--',16) )
300 print('UID ', uid)
301 print('Material ', material[2])
302 print('Color ', color[2])
303 print('Spool length ', length)
304 print('Region')
305 print(' manufacturer', producer[2])
306 print(' sales ', sales[2])
307 print( string.rep('--',16) )
310 -- self test
311 local function selftest()
312 list(_regions, 'Regions')
313 list(_materials, 'Materials')
314 list(_colors, 'Colors')
315 return nil
318 -- The main entry point
319 local function main(args)
321 math.randomseed(os.time());
322 math.random();
324 print( string.rep('--',20) )
325 print( string.rep('--',20) )
326 print()
328 local uid = '04C5DF4A6D5180'
329 local useUID = false
330 local useMAGIC = false
331 local material, color, length, producer, sales
333 if #args == 0 then return help() end
335 -- Read the parameters
336 for o, a in getopt.getopt(args, 'ht1u:l:m:c:p:s:') do
337 if o == 'h' then return help() end
338 if o == 't' then return selftest() end
339 if o == 'u' then uid = a; useUID = true end
340 if o == 'm' then material = a end
341 if o == 'c' then color = a end
342 if o == 'l' then length = tonumber(a) end
343 if o == 'p' then producer = a end
344 if o == 's' then sales = a end
345 if o == '1' then useMAGIC = true end
348 color = find(_colors, color)
349 if not color then list(_colors, 'Colors'); return oops('\n\nNot valid color') end
351 material = find(_materials, material)
352 if not material then list(_materials, 'Materials'); return oops('\n\nNot valid material') end
354 producer = find(_manufacturers, producer)
355 if not producer then list(_manufacturers, 'Regions Manufacturers'); return oops('\n\nNo valid manufacturer region') end
357 sales = find(_sales, sales)
358 if not sales then list(_sales, 'Regions Sales'); return oops('\n\nNo valid sales region') end
360 if length > 300 then
361 return oops('\n\nNot valid spool length. Must be lesser than 300')
364 if useUID then
365 -- uid string checks
366 if uid == nil then return oops('empty uid string') end
367 if #uid == 0 then return oops('empty uid string') end
368 if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end
369 else
370 -- GET TAG UID
371 local tag, err = lib14a.read(false, true)
372 if not tag then return oops(err) end
373 core.clearCommandBuffer()
374 uid = tag.uid
377 --print
378 print_conf(uid, material, color, length, producer, sales )
380 -- create template
381 local t = template_NTAG213(uid, material[1], color[1], length, producer[1], sales[1])
383 -- using MAGIC NTAG
384 if useMAGIC then
385 configure_magic_ntag(uid)
388 -- write template data to tag
389 write_tag(uid, t)
392 main(args)