RRG-Proxmark3/client/luascripts/hf_ntag_3d.lua
2021-12-22 21:48:25 +01:00

393 lines
10 KiB
Lua

local getopt = require('getopt')
local lib14a = require('read14a')
local utils = require('utils')
local ansicolors = require('ansicolors')
copyright = 'Copyright (c) 2017 IceSQL AB. All rights reserved.'
author = "Christian Herrmann"
version = 'v1.0.6'
desc = [[
This script writes a empty template for 3D printing system onto a empty NTAG213 or MAGIC NTAG21*
Thanks to @jack for his invaluable input on some of the configuration.
]]
example =[[
-- This will generate GOLD, PLA, TH, EU, 200m, tagbased uid.
script run hf_ntag-3d -c 46 -m 50 -p 5448 -s 4555 -l 200
-- This will generate GOLD, PLA, TH, EU, 200m, userbased uid.
script run hf_ntag-3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200
-- This will generate GOLD, PLA, TH, EU, 200m, userbased uid. and configure a MAGIC NTAG.
script run hf_ntag-3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 -1
]]
usage = [[
script run hf_ntag-3d [-h] [-t] [-u <uid>] [-c <color>] [-m <material>] [-p <region>] [-s <region>] [-l <length>]
]]
arguments = [[
-h : this help
-t : selftest
-u <UID> : UID
-c <COLOR> : color of filament
-m <MATERIAL> : material of filament
-p <REGION> : Manufacturer region
-s <REGION> : Sales region
-l <LENGTH> : Spool length. Use only 100,200,300. 300 has problems on OSX
]]
local DEBUG = true
local TIMEOUT = 10000 -- 10 seconds
local bxor = bit32.bxor
local band = bit32.band
local rshift = bit32.rshift
local _regions = {
{'4742', 'GB'},
{'5457', 'TW'},
{'4555', 'EU'},
{'5553', 'US'},
{'454E', 'EN'},
{'4A50', 'JP'},
{'434E', 'CN'},
{'5448', 'TH'},
{'4153', 'AS'},
{'5246', 'RF'},
{'4746', 'GF'},
{'4341', 'CA'},
{'504D', 'PM'},
{'5044', 'PD'},
}
local _manufacturers = {
{'5457', 'TW'},
{'434E', 'CN'},
{'5448', 'TH'},
}
local _sales = {
{'4742', 'GB'},
{'4555', 'EU'},
{'5553', 'US'},
{'454E', 'EN'},
{'504D', 'PM'},
}
local _materials = {
{'20', 'Other material'},
{'41', 'ABS'},
{'46', 'Flexible TPE Tree'},
{'46', 'TPE'},
{'46', 'PVA'},
{'47', 'PETG'},
{'50', 'PLA'},
{'51', 'PLA'},
{'54', 'Tough PLA'},
{'55', 'UVCR'},
{'56', 'Water Soluble PVA'},
}
local _colors = {
{'30', 'Bronze'},
{'31', 'Silver'},
{'32', 'Clear Red'},
{'33', 'Clear'},
{'34', 'Bottle Green'},
{'35', 'Neon Magenta'},
{'36', 'SteelBlue'},
{'37', 'Sun Orange'},
{'38', 'Pearl White'},
{'39', 'Copper'},
{'41', 'Purple'},
{'42', 'Blue'},
{'43', 'Neon Tangerine'},
{'44', 'Viridity'},
{'45', 'Olivine'},
{'46', 'Gold'},
{'47', 'Green'},
{'48', 'Neon Green'},
{'49', 'Snow White'},
{'4A', 'Neon Yellow'},
{'4B', 'Black'},
{'4C', 'Violet'},
{'4D', 'Grape Purple'},
{'4E', 'Purpurine'},
{'4F', 'Clear Yellow'},
{'50', 'Clear Green'},
{'51', 'Clear Tangerine'},
{'52', 'Red'},
{'53', 'Cyber Yellow'},
{'54', 'Tangerine'},
{'55', 'Clear Blue'},
{'56', 'Clear Purple'},
{'57', 'White'},
{'58', 'Clear Magenta'},
{'59', 'Yellow'},
{'5A', 'Nature'},
}
---
--
local function find( arr, name )
if not name then return nil end
name = name:lower()
for k, v in pairs(arr) do
if ( v[2]:lower() == name or v[1]:lower() == name ) then
return v
end
end
return nil
end
---
--
local function list( arr, desc )
print ('Value\t'..desc)
print (string.rep('=', 20))
for k, v in pairs(arr) do
print(("%s\t%s"):format(v[1],v[2]))
end
end
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while result[i] do
dbg(result[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, err
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
--
-- Exit message
local function ExitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
---
--
local function write_tag(uid, t)
print('Writing to tag')
core.console('hw dbg -0')
utils.Sleep(0.5)
local cmd = ''
local pwd, pack = core.keygen_algo_d(uid)
for i= 8, 23 do
cmd = ('hf mfu wrbl --blk %02d -d %s -k %08X'):format(i, t[i], pwd)
core.console(cmd)
end
--cfg1
core.console(('hf mfu wrbl --blk 42 -d %s -k %08X'):format(t[42], pwd))
--cfg0
core.console(('hf mfu wrbl --blk 41 -d %s -k %08X'):format(t[41], pwd))
--dynamic
core.console(('hf mfu wrbl --blk 40 -d %s -k %08X'):format(t[40], pwd))
core.console('hw dbg -1')
utils.Sleep(0.5)
print('Done')
end
---
-- configures a magic NTAG for NTAG213, with UID and PWD,PACK.
local function configure_magic_ntag(uid)
print('Configuring MAGIC NTAG')
-- Save the global args, those are *our* arguments
local myargs = args
local pwd, pack = core.keygen_algo_d(uid)
-- Set the arguments for hf_mfu_magicwrite script v1.0.8
-- -t 12 == configure NTAG213F
-- -u == set UID
-- -p == set pwd
-- -a == set pack
args =('-t 12 -u %s -p %08X -a %04X'):format(uid, pwd, pack)
require('hf_mfu_magicwrite')
-- Set back args. Not that it's used, just for the karma...
args = myargs
print('Done')
end
---
-- generates random hex numbers between 31-39
local function random_num_hex(length)
local str = ''
local i
for i = 1, length, 1 do
str = str..math.random(31, 39)
end
return str
end
---
--
local function nwo( val )
local b1 = band(val, 0xFF)
local b2 = band( rshift(val, 8), 0xFF)
local b3 = band( rshift(val, 16), 0xFF)
local b4 = band( rshift(val, 24), 0xFF)
return ('%02X%02X%02X%02X'):format(b1, b2, b3, b4)
end
---
-- NTAG213 template
local function template_NTAG213(uid, material, color, length, manufacture, sales)
local pwd, pack = core.keygen_algo_d(uid)
local m = tonumber(length, 10) * 1000
local m_str = nwo(m)
local t = {}
-- default empty file
for i = 0,42 do
t[i] = '00000000'
end
-- t[4] = '0103A00C' --
-- t[5] = '340300FE' --
-- 6,7
t[8] = '5A'..material..color..'00' -- 5A, material, color, 00
t[9] = '00'..random_num_hex(3) -- 00, three bytes serial number
t[10] = m_str -- total capacity
t[11] = m_str -- total capacity
t[12] = 'D2002D00' -- fixed
t[13] = manufacture..sales -- regioner,
t[14] = random_num_hex(4) -- serial number
-- 15,16
t[17] = '34000000' -- fixed
-- 18,19
-- remaining capacity of spool
t[20] = m_str
t[21] = nwo( bxor( m, 0x54321248))
t[22] = nwo( bxor( (m - 3876923 ), 0x31275455))
t[23] = nwo( bxor( (m + 6923923 ), 0x76235481))
-- 24-39
t[40] = '000000BD' --dynamic
t[41] = '07000008' --cfg0
t[42] = '80050000' --cfg1
t[43] = ('%08X'):format(pwd)
t[44] = ('%04X0000'):format(pack)
return t
end
---
-- outputs the called arguments
local function print_conf(uid, material, color, length, producer, sales )
print('Create tag as following')
print( string.rep('--',16) )
print('UID ', uid)
print('Material ', material[2])
print('Color ', color[2])
print('Spool length ', length)
print('Region')
print(' manufacturer', producer[2])
print(' sales ', sales[2])
print( string.rep('--',16) )
end
---
-- self test
local function selftest()
list(_regions, 'Regions')
list(_materials, 'Materials')
list(_colors, 'Colors')
return nil
end
---
-- The main entry point
local function main(args)
math.randomseed(os.time());
math.random();
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
local uid = '04C5DF4A6D5180'
local useUID = false
local useMAGIC = false
local material, color, length, producer, sales
if #args == 0 then return help() end
-- Read the parameters
for o, a in getopt.getopt(args, 'ht1u:l:m:c:p:s:') do
if o == 'h' then return help() end
if o == 't' then return selftest() end
if o == 'u' then uid = a; useUID = true end
if o == 'm' then material = a end
if o == 'c' then color = a end
if o == 'l' then length = tonumber(a) end
if o == 'p' then producer = a end
if o == 's' then sales = a end
if o == '1' then useMAGIC = true end
end
color = find(_colors, color)
if not color then list(_colors, 'Colors'); return oops('\n\nNot valid color') end
material = find(_materials, material)
if not material then list(_materials, 'Materials'); return oops('\n\nNot valid material') end
producer = find(_manufacturers, producer)
if not producer then list(_manufacturers, 'Regions Manufacturers'); return oops('\n\nNo valid manufacturer region') end
sales = find(_sales, sales)
if not sales then list(_sales, 'Regions Sales'); return oops('\n\nNo valid sales region') end
if length > 300 then
return oops('\n\nNot valid spool length. Must be lesser than 300')
end
if useUID then
-- uid string checks
if uid == nil then return oops('empty uid string') end
if #uid == 0 then return oops('empty uid string') end
if #uid ~= 14 then return oops('uid wrong length. Should be 7 hex bytes') end
else
-- GET TAG UID
local tag, err = lib14a.read(false, true)
if not tag then return oops(err) end
core.clearCommandBuffer()
uid = tag.uid
end
--print
print_conf(uid, material, color, length, producer, sales )
-- create template
local t = template_NTAG213(uid, material[1], color[1], length, producer[1], sales[1])
-- using MAGIC NTAG
if useMAGIC then
configure_magic_ntag(uid)
end
-- write template data to tag
write_tag(uid, t)
end
main(args)