| 1 | --[[ |
| 2 | This is an experimental lib. |
| 3 | --]] |
| 4 | local utils = require('utils') |
| 5 | |
| 6 | -- LOOKUP Tables |
| 7 | local perm = {} |
| 8 | perm [1]= { 0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5, 0xF, 0xE, 0xC, 0xD, 0x8, 0x9, 0xB, 0xA } |
| 9 | perm [2]= { 0x1, 0x0, 0x2, 0x3, 0x6, 0x7, 0x5, 0x4, 0xE, 0xF, 0xD, 0xC, 0x9, 0x8, 0xA, 0xB } |
| 10 | perm [3]= { 0x2, 0x3, 0x1, 0x0, 0x5, 0x4, 0x6, 0x7, 0xD, 0xC, 0xE, 0xF, 0xA, 0xB, 0x9, 0x8 } |
| 11 | perm [4]= { 0x3, 0x2, 0x0, 0x1, 0x4, 0x5, 0x7, 0x6, 0xC, 0xD, 0xF, 0xE, 0xB, 0xA, 0x8, 0x9 } |
| 12 | perm [5]= { 0x4, 0x5, 0x7, 0x6, 0x3, 0x2, 0x0, 0x1, 0xB, 0xA, 0x8, 0x9, 0xC, 0xD, 0xF, 0xE } |
| 13 | perm [6]= { 0x5, 0x4, 0x6, 0x7, 0x2, 0x3, 0x1, 0x0, 0xA, 0xB, 0x9, 0x8, 0xD, 0xC, 0xE, 0xF } |
| 14 | perm [7]= { 0x6, 0x7, 0x5, 0x4, 0x1, 0x0, 0x2, 0x3, 0x9, 0x8, 0xA, 0xB, 0xE, 0xF, 0xD, 0xC } |
| 15 | perm [8]= { 0x7, 0x6, 0x4, 0x5, 0x0, 0x1, 0x3, 0x2, 0x8, 0x9, 0xB, 0xA, 0xF, 0xE, 0xC, 0xD } |
| 16 | perm [9]= { 0x8, 0x9, 0xB, 0xA, 0xF, 0xE, 0xC, 0xD, 0x7, 0x6, 0x4, 0x5, 0x0, 0x1, 0x3, 0x2 } |
| 17 | perm [10]= { 0x9, 0x8, 0xA, 0xB, 0xE, 0xF, 0xD, 0xC, 0x6, 0x7, 0x5, 0x4, 0x1, 0x0, 0x2, 0x3 } |
| 18 | perm [11]= { 0xA, 0xB, 0x9, 0x8, 0xD, 0xC, 0xE, 0xF, 0x5, 0x4, 0x6, 0x7, 0x2, 0x3, 0x1, 0x0 } |
| 19 | perm [12]= { 0xB, 0xA, 0x8, 0x9, 0xC, 0xD, 0xF, 0xE, 0x4, 0x5, 0x7, 0x6, 0x3, 0x2, 0x0, 0x1 } |
| 20 | perm [13]= { 0xC, 0xD, 0xF, 0xE, 0xB, 0xA, 0x8, 0x9, 0x3, 0x2, 0x0, 0x1, 0x4, 0x5, 0x7, 0x6 } |
| 21 | perm [14]= { 0xD, 0xC, 0xE, 0xF, 0xA, 0xB, 0x9, 0x8, 0x2, 0x3, 0x1, 0x0, 0x5, 0x4, 0x6, 0x7 } |
| 22 | perm [15]= { 0xE, 0xF, 0xD, 0xC, 0x9, 0x8, 0xA, 0xB, 0x1, 0x0, 0x2, 0x3, 0x6, 0x7, 0x5, 0x4 } |
| 23 | perm [16]= { 0xF, 0xE, 0xC, 0xD, 0x8, 0x9, 0xB, 0xA, 0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5 } |
| 24 | |
| 25 | local shifts = {} |
| 26 | shifts[1]= { 0x4, 0x5, 0x7, 0x6, 0x3, 0x2, 0x0, 0x1, 0xB, 0xA, 0x8, 0x9, 0xC, 0xD, 0xF, 0xE } |
| 27 | shifts[2]= { 0x4, 0xB, 0xB, 0x4, 0xB, 0x4, 0x4, 0xB, 0xA, 0x5, 0x5, 0xA, 0x5, 0xA, 0xA, 0x5 } |
| 28 | shifts[3]= { 0xB, 0x6, 0x0, 0xD, 0xD, 0x0, 0x6, 0xB, 0x6, 0xB, 0xD, 0x0, 0x0, 0xD, 0xB, 0x6 } |
| 29 | shifts[4]= { 0xE, 0x5, 0x9, 0x2, 0x0, 0xB, 0x7, 0xC, 0x3, 0x8, 0x4, 0xF, 0xD, 0x6, 0xA, 0x1 } |
| 30 | shifts[5]= { 0x4, 0xE, 0x1, 0xB, 0xF, 0x5, 0xA, 0x0, 0x3, 0x9, 0x6, 0xC, 0x8, 0x2, 0xD, 0x7 } |
| 31 | shifts[6]= { 0xA, 0x4, 0x7, 0x9, 0x0, 0xE, 0xD, 0x3, 0xE, 0x0, 0x3, 0xD, 0x4, 0xA, 0x9, 0x7 } |
| 32 | shifts[7]= { 0xE, 0x6, 0xE, 0x6, 0xF, 0x7, 0xF, 0x7, 0xD, 0x5, 0xD, 0x5, 0xC, 0x4, 0xC, 0x4 } |
| 33 | shifts[8]= { 0x7, 0x1, 0xB, 0xD, 0xE, 0x8, 0x2, 0x4, 0x4, 0x2, 0x8, 0xE, 0xD, 0xB, 0x1, 0x7 } |
| 34 | shifts[9]= { 0xD, 0xB, 0x0, 0x6, 0x6, 0x0, 0xB, 0xD, 0xA, 0xC, 0x7, 0x1, 0x1, 0x7, 0xC, 0xA } |
| 35 | shifts[10]= { 0xe, 0x1, 0x1, 0xe, 0x1, 0xe, 0xe, 0x1, 0x1, 0xe, 0xe, 0x1, 0xe, 0x1, 0x1, 0xe } |
| 36 | |
| 37 | local function ApplyPermutationAndShifts( pos, value, nibble) |
| 38 | local shiftbytes = shifts[pos] |
| 39 | local shiftElem = shiftbytes[nibble+1] --one indexed |
| 40 | local shiftOne = shiftbytes[1] |
| 41 | local rs = bit32.bxor(value, bit32.bxor(shiftOne, shiftElem)) |
| 42 | return rs |
| 43 | end |
| 44 | |
| 45 | local function GetOne( uid, block ) |
| 46 | |
| 47 | if uid == nil then return nil, 'empty uid string' end |
| 48 | if #uid == 0 then return nil, 'empty uid string' end |
| 49 | if #uid ~= 8 then return nil, 'uid wrong length. Should be 4 hex bytes' end |
| 50 | if type(block) ~= 'number' then return nil, 'block is not number' end |
| 51 | if block > 16 or block < 0 then return nil, 'block is out-of-range' end |
| 52 | |
| 53 | local s = ('%s%02X'):format(uid,block) |
| 54 | local nibble1 = tonumber(s:sub(1,1),16) + 1 |
| 55 | |
| 56 | local permuted = '' |
| 57 | for i = 1, #s do |
| 58 | local el_row = shifts[i] |
| 59 | local el_value = el_row[nibble1] |
| 60 | j = 1 |
| 61 | while j <= i do |
| 62 | if i-j > 0 then |
| 63 | local nibble = tonumber(s:sub(j+1,j+1),16) |
| 64 | el_value = ApplyPermutationAndShifts(i-j, el_value, nibble) |
| 65 | end |
| 66 | j = j+1 |
| 67 | end |
| 68 | permuted =('%s%X'):format(permuted,el_value) |
| 69 | end |
| 70 | |
| 71 | permuted = 'C2'..permuted |
| 72 | local crc64numStr = utils.Crc64(permuted) |
| 73 | local keybytes = utils.ConvertAsciiToBytes(crc64numStr, true) |
| 74 | local key = utils.ConvertBytesToHex(keybytes) |
| 75 | return key:sub(1,12) |
| 76 | end |
| 77 | |
| 78 | local PreCalc = |
| 79 | { |
| 80 | GetAll = function(id) |
| 81 | if id == nil then return nil, 'empty string' end |
| 82 | if #id == 0 then return nil, 'empty string' end |
| 83 | if #id ~= 8 then return nil, 'wrong length. Should be 4 hex bytes' end |
| 84 | |
| 85 | local list = '4b0b20107ccb' |
| 86 | for i = 1,15 do |
| 87 | local key, err = GetOne(id,i) |
| 88 | if not key then return oops(err) end |
| 89 | list = list..key |
| 90 | end |
| 91 | return list |
| 92 | end, |
| 93 | } |
| 94 | return PreCalc |