Advertisement
Restioson

Secure Network Router

Mar 21st, 2017
178
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.65 KB | None | 0 0
  1. -- Load APIs
  2. os.loadAPI("disk/secunet/apis/uuid")
  3. os.loadAPI("disk/secunet/apis/base64")
  4. os.loadAPI("disk/secunet/apis/aeslua")
  5.  
  6. -- Variables
  7. local userdata = {} -- (Array of usernames as keys with values as table of userdata [HashMap<String, HashMap<String, String>>])
  8. local usernameByPin = {} -- Look up username by pin
  9. local hosts = {} -- Similar to DNS : Lookup usrname by hostname
  10. local reverseHosts = {} -- Reverse hosts
  11. local modem = peripheral.wrap("top")
  12.  
  13. -- Thanks to Lyqyd for this function
  14. local function split(input)
  15.  
  16.     local results = {}
  17.    
  18.     for regexmatch in string.gmatch(input, "[^ ]+") do
  19.         table.insert(results, regexmatch)
  20.     end
  21.  
  22.     return results
  23. end
  24.  
  25. -- Thanks to Lyqyd for this function
  26. local function splitTab(input)
  27.  
  28.     local results = {}
  29.    
  30.     for regexmatch in string.gmatch(input, "[^\t]+") do -- edit
  31.         table.insert(results, regexmatch)
  32.     end
  33.  
  34.     return results
  35. end
  36.  
  37.  
  38. -- Generates IV table
  39. local function generateIV()
  40.    
  41.     local index = 1
  42.     local iv = {}
  43.    
  44.     repeat
  45.    
  46.     iv[index] = math.random(1, 255)
  47.     index = index + 1
  48.    
  49.     until index == 17
  50.    
  51.     return iv
  52.  
  53. end
  54.  
  55. -- Encrypt
  56. local function encrypt(key, message, iv)
  57.     return aeslua.encrypt(key, message, aeslua.AES256, aeslua.CBCMODE, iv)
  58. end
  59.  
  60. -- Decrypt
  61. local function decrypt(key, message, iv)
  62.     return aeslua.decrypt(key, message, aeslua.AES256, aeslua.CBCMODE, iv)
  63. end
  64.  
  65. -- Saves user data
  66. local function saveUserdata(password)
  67.  
  68.     local userfile = assert(fs.open(shell.dir() .. "/users/server.dat", "w"))
  69.     local iv = generateIV()
  70.     local data = textutils.serialize(iv) .. "\t".. base64.enc(encrypt(password, textutils.serialize(userdata), iv))
  71.     userfile.write(data)
  72.     userfile.close()
  73.  
  74. end
  75.  
  76. -- Open and decrypt users' login details
  77. local function getUserdata(password)
  78.     if fs.exists(shell.dir() .. "/users/server.dat") ~= true then return end
  79.     local userfile = fs.open(shell.dir() .. "/users/server.dat", "r")
  80.     local userfileData = userfile.readAll()
  81.     local userfileIvSerialized = splitTab(userfileData)[1]
  82.     local userfileDataSplit = splitTab(userfileData)
  83.     table.remove(userfileDataSplit, 1)
  84.     local userfileDataEncrypted = base64.dec(table.concat(userfileDataSplit, " "))
  85.     local iv = textutils.unserialize(userfileIvSerialized)
  86.     local message = userfileDataEncrypted
  87.     local cleartextDetails = decrypt(password, message, iv)
  88.     if cleartextDetails == nil then
  89.         error()
  90.     end
  91.     userfile.close()
  92.     userdata = textutils.unserialize(cleartextDetails)
  93.     print("Successfully loaded " .. table.getn(userdata) .. " users")
  94.    
  95. end
  96.  
  97. -- Returns 16 bit random
  98. local function random128()
  99.     local charset = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"}
  100.     return tostring(math.random(10000000, 99999999))..tostring(math.random(10000000, 99999999))..tostring(math.random(10000000, 99999999))..tostring(math.random(10000000, 99999999))
  101. end
  102.  
  103. -- Generates a user
  104. local function generateUser(username, hostnames) -- Hostnames is an array of hostnames
  105.  
  106.     local user = {}
  107.     user["pin"] = uuid.Generate()
  108.     user["msgpassword"] = random128()
  109.     user["hmacpassword"] = random128()
  110.     user["username"] = username
  111.    
  112.     for key, value in pairs(hostnames) do
  113.         hosts[value] = username
  114.     end
  115.    
  116.     hosts[username] = username
  117.     reverseHosts[username] = hostnames
  118.     usernameByPin[user["pin"]] = username
  119.    
  120.     return user
  121.    
  122. end
  123.  
  124. -- Split cleartext data for server
  125. local function splitDataServer(cleartext)
  126.    
  127.     -- Data table
  128.     data = {}
  129.    
  130.     -- Split cleartext
  131.     cleartextSplit = split(cleartext)
  132.    
  133.     -- Put into data table
  134.     data["hmac"] = table.remove(cleartextSplit, 1)
  135.     data["destination"] = table.remove(cleartextSplit, (1))
  136.     data["nextmsgpassword"] = table.remove(cleartextSplit, (1))
  137.     data["nexthashpasswd"] = table.remove(cleartextSplit, (1))
  138.     data["message"] = table.concat(cleartextSplit)
  139.    
  140.     return data
  141.  
  142. end
  143.  
  144. -- Lookup usrname from hostname
  145. local function lookup(name)
  146.     return hosts[name]
  147. end
  148.  
  149. -- Reverse lookup
  150. local function reverseLookup(username)
  151.     return reverseHosts[username]
  152. end
  153.  
  154. -- Extracts data from packet
  155. local function handleData(packet)
  156.  
  157.     -- Split message
  158.     local messagesplit = split(packet)
  159.  
  160.     -- Filter for spam
  161.     if usernameByPin[messagesplit[1]] ~= nil then
  162.        
  163.         -- remove pin from message
  164.        table.remove(messagesplit, 1)
  165.        
  166.         -- Decrypt data
  167.         local decryptedData = decrypt(userdata["messagepassword"], base64.dec(messagesplit), textutils.unserialize(table.remove(messagesplit,1)))
  168.        
  169.         -- Split data
  170.         local splitErrorHappened, data = pcall(splitDataServer, decryptedData)
  171.        
  172.         if splitErrorHappened ~= true then
  173.             error("Invalid packet")
  174.        
  175.         -- Split successful
  176.         else
  177.            
  178.             -- Check hmac
  179.             local hmacErrorHappened, valid = pcall(data["hmac"], data["message"])
  180.            
  181.             if hmacErrorHappened ~= true then
  182.                 error("Error comparing HMACs!")
  183.             end
  184.            
  185.             if valid then
  186.                 return data
  187.    
  188.             else
  189.                 error("HMAC invalid!")
  190.             end
  191.            
  192.         end
  193.     end
  194. end
  195.  
  196. -- Send message
  197. local function send(message, destinationip, sender)
  198.  
  199.     -- Check for connection
  200.     assert(connected, "Not connected to server!")
  201.    
  202.     -- Create header
  203.     local pin = userdata["pin"]
  204.     local destination = destinationip
  205.     local nextmsgpasswd = random128()
  206.     local nexthashpasswd = random128()
  207.     local nextpin = uuid.Generate()
  208.     local hmac = sha.hmac(message, userdata[destinationuser]["hmacpassword"])
  209.     local iv = generateIV()
  210.    
  211.     -- Create encrypted message body
  212.     local messagebody = " " .. base64.enc(encrypt(userdata[destinationuser]["msgpassword"], hmac .. "" .. sender .. " " .. nextpin .. " " .. msgpasswd .. " " .. hashpasswd .. " " .. userdata[destinationuser]["msgpassword"] ..  message))
  213.    
  214.     -- Concat pin with messagebody
  215.     local message = pin .. " " .. iv .. " " .. messagebody
  216.    
  217.     -- Transmit to server
  218.     modem.transmit(channel, channel, message)
  219.    
  220.     -- Save the next passwords and pins
  221.     userdata["messagepassword"] = nextmspasswd
  222.     userdata["hmacpassword"] = nexthashpasswd
  223.     userdata["pin"] = nextpin
  224.    
  225.        
  226. end
  227.  
  228. -- Listen for packets
  229. local function listen()
  230.     while true do
  231.         os.queueEvent(".")
  232.         os.pullEvent(".")
  233.         modem.open(4000)
  234.         local event = {os.pullEvent()} -- event[1] = event --Wait for event
  235.         if event[1] == "modem_message" then -- event[2] = modemside; event[3] = senderchannel; event[4] = replychannel; event[5] = message; event[6] = senderDistance;
  236.             print(event[5])
  237.             local handleDataErrorHappened, data = pcall(handleData, event[5])
  238.            
  239.             if handleDataErrorHappened ~=  true then
  240.            
  241.             else
  242.                
  243.                 local usrname = usernameByPin[data["pin"]]
  244.                
  245.                 userdata[usrname]["hmacpassword"] = messageData["nexthashpasswd"]
  246.                 userdata[usrname]["msgpassword"] = messageData["nextmsgpasswd"]
  247.                 userdata[usrname]["pin"] = messageData["nextpin"]
  248.                
  249.                 lookupErrorHappened, username = pcall(lookup(data["destination"]))
  250.                
  251.                 if (lookupErrorHappened ~= true) then
  252.                
  253.                 elseif (username ~= nil) then
  254.                     send(data["message"], data["destination"], usrname)
  255.                 end
  256.             end
  257.         end
  258.     end
  259. end
  260.  
  261.  
  262. -- Shell (runs for 1 cycle)
  263. local function usrshell()
  264.     io.write("> ")
  265.     input = read()
  266.    
  267.     if input == "end" then
  268.         io.write("Enter server password: ")
  269.         saveUserdata(read("*"))
  270.         os.queueEvent("terminate")
  271.     end
  272.    
  273.     local usr = generateUser(input, {input})
  274.     print("User generated.")
  275.     io.write("Enter server password: ")
  276.     local pass = read("*")
  277.     userdata[input] = usr
  278.     saveUserdata(pass)
  279. end
  280.  
  281. -- Main thread
  282. function main()
  283.    
  284.     -- Gets server data
  285.     repeat
  286.         io.write("Enter server password: ")
  287.         password = read("*")
  288.         success, return_value = pcall(getUserdata, password)
  289.         if success ~= true then print("Error! Wrong password") end
  290.     until success == true
  291.    
  292.     print(textutils.serialize(userdata))
  293.    
  294.     while true do
  295.          parallel.waitForAny(listen, usrshell)
  296.     end
  297.    
  298.    
  299. end
  300.  
  301. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement