Advertisement
HydrantHunter

cc10 Remote

Jun 12th, 2013
3,092
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 67.98 KB | None | 0 0
  1. --[[    cc10 Remote    ]]--
  2. --[[      by Dog       ]]--
  3. --[[ aka HydrantHunter ]]--
  4. --[[  with assistance  ]]--
  5. --[[   from CometWolf  ]]--
  6. --[[ pastebin mbEHZZnh ]]--
  7. local cc10Rver = "2.0.04"
  8. --[[
  9. Tested with/requires:
  10.   - Minecraft 1.6.4+
  11.   - ComputerCraft 1.63+
  12.     - 1 Advanced Wireless Pocket Computer
  13.     - cc10host running on a Computer (standard or advanced) with a wireless modem
  14.                        or a Wireless Turtle (standard or advanced)
  15.  
  16. Special thanks to: Anavrins   (pbkdf2/sha256 hashing)
  17.                    SquidDev   (AES encryption/decryption)
  18.                    Alex Kloss (base64 encoder/decoder)
  19. ]]--
  20. --# AUTOMATIC/STATIC CONFIGURATION
  21. --# Default Settings
  22. local termX, termY = term.getSize()
  23. local netSide, runState, thisCC = "none", "init", tostring(os.getComputerID())
  24. local kernelState, timerDelay, inputting = true, false, false
  25. local drawCLI, netReceive, userInput, pollTimer, tempState
  26. --# Device List
  27. local allDevices, filteredDevices = { }, { }
  28. local numPages, pageNum = 1, 1
  29. local uFilter = false
  30. local thisDevice, cc10host
  31. local cc10Types = {
  32.   A = { "Analog", "UA" };
  33.   UA = { "U-Analog", "D" };
  34.   D = { "Digital", "UD" };
  35.   UD = { "U-Digital", "PS" };
  36.   PS = { "Pulsed-S", "PL" };
  37.   PL = { "Pulsed-L", "P3" };
  38.   P3 = { "Pulsed-3", "A" };
  39. }
  40. local colorBurst = {
  41.   G = { order = 1, text = "Green", color = colors.green };
  42.   S = { order = 2, text = "Sky", color = colors.lightBlue };
  43.   B = { order = 3, text = "Blue", color = colors.blue };
  44.   P = { order = 4, text = "Purple", color = colors.purple };
  45.   R = { order = 5, text = "Red", color = colors.red };
  46.   O = { order = 6, text = "Orange", color = colors.orange };
  47.   N = { order = 7, text = "Brown", color = colors.brown };
  48.   I = { order = 8, text = "Silver", color = colors.lightGray };
  49. }
  50. --# Color Definitions
  51. local white = colors.white
  52. local black = colors.black
  53. local silver = colors.lightGray
  54. local gray = colors.gray
  55. local brown = colors.brown
  56. local yellow = colors.yellow
  57. local orange = colors.orange
  58. local red = colors.red
  59. local magenta = colors.magenta
  60. local purple = colors.purple
  61. local blue = colors.blue
  62. local sky = colors.lightBlue
  63. local cyan = colors.cyan
  64. local lime = colors.lime
  65. local green = colors.green
  66. --local colorX, word
  67. --local curX, curY
  68. --# END AUTOMATIC/STATIC CONFIGURATION
  69.  
  70. -- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
  71. -- licensed under the terms of the LGPL2
  72. -- http://lua-users.org/wiki/BaseSixtyFour
  73. -- character table string
  74. local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  75. -- encoding
  76. function encode(data)
  77.   return ((data:gsub('.', function(x)
  78.     local r,b='',x:byte()
  79.     for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
  80.     return r;
  81.   end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
  82.     if (#x < 6) then return '' end
  83.     local c=0
  84.     for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
  85.     return b:sub(c+1,c+1)
  86.   end)..({ '', '==', '=' })[#data%3+1])
  87. end
  88. -- decoding
  89. function decode(data)
  90.   data = string.gsub(data, '[^'..b..'=]', '')
  91.   return (data:gsub('.', function(x)
  92.     if (x == '=') then return '' end
  93.     local r,f='',(b:find(x)-1)
  94.     for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
  95.     return r;
  96.   end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
  97.     if (#x ~= 8) then return '' end
  98.     local c=0
  99.     for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
  100.     return string.char(c)
  101.   end))
  102. end
  103.  
  104. -- AES Lua implementation by SquidDev
  105. -- https://gist.github.com/SquidDev/86925e07cbabd70773e53d781bd8b2fe
  106. local encrypt, decrypt
  107. do
  108.   local function _W(f) local e=setmetatable({}, {__index = _ENV or getfenv()}) if setfenv then setfenv(f, e) end return f(e) or e end
  109.   local bit=_W(function(_ENV, ...)
  110.   --[[
  111.     This bit API is designed to cope with unsigned integers instead of normal integers
  112.     To do this we add checks for overflows: (x > 2^31 ? x - 2 ^ 32 : x)
  113.     These are written in long form because no constant folding.
  114.   ]]
  115.   local floor = math.floor
  116.   local lshift, rshift
  117.  
  118.   rshift = function(a,disp)
  119.     return floor(a % 4294967296 / 2^disp)
  120.   end
  121.  
  122.   lshift = function(a,disp)
  123.     return (a * 2^disp) % 4294967296
  124.   end
  125.  
  126.   return {
  127.     -- bit operations
  128.     bnot = bit32 and bit32.bnot or bit.bnot,
  129.     band = bit32 and bit32.band or bit.band,
  130.     bor  = bit32 and bit32.bor or bit.bor,
  131.     bxor = bit32 and bit32.bxor or bit.bxor,
  132.     rshift = rshift,
  133.     lshift = lshift,
  134.   }
  135.   end)
  136.  
  137.   local gf=_W(function(_ENV, ...)
  138.   -- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d
  139.   local bxor = bit32 and bit32.bxor or bit.bxor
  140.   local lshift = bit.lshift
  141.   -- private data of gf
  142.   local n = 0x100
  143.   local ord = 0xff
  144.   local irrPolynom = 0x11b
  145.   local exp = {}
  146.   local log = {}
  147.   --
  148.   -- add two polynoms (its simply xor)
  149.   --
  150.   local function add(operand1, operand2)
  151.     return bxor(operand1,operand2)
  152.   end
  153.   --
  154.   -- subtract two polynoms (same as addition)
  155.   --
  156.   local function sub(operand1, operand2)
  157.     return bxor(operand1,operand2)
  158.   end
  159.   --
  160.   -- inverts element
  161.   -- a^(-1) = g^(order - log(a))
  162.   --
  163.   local function invert(operand)
  164.     -- special case for 1
  165.     if (operand == 1) then
  166.       return 1
  167.     end
  168.     -- normal invert
  169.     local exponent = ord - log[operand]
  170.     return exp[exponent]
  171.   end
  172.   --
  173.   -- multiply two elements using a logarithm table
  174.   -- a*b = g^(log(a)+log(b))
  175.   --
  176.   local function mul(operand1, operand2)
  177.     if (operand1 == 0 or operand2 == 0) then
  178.       return 0
  179.     end
  180.     local exponent = log[operand1] + log[operand2]
  181.     if (exponent >= ord) then
  182.       exponent = exponent - ord
  183.     end
  184.     return exp[exponent]
  185.   end
  186.   --
  187.   -- divide two elements
  188.   -- a/b = g^(log(a)-log(b))
  189.   --
  190.   local function div(operand1, operand2)
  191.     if (operand1 == 0)  then
  192.       return 0
  193.     end
  194.     -- TODO: exception if operand2 == 0
  195.     local exponent = log[operand1] - log[operand2]
  196.     if (exponent < 0) then
  197.       exponent = exponent + ord
  198.     end
  199.     return exp[exponent]
  200.   end
  201.   --
  202.   -- print logarithmic table
  203.   --
  204.   local function printLog()
  205.     for i = 1, n do
  206.       print("log(", i-1, ")=", log[i-1])
  207.     end
  208.   end
  209.   --
  210.   -- print exponentiation table
  211.   --
  212.   local function printExp()
  213.     for i = 1, n do
  214.       print("exp(", i-1, ")=", exp[i-1])
  215.     end
  216.   end
  217.   --
  218.   -- calculate logarithmic and exponentiation table
  219.   --
  220.   local function initMulTable()
  221.     local a = 1
  222.     for i = 0,ord-1 do
  223.       exp[i] = a
  224.       log[a] = i
  225.       -- multiply with generator x+1 -> left shift + 1
  226.       a = bxor(lshift(a, 1), a)
  227.       -- if a gets larger than order, reduce modulo irreducible polynom
  228.       if a > ord then
  229.         a = sub(a, irrPolynom)
  230.       end
  231.     end
  232.   end
  233.  
  234.   initMulTable()
  235.  
  236.   return {
  237.     add = add,
  238.     sub = sub,
  239.     invert = invert,
  240.     mul = mul,
  241.     div = div,
  242.     printLog = printLog,
  243.     printExp = printExp,
  244.   }
  245.   end)
  246.  
  247.   util=_W(function(_ENV, ...)
  248.   -- Cache some bit operators
  249.   local bxor = bit.bxor
  250.   local rshift = bit.rshift
  251.   local band = bit.band
  252.   local lshift = bit.lshift
  253.   local sleepCheckIn
  254.   --
  255.   -- calculate the parity of one byte
  256.   --
  257.   local function byteParity(byte)
  258.     byte = bxor(byte, rshift(byte, 4))
  259.     byte = bxor(byte, rshift(byte, 2))
  260.     byte = bxor(byte, rshift(byte, 1))
  261.     return band(byte, 1)
  262.   end
  263.   --
  264.   -- get byte at position index
  265.   --
  266.   local function getByte(number, index)
  267.     return index == 0 and band(number,0xff) or band(rshift(number, index*8),0xff)
  268.   end
  269.   --
  270.   -- put number into int at position index
  271.   --
  272.   local function putByte(number, index)
  273.     return index == 0 and band(number,0xff) or lshift(band(number,0xff),index*8)
  274.   end
  275.   --
  276.   -- convert byte array to int array
  277.   --
  278.   local function bytesToInts(bytes, start, n)
  279.     local ints = {}
  280.     for i = 0, n - 1 do
  281.       ints[i + 1] =
  282.           putByte(bytes[start + (i*4)], 3) +
  283.           putByte(bytes[start + (i*4) + 1], 2) +
  284.           putByte(bytes[start + (i*4) + 2], 1) +
  285.           putByte(bytes[start + (i*4) + 3], 0)
  286.       if n % 10000 == 0 then sleepCheckIn() end
  287.     end
  288.     return ints
  289.   end
  290.   --
  291.   -- convert int array to byte array
  292.   --
  293.   local function intsToBytes(ints, output, outputOffset, n)
  294.     n = n or #ints
  295.     for i = 0, n - 1 do
  296.       for j = 0,3 do
  297.         output[outputOffset + i*4 + (3 - j)] = getByte(ints[i + 1], j)
  298.       end
  299.       if n % 10000 == 0 then sleepCheckIn() end
  300.     end
  301.     return output
  302.   end
  303.   --
  304.   -- convert bytes to hexString
  305.   --
  306.   local function bytesToHex(bytes)
  307.     local hexBytes = ""
  308.     for i,byte in ipairs(bytes) do
  309.       hexBytes = hexBytes .. string.format("%02x ", byte)
  310.     end
  311.     return hexBytes
  312.   end
  313.  
  314.   local function hexToBytes(bytes)
  315.     local out = {}
  316.     for i = 1, #bytes, 2 do
  317.       out[#out + 1] = tonumber(bytes:sub(i, i + 1), 16)
  318.     end
  319.     return out
  320.   end
  321.   --
  322.   -- convert data to hex string
  323.   --
  324.   local function toHexString(data)
  325.     local type = type(data)
  326.     if (type == "number") then
  327.       return string.format("%08x",data)
  328.     elseif (type == "table") then
  329.       return bytesToHex(data)
  330.     elseif (type == "string") then
  331.       local bytes = {string.byte(data, 1, #data)}
  332.       return bytesToHex(bytes)
  333.     else
  334.       return data
  335.     end
  336.   end
  337.  
  338.   local function padByteString(data)
  339.     local dataLength = #data
  340.     local random1 = math.random(0,255)
  341.     local random2 = math.random(0,255)
  342.     local prefix = string.char(random1,
  343.       random2,
  344.       random1,
  345.       random2,
  346.       getByte(dataLength, 3),
  347.       getByte(dataLength, 2),
  348.       getByte(dataLength, 1),
  349.       getByte(dataLength, 0)
  350.     )
  351.     data = prefix .. data
  352.     local padding, paddingLength = "", math.ceil(#data/16)*16 - #data
  353.     for i=1,paddingLength do
  354.       padding = padding .. string.char(math.random(0,255))
  355.     end
  356.     return data .. padding
  357.   end
  358.  
  359.   local function properlyDecrypted(data)
  360.     local random = {string.byte(data,1,4)}
  361.     if (random[1] == random[3] and random[2] == random[4]) then
  362.       return true
  363.     end
  364.     return false
  365.   end
  366.  
  367.   local function unpadByteString(data)
  368.     if (not properlyDecrypted(data)) then
  369.       return nil
  370.     end
  371.     local dataLength = putByte(string.byte(data,5), 3)
  372.              + putByte(string.byte(data,6), 2)
  373.              + putByte(string.byte(data,7), 1)
  374.              + putByte(string.byte(data,8), 0)
  375.     return string.sub(data,9,8+dataLength)
  376.   end
  377.  
  378.   local function xorIV(data, iv)
  379.     for i = 1,16 do
  380.       data[i] = bxor(data[i], iv[i])
  381.     end
  382.   end
  383.  
  384.   local function increment(data)
  385.     local i = 16
  386.     while true do
  387.       local value = data[i] + 1
  388.       if value >= 256 then
  389.         data[i] = value - 256
  390.         i = (i - 2) % 16 + 1
  391.       else
  392.         data[i] = value
  393.         break
  394.       end
  395.     end
  396.   end
  397.  
  398.   -- Called every encryption cycle
  399.   local push, pull, time = os.queueEvent, coroutine.yield, os.time
  400.   local oldTime = time()
  401.   local function sleepCheckIn()
  402.     local newTime = time()
  403.     if newTime - oldTime >= 0.03 then -- (0.020 * 1.5)
  404.       oldTime = newTime
  405.       push("sleep")
  406.       pull("sleep")
  407.     end
  408.   end
  409.  
  410.   local function getRandomData(bytes)
  411.     local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
  412.     local result = {}
  413.     for i=1,bytes do
  414.       insert(result, random(0,255))
  415.       if i % 10240 == 0 then sleep() end
  416.     end
  417.     return result
  418.   end
  419.  
  420.   local function getRandomString(bytes)
  421.     local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
  422.     local result = {}
  423.     for i=1,bytes do
  424.       insert(result, char(random(0,255)))
  425.       if i % 10240 == 0 then sleep() end
  426.     end
  427.     return table.concat(result)
  428.   end
  429.  
  430.   return {
  431.     byteParity = byteParity,
  432.     getByte = getByte,
  433.     putByte = putByte,
  434.     bytesToInts = bytesToInts,
  435.     intsToBytes = intsToBytes,
  436.     bytesToHex = bytesToHex,
  437.     hexToBytes = hexToBytes,
  438.     toHexString = toHexString,
  439.     padByteString = padByteString,
  440.     properlyDecrypted = properlyDecrypted,
  441.     unpadByteString = unpadByteString,
  442.     xorIV = xorIV,
  443.     increment = increment,
  444.     sleepCheckIn = sleepCheckIn,
  445.     getRandomData = getRandomData,
  446.     getRandomString = getRandomString,
  447.   }
  448.   end)
  449.  
  450.   aes=_W(function(_ENV, ...)
  451.   -- Implementation of AES with nearly pure lua
  452.   -- AES with lua is slow, really slow :-)
  453.   local putByte = util.putByte
  454.   local getByte = util.getByte
  455.   -- some constants
  456.   local ROUNDS = 'rounds'
  457.   local KEY_TYPE = "type"
  458.   local ENCRYPTION_KEY=1
  459.   local DECRYPTION_KEY=2
  460.   -- aes SBOX
  461.   local SBox = {}
  462.   local iSBox = {}
  463.   -- aes tables
  464.   local table0 = {}
  465.   local table1 = {}
  466.   local table2 = {}
  467.   local table3 = {}
  468.   local tableInv0 = {}
  469.   local tableInv1 = {}
  470.   local tableInv2 = {}
  471.   local tableInv3 = {}
  472.   -- round constants
  473.   local rCon = {
  474.     0x01000000,
  475.     0x02000000,
  476.     0x04000000,
  477.     0x08000000,
  478.     0x10000000,
  479.     0x20000000,
  480.     0x40000000,
  481.     0x80000000,
  482.     0x1b000000,
  483.     0x36000000,
  484.     0x6c000000,
  485.     0xd8000000,
  486.     0xab000000,
  487.     0x4d000000,
  488.     0x9a000000,
  489.     0x2f000000,
  490.   }
  491.   --
  492.   -- affine transformation for calculating the S-Box of AES
  493.   --
  494.   local function affinMap(byte)
  495.     mask = 0xf8
  496.     result = 0
  497.     for i = 1,8 do
  498.       result = bit.lshift(result,1)
  499.       parity = util.byteParity(bit.band(byte,mask))
  500.       result = result + parity
  501.       -- simulate roll
  502.       lastbit = bit.band(mask, 1)
  503.       mask = bit.band(bit.rshift(mask, 1),0xff)
  504.       mask = lastbit ~= 0 and bit.bor(mask, 0x80) or bit.band(mask, 0x7f)
  505.     end
  506.     return bit.bxor(result, 0x63)
  507.   end
  508.   --
  509.   -- calculate S-Box and inverse S-Box of AES
  510.   -- apply affine transformation to inverse in finite field 2^8
  511.   --
  512.   local function calcSBox()
  513.     for i = 0, 255 do
  514.       inverse = i ~= 0 and gf.invert(i) or i
  515.       mapped = affinMap(inverse)
  516.       SBox[i] = mapped
  517.       iSBox[mapped] = i
  518.     end
  519.   end
  520.   --
  521.   -- Calculate round tables
  522.   -- round tables are used to calculate shiftRow, MixColumn and SubBytes
  523.   -- with 4 table lookups and 4 xor operations.
  524.   --
  525.   local function calcRoundTables()
  526.     for x = 0,255 do
  527.       byte = SBox[x]
  528.       table0[x] = putByte(gf.mul(0x03, byte), 0)
  529.                 + putByte(             byte , 1)
  530.                 + putByte(             byte , 2)
  531.                 + putByte(gf.mul(0x02, byte), 3)
  532.       table1[x] = putByte(             byte , 0)
  533.                 + putByte(             byte , 1)
  534.                 + putByte(gf.mul(0x02, byte), 2)
  535.                 + putByte(gf.mul(0x03, byte), 3)
  536.       table2[x] = putByte(             byte , 0)
  537.                 + putByte(gf.mul(0x02, byte), 1)
  538.                 + putByte(gf.mul(0x03, byte), 2)
  539.                 + putByte(             byte , 3)
  540.       table3[x] = putByte(gf.mul(0x02, byte), 0)
  541.                 + putByte(gf.mul(0x03, byte), 1)
  542.                 + putByte(             byte , 2)
  543.                 + putByte(             byte , 3)
  544.     end
  545.   end
  546.   --
  547.   -- Calculate inverse round tables
  548.   -- does the inverse of the normal roundtables for the equivalent
  549.   -- decryption algorithm.
  550.   --
  551.   local function calcInvRoundTables()
  552.     for x = 0,255 do
  553.       byte = iSBox[x]
  554.       tableInv0[x] = putByte(gf.mul(0x0b, byte), 0)
  555.                  + putByte(gf.mul(0x0d, byte), 1)
  556.                  + putByte(gf.mul(0x09, byte), 2)
  557.                  + putByte(gf.mul(0x0e, byte), 3)
  558.       tableInv1[x] = putByte(gf.mul(0x0d, byte), 0)
  559.                  + putByte(gf.mul(0x09, byte), 1)
  560.                  + putByte(gf.mul(0x0e, byte), 2)
  561.                  + putByte(gf.mul(0x0b, byte), 3)
  562.       tableInv2[x] = putByte(gf.mul(0x09, byte), 0)
  563.                  + putByte(gf.mul(0x0e, byte), 1)
  564.                  + putByte(gf.mul(0x0b, byte), 2)
  565.                  + putByte(gf.mul(0x0d, byte), 3)
  566.       tableInv3[x] = putByte(gf.mul(0x0e, byte), 0)
  567.                  + putByte(gf.mul(0x0b, byte), 1)
  568.                  + putByte(gf.mul(0x0d, byte), 2)
  569.                  + putByte(gf.mul(0x09, byte), 3)
  570.     end
  571.   end
  572.   --
  573.   -- rotate word: 0xaabbccdd gets 0xbbccddaa
  574.   -- used for key schedule
  575.   --
  576.   local function rotWord(word)
  577.     local tmp = bit.band(word,0xff000000)
  578.     return (bit.lshift(word,8) + bit.rshift(tmp,24))
  579.   end
  580.   --
  581.   -- replace all bytes in a word with the SBox.
  582.   -- used for key schedule
  583.   --
  584.   local function subWord(word)
  585.     return putByte(SBox[getByte(word,0)],0)
  586.       + putByte(SBox[getByte(word,1)],1)
  587.       + putByte(SBox[getByte(word,2)],2)
  588.       + putByte(SBox[getByte(word,3)],3)
  589.   end
  590.   --
  591.   -- generate key schedule for aes encryption
  592.   --
  593.   -- returns table with all round keys and
  594.   -- the necessary number of rounds saved in [ROUNDS]
  595.   --
  596.   local function expandEncryptionKey(key)
  597.     local keySchedule = {}
  598.     local keyWords = math.floor(#key / 4)
  599.     if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then
  600.       error("Invalid key size: " .. tostring(keyWords))
  601.       return nil
  602.     end
  603.     keySchedule[ROUNDS] = keyWords + 6
  604.     keySchedule[KEY_TYPE] = ENCRYPTION_KEY
  605.     for i = 0,keyWords - 1 do
  606.       keySchedule[i] = putByte(key[i*4+1], 3)
  607.                + putByte(key[i*4+2], 2)
  608.                + putByte(key[i*4+3], 1)
  609.                + putByte(key[i*4+4], 0)
  610.     end
  611.     for i = keyWords, (keySchedule[ROUNDS] + 1)*4 - 1 do
  612.       local tmp = keySchedule[i-1]
  613.       if ( i % keyWords == 0) then
  614.         tmp = rotWord(tmp)
  615.         tmp = subWord(tmp)
  616.         local index = math.floor(i/keyWords)
  617.         tmp = bit.bxor(tmp,rCon[index])
  618.       elseif (keyWords > 6 and i % keyWords == 4) then
  619.         tmp = subWord(tmp)
  620.       end
  621.       keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp)
  622.     end
  623.     return keySchedule
  624.   end
  625.   --
  626.   -- Inverse mix column
  627.   -- used for key schedule of decryption key
  628.   --
  629.   local function invMixColumnOld(word)
  630.     local b0 = getByte(word,3)
  631.     local b1 = getByte(word,2)
  632.     local b2 = getByte(word,1)
  633.     local b3 = getByte(word,0)
  634.     return putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1),
  635.                          gf.mul(0x0d, b2)),
  636.                          gf.mul(0x09, b3)),
  637.                          gf.mul(0x0e, b0)),3)
  638.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2),
  639.                          gf.mul(0x0d, b3)),
  640.                          gf.mul(0x09, b0)),
  641.                          gf.mul(0x0e, b1)),2)
  642.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3),
  643.                          gf.mul(0x0d, b0)),
  644.                          gf.mul(0x09, b1)),
  645.                          gf.mul(0x0e, b2)),1)
  646.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0),
  647.                          gf.mul(0x0d, b1)),
  648.                          gf.mul(0x09, b2)),
  649.                          gf.mul(0x0e, b3)),0)
  650.   end
  651.   --
  652.   -- Optimized inverse mix column
  653.   -- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
  654.   -- TODO: make it work
  655.   --
  656.   local function invMixColumn(word)
  657.     local b0 = getByte(word,3)
  658.     local b1 = getByte(word,2)
  659.     local b2 = getByte(word,1)
  660.     local b3 = getByte(word,0)
  661.     local t = bit.bxor(b3,b2)
  662.     local u = bit.bxor(b1,b0)
  663.     local v = bit.bxor(t,u)
  664.     v = bit.bxor(v,gf.mul(0x08,v))
  665.     w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0)))
  666.     v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1)))
  667.     return putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0)
  668.        + putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t              )), 1)
  669.        + putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2)
  670.        + putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u              )), 3)
  671.   end
  672.   --
  673.   -- generate key schedule for aes decryption
  674.   --
  675.   -- uses key schedule for aes encryption and transforms each
  676.   -- key by inverse mix column.
  677.   --
  678.   local function expandDecryptionKey(key)
  679.     local keySchedule = expandEncryptionKey(key)
  680.     if (keySchedule == nil) then
  681.       return nil
  682.     end
  683.     keySchedule[KEY_TYPE] = DECRYPTION_KEY
  684.     for i = 4, (keySchedule[ROUNDS] + 1)*4 - 5 do
  685.       keySchedule[i] = invMixColumnOld(keySchedule[i])
  686.     end
  687.     return keySchedule
  688.   end
  689.   --
  690.   -- xor round key to state
  691.   --
  692.   local function addRoundKey(state, key, round)
  693.     for i = 0, 3 do
  694.       state[i + 1] = bit.bxor(state[i + 1], key[round*4+i])
  695.     end
  696.   end
  697.   --
  698.   -- do encryption round (ShiftRow, SubBytes, MixColumn together)
  699.   --
  700.   local function doRound(origState, dstState)
  701.     dstState[1] =  bit.bxor(bit.bxor(bit.bxor(
  702.           table0[getByte(origState[1],3)],
  703.           table1[getByte(origState[2],2)]),
  704.           table2[getByte(origState[3],1)]),
  705.           table3[getByte(origState[4],0)])
  706.     dstState[2] =  bit.bxor(bit.bxor(bit.bxor(
  707.           table0[getByte(origState[2],3)],
  708.           table1[getByte(origState[3],2)]),
  709.           table2[getByte(origState[4],1)]),
  710.           table3[getByte(origState[1],0)])
  711.     dstState[3] =  bit.bxor(bit.bxor(bit.bxor(
  712.           table0[getByte(origState[3],3)],
  713.           table1[getByte(origState[4],2)]),
  714.           table2[getByte(origState[1],1)]),
  715.           table3[getByte(origState[2],0)])
  716.     dstState[4] =  bit.bxor(bit.bxor(bit.bxor(
  717.           table0[getByte(origState[4],3)],
  718.           table1[getByte(origState[1],2)]),
  719.           table2[getByte(origState[2],1)]),
  720.           table3[getByte(origState[3],0)])
  721.   end
  722.   --
  723.   -- do last encryption round (ShiftRow and SubBytes)
  724.   --
  725.   local function doLastRound(origState, dstState)
  726.     dstState[1] = putByte(SBox[getByte(origState[1],3)], 3)
  727.           + putByte(SBox[getByte(origState[2],2)], 2)
  728.           + putByte(SBox[getByte(origState[3],1)], 1)
  729.           + putByte(SBox[getByte(origState[4],0)], 0)
  730.     dstState[2] = putByte(SBox[getByte(origState[2],3)], 3)
  731.           + putByte(SBox[getByte(origState[3],2)], 2)
  732.           + putByte(SBox[getByte(origState[4],1)], 1)
  733.           + putByte(SBox[getByte(origState[1],0)], 0)
  734.     dstState[3] = putByte(SBox[getByte(origState[3],3)], 3)
  735.           + putByte(SBox[getByte(origState[4],2)], 2)
  736.           + putByte(SBox[getByte(origState[1],1)], 1)
  737.           + putByte(SBox[getByte(origState[2],0)], 0)
  738.     dstState[4] = putByte(SBox[getByte(origState[4],3)], 3)
  739.           + putByte(SBox[getByte(origState[1],2)], 2)
  740.           + putByte(SBox[getByte(origState[2],1)], 1)
  741.           + putByte(SBox[getByte(origState[3],0)], 0)
  742.   end
  743.   --
  744.   -- do decryption round
  745.   --
  746.   local function doInvRound(origState, dstState)
  747.     dstState[1] =  bit.bxor(bit.bxor(bit.bxor(
  748.           tableInv0[getByte(origState[1],3)],
  749.           tableInv1[getByte(origState[4],2)]),
  750.           tableInv2[getByte(origState[3],1)]),
  751.           tableInv3[getByte(origState[2],0)])
  752.     dstState[2] =  bit.bxor(bit.bxor(bit.bxor(
  753.           tableInv0[getByte(origState[2],3)],
  754.           tableInv1[getByte(origState[1],2)]),
  755.           tableInv2[getByte(origState[4],1)]),
  756.           tableInv3[getByte(origState[3],0)])
  757.     dstState[3] =  bit.bxor(bit.bxor(bit.bxor(
  758.           tableInv0[getByte(origState[3],3)],
  759.           tableInv1[getByte(origState[2],2)]),
  760.           tableInv2[getByte(origState[1],1)]),
  761.           tableInv3[getByte(origState[4],0)])
  762.     dstState[4] =  bit.bxor(bit.bxor(bit.bxor(
  763.           tableInv0[getByte(origState[4],3)],
  764.           tableInv1[getByte(origState[3],2)]),
  765.           tableInv2[getByte(origState[2],1)]),
  766.           tableInv3[getByte(origState[1],0)])
  767.   end
  768.   --
  769.   -- do last decryption round
  770.   --
  771.   local function doInvLastRound(origState, dstState)
  772.     dstState[1] = putByte(iSBox[getByte(origState[1],3)], 3)
  773.           + putByte(iSBox[getByte(origState[4],2)], 2)
  774.           + putByte(iSBox[getByte(origState[3],1)], 1)
  775.           + putByte(iSBox[getByte(origState[2],0)], 0)
  776.     dstState[2] = putByte(iSBox[getByte(origState[2],3)], 3)
  777.           + putByte(iSBox[getByte(origState[1],2)], 2)
  778.           + putByte(iSBox[getByte(origState[4],1)], 1)
  779.           + putByte(iSBox[getByte(origState[3],0)], 0)
  780.     dstState[3] = putByte(iSBox[getByte(origState[3],3)], 3)
  781.           + putByte(iSBox[getByte(origState[2],2)], 2)
  782.           + putByte(iSBox[getByte(origState[1],1)], 1)
  783.           + putByte(iSBox[getByte(origState[4],0)], 0)
  784.     dstState[4] = putByte(iSBox[getByte(origState[4],3)], 3)
  785.           + putByte(iSBox[getByte(origState[3],2)], 2)
  786.           + putByte(iSBox[getByte(origState[2],1)], 1)
  787.           + putByte(iSBox[getByte(origState[1],0)], 0)
  788.   end
  789.   --
  790.   -- encrypts 16 Bytes
  791.   -- key           encryption key schedule
  792.   -- input         array with input data
  793.   -- inputOffset   start index for input
  794.   -- output        array for encrypted data
  795.   -- outputOffset  start index for output
  796.   --
  797.   local function encrypt(key, input, inputOffset, output, outputOffset)
  798.     --default parameters
  799.     inputOffset = inputOffset or 1
  800.     output = output or {}
  801.     outputOffset = outputOffset or 1
  802.     local state = {}
  803.     local tmpState = {}
  804.     if (key[KEY_TYPE] ~= ENCRYPTION_KEY) then
  805.       error("No encryption key: " .. tostring(key[KEY_TYPE]) .. ", expected " .. ENCRYPTION_KEY)
  806.       return
  807.     end
  808.     state = util.bytesToInts(input, inputOffset, 4)
  809.     addRoundKey(state, key, 0)
  810.     local round = 1
  811.     while (round < key[ROUNDS] - 1) do
  812.       -- do a double round to save temporary assignments
  813.       doRound(state, tmpState)
  814.       addRoundKey(tmpState, key, round)
  815.       round = round + 1
  816.       doRound(tmpState, state)
  817.       addRoundKey(state, key, round)
  818.       round = round + 1
  819.     end
  820.     doRound(state, tmpState)
  821.     addRoundKey(tmpState, key, round)
  822.     round = round +1
  823.     doLastRound(tmpState, state)
  824.     addRoundKey(state, key, round)
  825.     util.sleepCheckIn()
  826.     return util.intsToBytes(state, output, outputOffset)
  827.   end
  828.   --
  829.   -- decrypt 16 bytes
  830.   -- key           decryption key schedule
  831.   -- input         array with input data
  832.   -- inputOffset   start index for input
  833.   -- output        array for decrypted data
  834.   -- outputOffset  start index for output
  835.   ---
  836.   local function decrypt(key, input, inputOffset, output, outputOffset)
  837.     -- default arguments
  838.     inputOffset = inputOffset or 1
  839.     output = output or {}
  840.     outputOffset = outputOffset or 1
  841.     local state = {}
  842.     local tmpState = {}
  843.     if (key[KEY_TYPE] ~= DECRYPTION_KEY) then
  844.       error("No decryption key: " .. tostring(key[KEY_TYPE]))
  845.       return
  846.     end
  847.     state = util.bytesToInts(input, inputOffset, 4)
  848.     addRoundKey(state, key, key[ROUNDS])
  849.     local round = key[ROUNDS] - 1
  850.     while (round > 2) do
  851.       -- do a double round to save temporary assignments
  852.       doInvRound(state, tmpState)
  853.       addRoundKey(tmpState, key, round)
  854.       round = round - 1
  855.       doInvRound(tmpState, state)
  856.       addRoundKey(state, key, round)
  857.       round = round - 1
  858.     end
  859.     doInvRound(state, tmpState)
  860.     addRoundKey(tmpState, key, round)
  861.     round = round - 1
  862.     doInvLastRound(tmpState, state)
  863.     addRoundKey(state, key, round)
  864.     util.sleepCheckIn()
  865.     return util.intsToBytes(state, output, outputOffset)
  866.   end
  867.  
  868.   -- calculate all tables when loading this file
  869.   calcSBox()
  870.   calcRoundTables()
  871.   calcInvRoundTables()
  872.  
  873.   return {
  874.     ROUNDS = ROUNDS,
  875.     KEY_TYPE = KEY_TYPE,
  876.     ENCRYPTION_KEY = ENCRYPTION_KEY,
  877.     DECRYPTION_KEY = DECRYPTION_KEY,
  878.     expandEncryptionKey = expandEncryptionKey,
  879.     expandDecryptionKey = expandDecryptionKey,
  880.     encrypt = encrypt,
  881.     decrypt = decrypt,
  882.   }
  883.   end)
  884.  
  885.   local buffer=_W(function(_ENV, ...)
  886.   local function new ()
  887.     return {}
  888.   end
  889.  
  890.   local function addString (stack, s)
  891.     table.insert(stack, s)
  892.   end
  893.  
  894.   local function toString (stack)
  895.     return table.concat(stack)
  896.   end
  897.  
  898.   return {
  899.     new = new,
  900.     addString = addString,
  901.     toString = toString,
  902.   }
  903.   end)
  904.  
  905.   ciphermode=_W(function(_ENV, ...)
  906.   local public = {}
  907.   --
  908.   -- Encrypt strings
  909.   -- key - byte array with key
  910.   -- string - string to encrypt
  911.   -- modefunction - function for cipher mode to use
  912.   --
  913.   local random, unpack = math.random, unpack or table.unpack
  914.   function public.encryptString(key, data, modeFunction, iv)
  915.     if iv then
  916.       local ivCopy = {}
  917.       for i = 1, 16 do ivCopy[i] = iv[i] end
  918.       iv = ivCopy
  919.     else
  920.       iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  921.     end
  922.     local keySched = aes.expandEncryptionKey(key)
  923.     local encryptedData = buffer.new()
  924.     for i = 1, #data/16 do
  925.       local offset = (i-1)*16 + 1
  926.       local byteData = {string.byte(data,offset,offset +15)}
  927.       iv = modeFunction(keySched, byteData, iv)
  928.       buffer.addString(encryptedData, string.char(unpack(byteData)))
  929.     end
  930.     return buffer.toString(encryptedData)
  931.   end
  932.   --
  933.   -- the following 4 functions can be used as
  934.   -- modefunction for encryptString
  935.   --
  936.   -- Electronic code book mode encrypt function
  937.   function public.encryptECB(keySched, byteData, iv)
  938.     aes.encrypt(keySched, byteData, 1, byteData, 1)
  939.   end
  940.  
  941.   -- Cipher block chaining mode encrypt function
  942.   function public.encryptCBC(keySched, byteData, iv)
  943.     util.xorIV(byteData, iv)
  944.     aes.encrypt(keySched, byteData, 1, byteData, 1)
  945.     return byteData
  946.   end
  947.  
  948.   -- Output feedback mode encrypt function
  949.   function public.encryptOFB(keySched, byteData, iv)
  950.     aes.encrypt(keySched, iv, 1, iv, 1)
  951.     util.xorIV(byteData, iv)
  952.     return iv
  953.   end
  954.  
  955.   -- Cipher feedback mode encrypt function
  956.   function public.encryptCFB(keySched, byteData, iv)
  957.     aes.encrypt(keySched, iv, 1, iv, 1)
  958.     util.xorIV(byteData, iv)
  959.     return byteData
  960.   end
  961.  
  962.   function public.encryptCTR(keySched, byteData, iv)
  963.     local nextIV = {}
  964.     for j = 1, 16 do nextIV[j] = iv[j] end
  965.     aes.encrypt(keySched, iv, 1, iv, 1)
  966.     util.xorIV(byteData, iv)
  967.     util.increment(nextIV)
  968.     return nextIV
  969.   end
  970.   --
  971.   -- Decrypt strings
  972.   -- key - byte array with key
  973.   -- string - string to decrypt
  974.   -- modefunction - function for cipher mode to use
  975.   --
  976.   function public.decryptString(key, data, modeFunction, iv)
  977.     if iv then
  978.       local ivCopy = {}
  979.       for i = 1, 16 do ivCopy[i] = iv[i] end
  980.       iv = ivCopy
  981.     else
  982.       iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  983.     end
  984.     local keySched
  985.     if modeFunction == public.decryptOFB or modeFunction == public.decryptCFB or modeFunction == public.decryptCTR then
  986.       keySched = aes.expandEncryptionKey(key)
  987.     else
  988.       keySched = aes.expandDecryptionKey(key)
  989.     end
  990.     local decryptedData = buffer.new()
  991.     for i = 1, #data/16 do
  992.       local offset = (i-1)*16 + 1
  993.       local byteData = {string.byte(data,offset,offset +15)}
  994.       iv = modeFunction(keySched, byteData, iv)
  995.       buffer.addString(decryptedData, string.char(unpack(byteData)))
  996.     end
  997.     return buffer.toString(decryptedData)
  998.   end
  999.   --
  1000.   -- the following 4 functions can be used as
  1001.   -- modefunction for decryptString
  1002.   --
  1003.   -- Electronic code book mode decrypt function
  1004.   function public.decryptECB(keySched, byteData, iv)
  1005.     aes.decrypt(keySched, byteData, 1, byteData, 1)
  1006.     return iv
  1007.   end
  1008.  
  1009.   -- Cipher block chaining mode decrypt function
  1010.   function public.decryptCBC(keySched, byteData, iv)
  1011.     local nextIV = {}
  1012.     for j = 1, 16 do nextIV[j] = byteData[j] end
  1013.     aes.decrypt(keySched, byteData, 1, byteData, 1)
  1014.     util.xorIV(byteData, iv)
  1015.     return nextIV
  1016.   end
  1017.  
  1018.   -- Output feedback mode decrypt function
  1019.   function public.decryptOFB(keySched, byteData, iv)
  1020.     aes.encrypt(keySched, iv, 1, iv, 1)
  1021.     util.xorIV(byteData, iv)
  1022.     return iv
  1023.   end
  1024.  
  1025.   -- Cipher feedback mode decrypt function
  1026.   function public.decryptCFB(keySched, byteData, iv)
  1027.     local nextIV = {}
  1028.     for j = 1, 16 do nextIV[j] = byteData[j] end
  1029.     aes.encrypt(keySched, iv, 1, iv, 1)
  1030.     util.xorIV(byteData, iv)
  1031.     return nextIV
  1032.   end
  1033.  
  1034.   public.decryptCTR = public.encryptCTR
  1035.   return public
  1036.   end)
  1037.  
  1038.   -- Simple API for encrypting strings.
  1039.   --
  1040.   AES128 = 16
  1041.   AES192 = 24
  1042.   AES256 = 32
  1043.   ECBMODE = 1
  1044.   CBCMODE = 2
  1045.   OFBMODE = 3
  1046.   CFBMODE = 4
  1047.   CTRMODE = 4
  1048.  
  1049.   local function pwToKey(password, keyLength, iv)
  1050.     local padLength = keyLength
  1051.     if (keyLength == AES192) then
  1052.       padLength = 32
  1053.     end
  1054.     if (padLength > #password) then
  1055.       local postfix = ""
  1056.       for i = 1,padLength - #password do
  1057.         postfix = postfix .. string.char(0)
  1058.       end
  1059.       password = password .. postfix
  1060.     else
  1061.       password = string.sub(password, 1, padLength)
  1062.     end
  1063.     local pwBytes = {string.byte(password,1,#password)}
  1064.     password = ciphermode.encryptString(pwBytes, password, ciphermode.encryptCBC, iv)
  1065.     password = string.sub(password, 1, keyLength)
  1066.     return {string.byte(password,1,#password)}
  1067.   end
  1068.   --
  1069.   -- Encrypts string data with password password.
  1070.   -- password  - the encryption key is generated from this string
  1071.   -- data      - string to encrypt (must not be too large)
  1072.   -- keyLength - length of aes key: 128(default), 192 or 256 Bit
  1073.   -- mode      - mode of encryption: ecb, cbc(default), ofb, cfb
  1074.   --
  1075.   -- mode and keyLength must be the same for encryption and decryption.
  1076.   --
  1077.   function encrypt(password, data, keyLength, mode, iv)
  1078.     assert(password ~= nil, "Empty password.")
  1079.     assert(data ~= nil, "Empty data.")
  1080.     local mode = mode or CBCMODE
  1081.     local keyLength = keyLength or AES128
  1082.     local key = pwToKey(password, keyLength, iv)
  1083.     local paddedData = util.padByteString(data)
  1084.     if mode == ECBMODE then
  1085.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptECB, iv)
  1086.     elseif mode == CBCMODE then
  1087.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCBC, iv)
  1088.     elseif mode == OFBMODE then
  1089.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptOFB, iv)
  1090.     elseif mode == CFBMODE then
  1091.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCFB, iv)
  1092.     elseif mode == CTRMODE then
  1093.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCTR, iv)
  1094.     else
  1095.       error("Unknown mode", 2)
  1096.     end
  1097.   end
  1098.   --
  1099.   -- Decrypts string data with password password.
  1100.   -- password  - the decryption key is generated from this string
  1101.   -- data      - string to encrypt
  1102.   -- keyLength - length of aes key: 128(default), 192 or 256 Bit
  1103.   -- mode      - mode of decryption: ecb, cbc(default), ofb, cfb
  1104.   --
  1105.   -- mode and keyLength must be the same for encryption and decryption.
  1106.   --
  1107.   function decrypt(password, data, keyLength, mode, iv)
  1108.     local mode = mode or CBCMODE
  1109.     local keyLength = keyLength or AES128
  1110.     local key = pwToKey(password, keyLength, iv)
  1111.     local plain
  1112.     if mode == ECBMODE then
  1113.       plain = ciphermode.decryptString(key, data, ciphermode.decryptECB, iv)
  1114.     elseif mode == CBCMODE then
  1115.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCBC, iv)
  1116.     elseif mode == OFBMODE then
  1117.       plain = ciphermode.decryptString(key, data, ciphermode.decryptOFB, iv)
  1118.     elseif mode == CFBMODE then
  1119.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCFB, iv)
  1120.     elseif mode == CTRMODE then
  1121.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCTR, iv)
  1122.     else
  1123.       error("Unknown mode", 2)
  1124.     end
  1125.     result = util.unpadByteString(plain)
  1126.     if (result == nil) then
  1127.       return nil
  1128.     end
  1129.     return result
  1130.   end
  1131. end
  1132.  
  1133. -- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
  1134. -- By Anavrins
  1135. -- For help and details, you can PM me on the CC forums
  1136. -- http://www.computercraft.info/forums2/index.php?/user/12870-anavrins
  1137. -- Pastebin: http://pastebin.com/6UV4qfNF
  1138. -- You may use this code in your projects without asking me, as long as credit is given and this header is kept intact
  1139. local digest, hmac, pbkdf2
  1140. do
  1141.   local mod32 = 2^32
  1142.   local sha_hashlen = 32
  1143.   local sha_blocksize = 64
  1144.   local band    = bit32 and bit32.band or bit.band
  1145.   local bnot    = bit32 and bit32.bnot or bit.bnot
  1146.   local bxor    = bit32 and bit32.bxor or bit.bxor
  1147.   local blshift = bit32 and bit32.lshift or bit.blshift
  1148.   local upack   = unpack
  1149.  
  1150.   local function rrotate(n, b)
  1151.     local s = n/(2^b)
  1152.     local f = s%1
  1153.     return (s-f) + f*mod32
  1154.   end
  1155.  
  1156.   local function brshift(int, by) -- Thanks bit32 for bad rshift
  1157.     local s = int / (2^by)
  1158.     return s - s%1
  1159.   end
  1160.  
  1161.   local H = {
  1162.     0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
  1163.     0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
  1164.   }
  1165.  
  1166.   local K = {
  1167.     0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  1168.     0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  1169.     0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  1170.     0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  1171.     0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  1172.     0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  1173.     0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  1174.     0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
  1175.   }
  1176.  
  1177.   local function counter(incr)
  1178.     local t1, t2 = 0, 0
  1179.     if 0xFFFFFFFF - t1 < incr then
  1180.       t2 = t2 + 1
  1181.       t1 = incr - (0xFFFFFFFF - t1) - 1    
  1182.     else t1 = t1 + incr
  1183.     end
  1184.     return t2, t1
  1185.   end
  1186.  
  1187.   local function BE_toInt(bs, i)
  1188.     return blshift((bs[i] or 0), 24) + blshift((bs[i+1] or 0), 16) + blshift((bs[i+2] or 0), 8) + (bs[i+3] or 0)
  1189.   end
  1190.  
  1191.   local function preprocess(data)
  1192.     local len = #data
  1193.     local proc = {}
  1194.     data[#data+1] = 0x80
  1195.     while #data%64~=56 do data[#data+1] = 0 end
  1196.     local blocks = math.ceil(#data/64)
  1197.     for i = 1, blocks do
  1198.       proc[i] = {}
  1199.       for j = 1, 16 do
  1200.         proc[i][j] = BE_toInt(data, 1+((i-1)*64)+((j-1)*4))
  1201.       end
  1202.     end
  1203.     proc[blocks][15], proc[blocks][16] = counter(len*8)
  1204.     return proc
  1205.   end
  1206.  
  1207.   local function digestblock(w, C)
  1208.     for j = 17, 64 do
  1209.       local v = w[j-15]
  1210.       local s0 = bxor(bxor(rrotate(w[j-15], 7), rrotate(w[j-15], 18)), brshift(w[j-15], 3))
  1211.       local s1 = bxor(bxor(rrotate(w[j-2], 17), rrotate(w[j-2], 19)), brshift(w[j-2], 10))
  1212.       w[j] = (w[j-16] + s0 + w[j-7] + s1)%mod32
  1213.     end
  1214.     local a, b, c, d, e, f, g, h = upack(C)
  1215.     for j = 1, 64 do
  1216.       local S1 = bxor(bxor(rrotate(e, 6), rrotate(e, 11)), rrotate(e, 25))
  1217.       local ch = bxor(band(e, f), band(bnot(e), g))
  1218.       local temp1 = (h + S1 + ch + K[j] + w[j])%mod32
  1219.       local S0 = bxor(bxor(rrotate(a, 2), rrotate(a, 13)), rrotate(a, 22))
  1220.       local maj = bxor(bxor(band(a, b), band(a, c)), band(b, c))
  1221.       local temp2 = (S0 + maj)%mod32
  1222.       h, g, f, e, d, c, b, a = g, f, e, (d+temp1)%mod32, c, b, a, (temp1+temp2)%mod32
  1223.     end
  1224.     C[1] = (C[1] + a)%mod32
  1225.     C[2] = (C[2] + b)%mod32
  1226.     C[3] = (C[3] + c)%mod32
  1227.     C[4] = (C[4] + d)%mod32
  1228.     C[5] = (C[5] + e)%mod32
  1229.     C[6] = (C[6] + f)%mod32
  1230.     C[7] = (C[7] + g)%mod32
  1231.     C[8] = (C[8] + h)%mod32
  1232.     return C
  1233.   end
  1234.  
  1235.   local mt = {
  1236.     __tostring = function(a) return string.char(unpack(a)) end,
  1237.     __index = {
  1238.       toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end,
  1239.       isEqual = function(self, t)
  1240.         if type(t) ~= "table" then return false end
  1241.         if #self ~= #t then return false end
  1242.         local ret = 0
  1243.         for i = 1, #self do
  1244.           ret = bit32.bor(ret, bxor(self[i], t[i]))
  1245.         end
  1246.         return ret == 0
  1247.       end
  1248.     }
  1249.   }
  1250.  
  1251.   local function toBytes(t, n)
  1252.     local b = {}
  1253.     for i = 1, n do
  1254.       b[(i-1)*4+1] = band(brshift(band(t[i], 0xFF000000), 24), 0xFF)
  1255.       b[(i-1)*4+2] = band(brshift(band(t[i], 0xFF0000), 16), 0xFF)
  1256.       b[(i-1)*4+3] = band(brshift(band(t[i], 0xFF00), 8), 0xFF)
  1257.       b[(i-1)*4+4] = band(t[i], 0xFF)
  1258.     end
  1259.     return setmetatable(b, mt)
  1260.   end
  1261.  
  1262.   digest = function(data)
  1263.     data = data or ""
  1264.     data = type(data) == "string" and {data:byte(1,-1)} or data
  1265.     data = preprocess(data)
  1266.     local C = {upack(H)}
  1267.     for i = 1, #data do C = digestblock(data[i], C) end
  1268.     return toBytes(C, 8)
  1269.   end
  1270.  
  1271.   hmac = function(data, key)
  1272.     local data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)}
  1273.     local key = type(key) == "table" and {upack(key)} or {tostring(key):byte(1,-1)}
  1274.     local blocksize = sha_blocksize
  1275.     key = #key > blocksize and digest(key) or key
  1276.     local ipad = {}
  1277.     local opad = {}
  1278.     local padded_key = {}
  1279.     for i = 1, blocksize do
  1280.       ipad[i] = bxor(0x36, key[i] or 0)
  1281.       opad[i] = bxor(0x5C, key[i] or 0)
  1282.     end
  1283.     for i = 1, #data do
  1284.       ipad[blocksize+i] = data[i]
  1285.     end
  1286.     ipad = digest(ipad)
  1287.     for i = 1, blocksize do
  1288.       padded_key[i] = opad[i]
  1289.       padded_key[blocksize+i] = ipad[i]
  1290.     end
  1291.     return digest(padded_key)
  1292.   end
  1293.  
  1294.   pbkdf2 = function(pass, salt, iter, dklen)
  1295.     local out = {}
  1296.     local hashlen = sha_hashlen
  1297.     local block = 1
  1298.     dklen = dklen or 32
  1299.     while dklen > 0 do
  1300.       local ikey = {}
  1301.       local isalt = type(salt) == "table" and {upack(salt)} or {tostring(salt):byte(1,-1)}
  1302.       local clen = dklen > hashlen and hashlen or dklen
  1303.       local iCount = #isalt
  1304.       isalt[iCount+1] = band(brshift(band(block, 0xFF000000), 24), 0xFF)
  1305.       isalt[iCount+2] = band(brshift(band(block, 0xFF0000), 16), 0xFF)
  1306.       isalt[iCount+3] = band(brshift(band(block, 0xFF00), 8), 0xFF)
  1307.       isalt[iCount+4] = band(block, 0xFF)
  1308.       for j = 1, iter do
  1309.         isalt = hmac(isalt, pass)
  1310.         for k = 1, clen do ikey[k] = bxor(isalt[k], ikey[k] or 0) end
  1311.         if j % 200 == 0 then os.queueEvent("PBKDF2", j) coroutine.yield("PBKDF2") end
  1312.       end
  1313.       dklen = dklen - clen
  1314.       block = block+1
  1315.       for k = 1, clen do out[#out+1] = ikey[k] end
  1316.     end
  1317.     return setmetatable(out, mt)
  1318.   end
  1319. end
  1320.  
  1321. local function filterDeviceList()
  1322.   for i = #filteredDevices, 1, -1 do
  1323.     filteredDevices[i] = nil
  1324.   end
  1325.   local deviceCount = 0
  1326.   for i = 1, #allDevices do
  1327.     if (type(uFilter) == "boolean" and uFilter and allDevices[i].outputType:sub(1, 1) == "U") or (not uFilter) or (type(uFilter) == "string" and allDevices[i].outputType:sub(1, 1) ~= "U") then
  1328.       deviceCount = deviceCount + 1
  1329.       filteredDevices[deviceCount] = { }
  1330.       for k, v in pairs(allDevices[i]) do
  1331.         filteredDevices[deviceCount][k] = v
  1332.       end
  1333.       filteredDevices[deviceCount].adList = i
  1334.     end
  1335.   end
  1336.   numPages = math.max(1, math.ceil(#filteredDevices / 24))
  1337.   pageNum = math.min(pageNum, numPages)
  1338. end
  1339.  
  1340. do
  1341.   local function sortDeviceList(newSettings)
  1342.     local deviceCount = #allDevices
  1343.     if deviceCount == 0 then                --# the list is empty
  1344.       allDevices[1] = { }
  1345.       for k, v in pairs(newSettings) do     --# add this device
  1346.         allDevices[1][k] = v
  1347.       end
  1348.     else
  1349.       local nsName, filterCount = newSettings.name, #filteredDevices
  1350.       for i = 1, deviceCount do
  1351.         if cc10host == allDevices[i].cc then  --# we're already on the list
  1352.           for k, v in pairs(newSettings) do   --# update entry with current state of host
  1353.             allDevices[i][k] = v
  1354.           end
  1355.           for j = 1, filterCount do
  1356.             if filteredDevices[j].adList == i then
  1357.               for k, v in pairs(newSettings) do
  1358.                 filteredDevices[j][k] = v
  1359.               end
  1360.               break
  1361.             end
  1362.           end
  1363.           return
  1364.         end
  1365.       end
  1366.       for i = 1, deviceCount do
  1367.         if nsName < allDevices[i].name then --# alphabetize
  1368.           table.insert(allDevices, i, newSettings) --# insert
  1369.           break
  1370.         end
  1371.         if i == deviceCount then            --# we've reached the end of the list
  1372.           deviceCount = deviceCount + 1
  1373.           allDevices[deviceCount] = { }     --# tack it on
  1374.           for k, v in pairs(newSettings) do
  1375.             allDevices[deviceCount][k] = v
  1376.           end
  1377.           break
  1378.         end
  1379.       end
  1380.     end
  1381.     filterDeviceList()
  1382.   end
  1383.  
  1384.   netReceive = function()
  1385.     local id, success, encKey, message, encryptedMessage, decryptedMessage, decodedMessage
  1386.     while true do
  1387.       if not rednet.isOpen(netSide) then rednet.open(netSide) end
  1388.       id, encryptedMessage = rednet.receive("cc10")
  1389.       if type(encryptedMessage) == "string" then
  1390.         success, decodedMessage = pcall(decode, encryptedMessage)
  1391.         if success and type(decodedMessage) == "string" then
  1392.           encKey = thisCC .. "cc!10" .. tostring(id)
  1393.           success, decryptedMessage = pcall(decrypt, encKey, decodedMessage)
  1394.           if success and type(decryptedMessage) == "string" then
  1395.             success, message = pcall(textutils.unserialize, decryptedMessage)
  1396.             if success and type(message) == "table" and message.program and message.program == "cc10host" then
  1397.               cc10host = id
  1398.               sortDeviceList(message)
  1399.               drawCLI()
  1400.             end
  1401.           end
  1402.         end
  1403.       end
  1404.     end
  1405.   end
  1406. end
  1407.  
  1408. local function netSend(targetHost, cmd1, act1)
  1409.   local dataPack = textutils.serialize({ program = "cc10", cmd = cmd1, action = act1 })
  1410.   if not rednet.isOpen(netSide) then rednet.open(netSide) end
  1411.   if targetHost == "ALL" then
  1412.     local encKey = thisCC .. "cc!10_Broadcast" .. thisCC
  1413.     local encryptedData = encode(encrypt(encKey, dataPack))
  1414.     rednet.broadcast(encryptedData, "cc10")
  1415.   else
  1416.     local encKey = tostring(targetHost) .. "cc!10" .. thisCC
  1417.     local encryptedData = encode(encrypt(encKey, dataPack))
  1418.     rednet.send(targetHost, encryptedData, "cc10")
  1419.   end
  1420. end
  1421.  
  1422. local function assignColor(assignment)
  1423.   return colorBurst[assignment].color or silver
  1424. end
  1425.  
  1426. local function drawElement(x, y, w, h, txtColor, bgColor, text)
  1427.   if type(w) == "boolean" then
  1428.     term.setCursorPos(x, y)
  1429.     term.setBackgroundColor(w and green or gray)
  1430.     term.write("  ")
  1431.     term.setBackgroundColor(w and gray or red)
  1432.     term.write("  ")
  1433.   else
  1434.     text = text and tostring(text) or ""
  1435.     local txtLen = #text
  1436.     w = math.max(w, txtLen)
  1437.     local spacer = (w - txtLen) / 2
  1438.     local txtLine = string.rep(" ", math.floor(spacer)) .. text .. string.rep(" ", math.ceil(spacer))
  1439.     if txtColor then term.setTextColor(txtColor) end
  1440.     if bgColor then term.setBackgroundColor(bgColor) end
  1441.     if h == 1 then
  1442.       term.setCursorPos(x, y)
  1443.       term.write(txtLine)
  1444.     else
  1445.       local line, textRow = string.rep(" ", w), y + math.floor(h / 2)
  1446.       for i = y, y + h - 1 do
  1447.         term.setCursorPos(x, i)        
  1448.         term.write(i == textRow and txtLine or line) --# Draw one line of the 'element' (box/rectangle/line-seg)
  1449.       end
  1450.     end
  1451.   end
  1452. end
  1453.  
  1454. local function drawHeader()
  1455.   local hColor = (runState == "Edit" or runState == "color") and assignColor(allDevices[thisDevice].color) or blue
  1456.   local hText = runState == "Help" and "cc10  " .. cc10Rver or ((runState == "Edit" or runState == "color") and allDevices[thisDevice].name .. " (cc# " .. tostring(allDevices[thisDevice].cc) .. ")" or "cc10")
  1457.   drawElement(1, 1, termX, 1, white, hColor, hText) --# title bar
  1458.   if runState == "List" or runState == "goPage" then
  1459.     drawElement(1, 1, 1, 1, nil, nil, "[ ]")
  1460.     local fColor = uFilter and green or gray
  1461.     drawElement(2, 1, 1, 1, type(uFilter) == "boolean" and fColor or orange, nil, "U")
  1462.     drawElement(termX - 2, 1, 1, 1, white, nil, "[ ]")
  1463.     drawElement(termX - 1, 1, 1, 1, red, nil, "X")
  1464.     drawElement(1, 2, 1, 1, green, gray, string.rep(" ", math.floor(termX / 4) - 2) .. "All ON" .. string.rep(" ", math.ceil(termX / 4) - 2))
  1465.     drawElement(math.ceil(termX / 2), 2, 1, 1, red, nil, string.rep(" ", math.floor(termX / 4) - 2) .. "All OFF" .. string.rep(" ", math.ceil(termX / 4) - 2))
  1466.   elseif runState == "Edit" or runState == "color" or runState == "Help" then
  1467.     drawElement(1, 2, termX, 1, red, gray, "Close")
  1468.   end
  1469. end
  1470.  
  1471. local function drawColorList(rating)
  1472.   local color
  1473.   drawElement(8, 4, 9, 8, nil, gray)                      --# menu body
  1474.   for k, v in pairs(colorBurst) do
  1475.     if rating == k then
  1476.       color = v.color
  1477.       drawElement(16, v.order + 3, 1, 1, nil, color, " ") --# selected color pip
  1478.     else
  1479.       color = silver
  1480.     end
  1481.     drawElement(7, v.order + 3, 1, 1, nil, v.color, " ")  --# rating color pips
  1482.     if rating == "I" and k == "I" then color = white end
  1483.     drawElement(9, v.order + 3, 1, 1, color, gray, v.text)
  1484.   end
  1485. end
  1486.  
  1487. local function viewDeviceEntry()
  1488.   runState, outputType, onState = "Edit", allDevices[thisDevice].outputType, allDevices[thisDevice].onState
  1489.   drawHeader()
  1490.   if thisDevice <= #allDevices then
  1491.     drawElement(2, 4, 1, 1, assignColor(allDevices[thisDevice].color), black, allDevices[thisDevice].name) --# Name
  1492.     drawElement(12, 4, 1, 1, gray, nil, "Power:") --# Power state
  1493.     drawElement(22, 4, allDevices[thisDevice].state ~= 0)
  1494.     drawElement(2, 6, 1, 1, gray, black, "cc#")   --# cc#
  1495.     drawElement(6, 6, 1, 1, white, nil, tostring(allDevices[thisDevice].cc))
  1496.     if outputType:sub(1, 1) ~= "P" then           --# Restore state upon restart ON/OFF
  1497.       drawElement(12, 6, 1, 1, gray, nil, "Restore:")
  1498.       drawElement(22, 6, allDevices[thisDevice].restore)
  1499.     else
  1500.       drawElement(12, 6, 14, 1, nil, black)
  1501.     end
  1502.     drawElement(2, 8, 1, 1, silver, black, allDevices[thisDevice].note) --# Short description
  1503.     drawElement(2, 10, 1, 1, gray, nil, "Output type:") --# Output Type (Digital, Analog, Universal Digital, Universal Analog, Pulsed (short), Pulsed (long), Pulsed (3))
  1504.     drawElement(15, 10, 1, 1, silver, nil, (cc10Types[outputType][1] or "ERROR  ") .. "   ")
  1505.     if outputType == "A" or outputType == "UA" then     --# Output Level (0-15)
  1506.       drawElement(2, 12, 1, 1, gray, nil, "Output Level:")
  1507.       local sState = onState < 10 and " " .. tostring(onState) or tostring(onState)
  1508.       drawElement(17, 12, 1, 1, white, nil, sState)
  1509.       drawElement(2, 13, 1, 1, silver, nil, "|---------------|")
  1510.       drawElement(onState + 2, 13, 1, 1, white, (onState > 0 and onState < 16) and green or red, "+")
  1511.     else
  1512.       drawElement(2, 12, 17, 2, nil, black)
  1513.     end
  1514.     if allDevices[thisDevice].loc.x ~= "No GPS Fix" then --# Device location (Export to pgps button)
  1515.       drawElement(14, 17, 9, 1, black, gray, "Export")
  1516.       drawElement(14, 18, 9, 1, nil, nil, "to pgps")
  1517.     end
  1518.     drawElement(2, 15, 1, 1, silver, black, "Dim:")      --# Device location (dim/x/y/z)
  1519.     drawElement(2, 16, 1, 1, nil, nil, "x:")
  1520.     drawElement(2, 17, 1, 1, nil, nil, "y:")
  1521.     drawElement(2, 18, 1, 1, nil, nil, "z:")
  1522.     drawElement(7, 15, 1, 1, brown, nil, allDevices[thisDevice].loc.dim)
  1523.     drawElement(5, 16, 1, 1, sky, nil, tostring(allDevices[thisDevice].loc.x))
  1524.     drawElement(5, 17, 1, 1, nil, nil, tostring(allDevices[thisDevice].loc.y))
  1525.     drawElement(5, 18, 1, 1, nil, nil, tostring(allDevices[thisDevice].loc.z))
  1526.   end
  1527. end
  1528.  
  1529. local function drawHelpUI()
  1530.   drawElement(1, 3, termX, termY - 2, nil, white)
  1531.   drawHeader()
  1532.   if tempState == "List" then
  1533.     drawElement(2, 4, 1, 1, black, white, "Left click an entry to")
  1534.     drawElement(2, 5, 1, 1, nil, nil, "toggle its state")
  1535.     drawElement(2, 7, 1, 1, nil, nil, "Right click an entry to")
  1536.     drawElement(2, 8, 1, 1, nil, nil, "view that entry's details")
  1537.     drawElement(2, 10, 1, 1, nil, nil, "Middle click an entry to")
  1538.     drawElement(2, 11, 1, 1, nil, nil, "lock it")
  1539.     drawElement(2, 13, 1, 1, nil, nil, "All ON/All OFF toggles")
  1540.     drawElement(2, 14, 1, 1, nil, nil, "all Universals in range")
  1541.     drawElement(2, 16, 1, 1, nil, nil, "[U] = Universal Filter")
  1542.     drawElement(2, 17, 1, 1, nil, nil, "Switch filter between")
  1543.     drawElement(2, 18, 1, 1, nil, nil, "universal, non-U, & all")
  1544.   elseif tempState == "Edit" then
  1545.     drawElement(2, 4, 1, 1, black, white, "Restore: restore last")
  1546.     drawElement(2, 5, 1, 1, nil, nil, "state after server or")
  1547.     drawElement(2, 6, 1, 1, nil, nil, "software restart")
  1548.     drawElement(2, 8, 1, 1, nil, nil, "Left click name, note, ")
  1549.     drawElement(2, 9, 1, 1, nil, nil, "or dim to edit")
  1550.     drawElement(2, 11, 1, 1, nil, nil, "Right click name to")
  1551.     drawElement(2, 12, 1, 1, nil, nil, "change color")
  1552.     drawElement(2, 14, 1, 1, nil, nil, "Universal Digital and")
  1553.     drawElement(2, 15, 1, 1, nil, nil, "Universal Analog both")
  1554.     drawElement(2, 16, 1, 1, nil, nil, "respond to All ON/OFF")
  1555.   end
  1556. end
  1557.  
  1558. local function drawNaviUI()
  1559.   local pNum = tostring(pageNum)
  1560.   if pageNum < 100 then pNum = "0" .. pNum end --# Add a "0" before double digit page numbers
  1561.   if pageNum < 10 then pNum = "0" .. pNum end  --# Add another "0" before single digit page numbers
  1562.   drawElement(math.floor(termX / 2) - 10, termY, 7, 1, gray, black, pageNum > 1 and "<< BACK" or "       ")
  1563.   drawElement(math.floor(termX / 2) + 4, termY, 7, 1, nil, nil, pageNum < numPages and "NEXT >>" or "       ")
  1564.   drawElement(math.floor((termX - #pNum) / 2) + 1, termY, 3, 1, silver, nil, pNum) --# Page Number
  1565. end
  1566.  
  1567. local function drawMainUI() --# Device 'Address Book'
  1568.   local xPos, yPos, fdName, fdState, spacer = 1, 4
  1569.   local magicNumber = ((pageNum - 1) * 23) + pageNum
  1570.   for i = magicNumber, math.min(#filteredDevices, pageNum * 24) do
  1571.     term.setCursorPos(xPos, yPos)
  1572.     fdState = filteredDevices[i].state
  1573.     if not filteredDevices[i].lockState then
  1574.       term.setBackgroundColor(fdState == 0 and black or assignColor(filteredDevices[i].color))
  1575.       term.setTextColor(fdState == 0 and assignColor(filteredDevices[i].color) or white)
  1576.     else
  1577.       term.setBackgroundColor(fdState == 0 and black or gray)
  1578.       term.setTextColor(fdState == 0 and gray or silver)
  1579.     end
  1580.     fdName = filteredDevices[i].name
  1581.     spacer = (8 - #fdName) / 2
  1582.     term.write(string.rep(" ", math.floor(spacer)) .. fdName .. string.rep(" ", math.ceil(spacer)))
  1583.     yPos = yPos + 2
  1584.     if yPos > 19 then yPos = 4 xPos = xPos + 9 end
  1585.   end
  1586. end
  1587.  
  1588. do
  1589.   local runStates = {
  1590.     List = function() drawMainUI() drawNaviUI() end;
  1591.     Edit = function() viewDeviceEntry() end;
  1592.   }
  1593.  
  1594.   drawCLI = function() --# Client Interface 'decider'
  1595.     if not inputting then
  1596.       drawHeader()
  1597.       if runStates[runState] then runStates[runState]() end
  1598.     end
  1599.   end
  1600. end
  1601.  
  1602. local function readInput(cX, cY, cO, bG, limit, mask) --# cursor X, Y, text color, bg color, character limit, character mask
  1603.   local word, pos = "", 0
  1604.   local curX, curY = cX, cY
  1605.   inputting, timerDelay = true, true
  1606.   os.cancelTimer(pollTimer)
  1607.   bG = bG or black
  1608.   limit = (limit and type(limit) == "number" and limit > 0) and limit or 21
  1609.   term.setCursorPos(curX, curY)
  1610.   term.setTextColor(cO)
  1611.   term.setBackgroundColor(bG)
  1612.   term.setCursorBlink(true)
  1613.   while true do
  1614.     local event, data, mX, mY = os.pullEvent()
  1615.     if event == "key" then
  1616.       if data == keys.backspace then
  1617.         if curX > cX then
  1618.           curX = math.max(cX, curX - 1)
  1619.           pos = math.max(0, pos - 1)
  1620.           word = word:sub(1, #word - 1)
  1621.         end
  1622.         drawElement(curX, curY, 1, 1, cO, bG, " ")
  1623.         term.setCursorPos(curX, curY)
  1624.       elseif data == keys.enter or data == keys.numPadEnter then
  1625.         break
  1626.       end
  1627.     elseif event == "char" and pos < limit then
  1628.       drawElement(curX, curY, 1, 1, cO, bG, mask or data)
  1629.       word = word .. data
  1630.       curX = curX + 1
  1631.       pos = pos + 1
  1632.     elseif event == "paste" and pos < limit then
  1633.       if pos + #data > limit then
  1634.         data = data:sub(1, limit - pos)
  1635.       end
  1636.       drawElement(curX, curY, 1, 1, cO, bG, mask and string.rep(mask, #data) or data)
  1637.       word = word .. data
  1638.       curX = curX + #data
  1639.       pos = pos + #data
  1640.     elseif event == "mouse_click" then
  1641.       if mY ~= curY or mX < cX or mX >= cX + limit then
  1642.         break
  1643.       end
  1644.     end
  1645.   end
  1646.   term.setCursorBlink(false)
  1647.   inputting = false
  1648.   return word
  1649. end
  1650.  
  1651. do
  1652.   local function toggleFilter()
  1653.     if type(uFilter) == "boolean" then
  1654.       uFilter = uFilter and "U" or true
  1655.     else
  1656.       uFilter = false
  1657.     end
  1658.     filterDeviceList()
  1659.     drawElement(1, 3, termX, termY - 2, nil, black)
  1660.     drawCLI()
  1661.   end
  1662.  
  1663.   local function inputMain()
  1664.     local event, mButton, mcX, mcY, xPos, yPos, magicNumber
  1665.     while true do
  1666.       event, mButton, mcX, mcY = os.pullEvent()
  1667.       if event == "mouse_click" then
  1668.         if runState == "Help" then
  1669.           if mcY == 2 and mButton == 1 then
  1670.             drawElement(1, 2, termX, termY - 1, nil, black)
  1671.             runState = tempState
  1672.             drawCLI()
  1673.           end
  1674.         elseif runState == "Edit" then
  1675.           if mcY == 2 and mButton == 1 then --# Exit Edit Screen
  1676.             drawElement(2, 2, termX, termY - 1, nil, black)
  1677.             runState = "List"
  1678.             drawCLI()
  1679.           elseif mcY == 4 then
  1680.             if mcX > 1 and mcX < 10 then
  1681.               if mButton == 1 then          --# Edit Device Name
  1682.                 runState = "EditName"
  1683.                 return
  1684.               elseif mButton == 2 then      --# Change color assignment
  1685.                 drawColorList(allDevices[thisDevice].color)
  1686.                 runState = "color"
  1687.                 return
  1688.               end
  1689.             elseif mcX > 21 and mcX < 26  and mButton == 1 then --# Change ON/OFF state
  1690.               if allDevices[thisDevice].state == 0 then
  1691.                 netSend(allDevices[thisDevice].cc, "set", allDevices[thisDevice].onState)
  1692.               elseif allDevices[thisDevice].state > 0 and allDevices[thisDevice].state < 16 then
  1693.                 netSend(allDevices[thisDevice].cc, "set", 0)
  1694.               end
  1695.             end
  1696.           elseif mcY == 6 and mButton == 1 then
  1697.             if mcX > 21 and mcX < 26 and allDevices[thisDevice].outputType:sub(1, 1) ~= "P" then --# Restore state on restart?
  1698.               netSend(allDevices[thisDevice].cc, "restore", not allDevices[thisDevice].restore)
  1699.             end
  1700.           elseif mcY == 8 and mButton == 1 then  --# Edit Device Note
  1701.             if mcX > 1 then
  1702.               runState = "EditNote"
  1703.               return
  1704.             end
  1705.           elseif mcY == 10 and mButton == 1 then --# Edit Output Type (Analog/Digital/Universal/Pulsed)
  1706.             if mcX > 14 and mcX < 24 then
  1707.               netSend(allDevices[thisDevice].cc, "changeOutputType", cc10Types[allDevices[thisDevice].outputType][2])
  1708.             end
  1709.           elseif mcY == 13 and mButton == 1 then --# Edit Redstone Output Level
  1710.             if mcX > 2 and mcX < 18 then
  1711.               if allDevices[thisDevice].outputType == "A" or allDevices[thisDevice].outputType == "UA" then
  1712.                 netSend(allDevices[thisDevice].cc, "lvl", mcX - 2)
  1713.               end
  1714.             end
  1715.           elseif mcY == 15 and mButton == 1 then --# Device Dimension
  1716.             if mcX > 6 and mcX < 26 then
  1717.               runState = "EditDim"
  1718.               return
  1719.             end
  1720.           elseif (mcY == 17 or mcY == 18) and mButton == 1 then
  1721.             if mcX > 14 and mcX < 23 and allDevices[thisDevice].loc.x ~= "No GPS Fix" then --# Export to Lyqyd's pocketgps
  1722.               drawElement(14, 17, 9, 1, white, gray, "Export")
  1723.               drawElement(14, 18, 9, 1, nil, nil, "to pgps")
  1724.               sleep(0.1)
  1725.               drawElement(14, 17, 9, 1, black, nil, "Export")
  1726.               drawElement(14, 18, 9, 1, nil, nil, "to pgps")
  1727.               local pgpsPlaces = fs.open("/.places", fs.exists("/.places") and "a" or "w")
  1728.               pgpsPlaces.writeLine(allDevices[thisDevice].loc.x .. ", " .. allDevices[thisDevice].loc.y .. ", " .. allDevices[thisDevice].loc.z .. ", " .. allDevices[thisDevice].name)
  1729.               pgpsPlaces.close()
  1730.             end
  1731.           end
  1732.         elseif runState == "List" then
  1733.           if mcY == 1 and mButton == 1 then
  1734.             if mcX > 0 and mcX < 4 then --# Universal filter
  1735.               toggleFilter()
  1736.             elseif mcX > termX - 3 and mcX <= termX then --# Exit cc10 Remote
  1737.               kernelState = false
  1738.               if rednet.isOpen(netSide) then rednet.close(netSide) end
  1739.               term.setBackgroundColor(black)
  1740.               term.setTextColor(white)
  1741.               term.clear()
  1742.               term.setCursorPos(1, 1)
  1743.               break
  1744.             end
  1745.           elseif mcY == 2 and mButton == 1 then --# ALL ON/OFF
  1746.             netSend("ALL", "set", mcX < termX / 2 and "ON" or "OFF")
  1747.           elseif mcY > 3 and mcY < 19 then --# Switch a listed device on or off, or view it's info
  1748.             magicNumber, xPos, yPos = ((pageNum - 1) * 23) + pageNum, 1, 4
  1749.             for i = magicNumber, math.min(#filteredDevices, pageNum * 24) do
  1750.               if mcX >= xPos and mcX < xPos + 8 and mcY == yPos then
  1751.                 if not filteredDevices[i].lockState then
  1752.                   if mButton == 1 then
  1753.                     netSend(filteredDevices[i].cc, "set", filteredDevices[i].state == 0 and filteredDevices[i].onState or 0)
  1754.                     drawMainUI()
  1755.                   elseif mButton == 2 then
  1756.                     term.clear()
  1757.                     thisDevice = filteredDevices[i].adList
  1758.                     viewDeviceEntry()
  1759.                   elseif mButton == 3 then
  1760.                     thisDevice = filteredDevices[i].adList
  1761.                     netSend(filteredDevices[i].cc, "lock")
  1762.                   end
  1763.                 else
  1764.                   thisDevice = filteredDevices[i].adList
  1765.                   runState = "unlock"
  1766.                   return
  1767.                 end
  1768.               end
  1769.               yPos = yPos + 2
  1770.               if yPos > 19 then yPos = 4 xPos = xPos + 9 end
  1771.             end
  1772.           elseif mcY == termY and numPages > 1 and mButton == 1 then --# Page Navigation via click
  1773.             if mcX < math.floor(termX / 2) - 3 or mcX > math.floor(termX / 2) + 3 then --# Page Back / Forward
  1774.               pageNum = mcX < math.floor(termX / 2) - 3 and math.max(1, pageNum - 1) or math.min(pageNum + 1, numPages)
  1775.               if pageNum == numPages and numPages > 1 then drawElement(2, 4, termX, termY - 3, nil, black) end
  1776.               drawMainUI()
  1777.               drawNaviUI()
  1778.             elseif mcX > math.floor(termX / 2) - 2 and mcX < math.floor(termX / 2) + 2 then --# Page Numbers (Go To Page dialogue)
  1779.               runState = "goPage"
  1780.               return
  1781.             end
  1782.           end
  1783.         end
  1784.       elseif event == "mouse_scroll" and runState == "List" then
  1785.         pageNum = mButton == 1 and math.min(pageNum + 1, numPages) or math.max(1, pageNum - 1)
  1786.         if pageNum == numPages and numPages > 1 then drawElement(2, 4, termX, termY - 3, nil, black) end
  1787.         drawMainUI()
  1788.         drawNaviUI()
  1789.       elseif event == "key" then
  1790.         if mButton == keys.u and runState == "List" then --# U
  1791.           if runState == "List" then toggleFilter() end
  1792.         elseif mButton == keys.f1 then
  1793.           if runState ~= "Help" then
  1794.             tempState = runState
  1795.             runState = "Help"
  1796.             drawHelpUI()
  1797.           else
  1798.             drawElement(1, 2, termX, termY - 1, nil, black)
  1799.             runState = tempState
  1800.             drawCLI()
  1801.           end
  1802.         end
  1803.       end
  1804.     end
  1805.   end
  1806.  
  1807.   local function colorPicker()
  1808.     local choice = false
  1809.     local _, button, x, y = os.pullEvent("mouse_click")
  1810.     if x > 6 and x < 17 and y > 3 and y < 12 and button == 1 then
  1811.       for colorChoice = 4, 11 do
  1812.         if y == colorChoice then
  1813.           for k, v in pairs(colorBurst) do
  1814.             if (colorChoice - 3) == v.order then
  1815.               netSend(allDevices[thisDevice].cc, "color", k)
  1816.               choice = true
  1817.               break
  1818.             end
  1819.           end
  1820.         end
  1821.         if choice then break end
  1822.       end
  1823.     end
  1824.     drawElement(7, 4, 10, 8, nil, black)
  1825.     viewDeviceEntry()
  1826.   end
  1827.  
  1828.   local function editEntry()
  1829.     if runState == "EditName" then
  1830.       drawElement(2, 4, 1, 1, gray, black, allDevices[thisDevice].name)
  1831.       local newName = readInput(2, 4, yellow, nil, 8)
  1832.       if newName ~= "" then
  1833.         netSend(allDevices[thisDevice].cc, "name", newName)
  1834.         drawElement(2, 4, 8, 1)
  1835.       else
  1836.         drawElement(2, 4, 1, 1, assignColor(allDevices[thisDevice].color), nil, allDevices[thisDevice].name)
  1837.       end
  1838.     elseif runState == "EditNote" then
  1839.       drawElement(2, 8, 1, 1, gray, black, allDevices[thisDevice].note)
  1840.       local newNote = readInput(2, 8, white, nil, 21)
  1841.       if newNote ~= "" then
  1842.         netSend(allDevices[thisDevice].cc, "note", newNote)
  1843.         drawElement(2, 8, 21, 1)
  1844.       else
  1845.         drawElement(2, 8, 1, 1, silver, nil, allDevices[thisDevice].note)
  1846.       end
  1847.     elseif runState == "EditDim" then
  1848.       drawElement(7, 15, 1, 1, gray, black, allDevices[thisDevice].loc.dim)
  1849.       local newDim = readInput(7, 15, sky, nil, 19)
  1850.       if newDim ~= "" then
  1851.         netSend(allDevices[thisDevice].cc, "locDim", newDim)
  1852.         drawElement(7, 15, 19, 1)
  1853.       else
  1854.         drawElement(7, 15, 1, 1, brown, nil, allDevices[thisDevice].loc.dim)
  1855.       end
  1856.     end
  1857.     runState = "Edit"
  1858.   end
  1859.  
  1860.   local function enterPassword()
  1861.     drawElement(math.floor(termX / 2) - 7, 8, 15, 1, white, gray, "   Password:   ")
  1862.     drawElement(math.floor(termX / 2) - 7, 9, 15, 2)
  1863.     drawElement(math.floor(termX / 2) - 6, 9, 13, 1, nil, black) --# input area bg
  1864.     local pass = readInput(math.floor(termX / 2) - 6, 9, lime, nil, 13, "*")
  1865.     if pass ~= "" then
  1866.       local pw = table.concat(pbkdf2(pass, "cc!10", 15))
  1867.       netSend(allDevices[thisDevice].cc, "unlock", pw)
  1868.     end
  1869.     drawElement(math.floor(termX / 2) - 7, 8, 15, 3)
  1870.     runState = "List"
  1871.     drawMainUI()
  1872.   end
  1873.  
  1874.   local function goToPage()
  1875.     drawElement(math.floor(termX / 2) - 3, termY - 3, 7, 1, white, gray, "Page:")
  1876.     drawElement(math.floor(termX / 2) - 3, termY - 2, 7, 2)
  1877.     drawElement(math.floor(termX / 2) - 2, termY - 2, 5, 1, nil, black) --# input area bg
  1878.     local newPage = tonumber(readInput(math.floor(termX / 2) - 1, termY - 2, lime, nil, 3))
  1879.     pageNum = newPage or pageNum
  1880.     pageNum = math.max(1, math.min(pageNum, numPages))
  1881.     if pageNum == numPages and numPages > 1 then
  1882.       drawElement(1, 4, termX, termY - 3)
  1883.     else
  1884.       drawElement(math.floor(termX / 2) - 3, termY - 3, 7, 3)
  1885.     end
  1886.     runState = "List"
  1887.     drawMainUI()
  1888.     drawNaviUI()
  1889.   end
  1890.  
  1891.   local runStates = {
  1892.     List = function() inputMain() end;
  1893.     Edit = function() inputMain() end;
  1894.     Help = function() inputMain() end;
  1895.     EditName = function() editEntry() end;
  1896.     EditNote = function() editEntry() end;
  1897.     EditDim = function() editEntry() end;
  1898.     unlock = function() enterPassword() end;
  1899.     goPage = function() goToPage() end;
  1900.     color = function() colorPicker() end;
  1901.   }
  1902.  
  1903.   userInput = function()
  1904.     repeat
  1905.       if runStates[runState] then runStates[runState]() end
  1906.       if kernelState and timerDelay and not inputting then
  1907.         timerDelay = false
  1908.         pollTimer = os.startTimer(0.1)
  1909.       end
  1910.     until not kernelState
  1911.   end
  1912. end
  1913.  
  1914. local function dataPoller()
  1915.   local removal, _, timerID = false
  1916.   while true do
  1917.     _, timerID = os.pullEvent("timer")
  1918.     if timerID == pollTimer then
  1919.       if runState == "List" then
  1920.         for i = #allDevices, 1, -1 do
  1921.           if allDevices[i].quietCount > 1 then
  1922.             table.remove(allDevices, i)
  1923.             removal = true
  1924.           else
  1925.             allDevices[i].quietCount = allDevices[i].quietCount + 1
  1926.           end
  1927.         end
  1928.         if removal then
  1929.           removal = false
  1930.           filterDeviceList()
  1931.           drawElement(1, 4, termX, termY - 3, nil, black)
  1932.           drawMainUI()
  1933.           drawNaviUI()
  1934.         end
  1935.       end
  1936.       if not timerDelay then
  1937.         netSend("ALL", "QRY", "cc10QRY")
  1938.         pollTimer = os.startTimer(3)
  1939.       end
  1940.     end
  1941.   end
  1942. end
  1943.  
  1944. term.setBackgroundColor(black)
  1945. term.clear()
  1946. if not term.isColor() or not pocket then term.setCursorPos(1, 1) error("Advanced Wireless Pocket Computer Required", 0) end
  1947. drawElement(2, 2, 1, 1, white, nil, "Initializing . . .")
  1948. if not os.getComputerLabel() then os.setComputerLabel("PocketPC.ID#" .. thisCC) end
  1949. if peripheral.isPresent("back") and peripheral.getType("back") == "modem" and peripheral.call("back", "isWireless") then
  1950.   rednet.open("back")
  1951.   netSide = "back"
  1952. else
  1953.   term.clear()
  1954.   drawElement(2, 2, 1, 1, red, nil, "No wireless")
  1955.   drawElement(2, 3, 1, 1, nil, nil, "modem detected!")
  1956.   drawElement(2, 5, 1, 1, nil, nil, "cc10 REQUIRES")
  1957.   drawElement(2, 6, 1, 1, nil, nil, "a wireless modem.")
  1958.   term.setCursorPos(1, 9)
  1959.   return
  1960. end
  1961. runState = "List"
  1962. drawElement(2, 4, 1, 1, white, nil, "Searching for hosts . . .")
  1963. netSend("ALL", "QRY", "cc10QRY")
  1964. pollTimer = os.startTimer(3)
  1965. term.clear()
  1966. drawCLI()
  1967. parallel.waitForAny(userInput, netReceive, dataPoller)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement