turtle5204

New Ringnet API

Apr 23rd, 2018
253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.74 KB | None | 0 0
  1. ---------------------------
  2. -- Initial Loading Start --
  3. ---------------------------
  4. local d = false
  5. local mod = nil
  6. for k, v in pairs(peripheral.getNames()) do
  7.     if peripheral.getType(v) == "modem" then
  8.         rednet.open(v)
  9.         mod = peripheral.wrap(v)
  10.         d = true
  11.     end
  12. end
  13. if not d or not mod then
  14.     error("A modem is required!")
  15. end
  16.  
  17. local function gen_nonce(size)
  18.     local n = {}
  19.     for i = 1, size do
  20.         n[#n + 1] = math.random(0, 255)
  21.     end
  22.     return n
  23. end
  24.  
  25. local function cc_encrypt(msg, key)
  26.     local nonce = gen_nonce(12)
  27.     local ctx = chacha.crypt(msg, key, nonce)
  28.     return nonce, ctx
  29. end
  30.  
  31. local function cc_decrypt(ctx, key, nonce)
  32.     return chacha.crypt(ctx, key, nonce)
  33. end
  34.  
  35. local function download_file(url, target)
  36.     local ht = http.get(url)
  37.     local data = ht.readAll()
  38.     ht.close()
  39.     local file = fs.open(target, "w")
  40.     file.write(data)
  41.     file.close()
  42. end
  43.  
  44. local function getAPI(url, name)
  45.     local apiloc = "/" .. name
  46.     if (not fs.exists(apiloc)) then
  47.         local newapiloc = shell and shell.resolveProgram(name) or nil
  48.         if type(newapiloc) ~= "string" then
  49.             download_file(url, "/" .. name)
  50.         else
  51.             apiloc = newapiloc
  52.         end
  53.     end
  54.     os.loadAPI(apiloc)
  55.     if type(_G[name]) ~= "table" then
  56.         error(name .. " failed to load!")
  57.         return
  58.     end
  59. end
  60.  
  61. getAPI("https://pastebin.com/raw/hCbYTgRs", "ring")
  62. getAPI("https://pastebin.com/raw/GPzf9JSa", "chacha")
  63. getAPI("https://pastebin.com/raw/6UV4qfNF", "crypt")
  64. -------------------------
  65. -- Initial Loading End --
  66. -------------------------
  67.  
  68. local crypt_keys = {}
  69. local crypt_precaps = {}
  70. local crypt_channels = {}
  71. local all_connections = {}
  72. local our_rids = {}
  73. local msg_counter = {}
  74. local ongoing_handshakes = {}
  75.  
  76. if _G.snet_debug == nil then
  77.     _G.snet_debug = false
  78. end
  79.  
  80. local handshake_id =
  81.     string.sub(crypt.digest(tostring(os.getComputerID()) .. tostring(math.random(1, 99999))):toHex(), 1, 8)
  82.  
  83. ----------------------------
  84. -- Helper Functions Begin --
  85. ----------------------------
  86.  
  87. local function mesoData(mes)
  88.     if (type(mes) == "string") then
  89.         return textutils.unserialize(mes) or {}
  90.     elseif (type(mes) == "table") then
  91.         return mes
  92.     end
  93.     return {}
  94. end
  95.  
  96. local function get_msg(id)
  97.     return msg_counter[id] or 0
  98. end
  99.  
  100. local function get_frq(id)
  101.     return last_frq[id] or 1337
  102. end
  103.  
  104. local function logDebug(mes)
  105.     if not _G.snet_debug then
  106.         return false
  107.     end
  108.     print("[DEBUG] " .. tostring(mes))
  109. end
  110.  
  111. local function isConnectionID(id)
  112.     for k, v in pairs(all_connections) do
  113.         if v == id then
  114.             return true
  115.         end
  116.     end
  117.     return false
  118. end
  119.  
  120. local function isOurRid(id)
  121.     for k, v in pairs(our_rids) do
  122.         if v == id then
  123.             return true
  124.         end
  125.     end
  126.     return false
  127. end
  128.  
  129. function openChannel(ch)
  130.     mod.open(ch)
  131. end
  132.  
  133. local function closeConnection(id)
  134. end
  135.  
  136. --------------------------
  137. -- Helper Functions End --
  138. --------------------------
  139.  
  140. logDebug("Our handshake-UID is " .. tostring(handshake_id) .. "!")
  141.  
  142. ----------------------------
  143. -- Actual functions begin --
  144. ----------------------------
  145.  
  146. function connectionHandler(clientMode)
  147.     while true do
  148.         local _, side, sfrq, rfrq, mes, dist = os.pullEvent("modem_message")
  149.         if (type(mes) == "string") then
  150.             mes = textutils.unserialize(mes)
  151.         end
  152.         if (type(mes) == "table") then
  153.             local srid = tostring(mes.rid)
  154.             logDebug(
  155.                 (mes.type or "invalid") ..
  156.                     " | " .. srid .. " (" .. ((isOurRid(mes.rid) and "Y") or "N") .. ") | " .. (mes.target or "none")
  157.             )
  158.             if
  159.                 (not clientMode and mes.type == "RLWE_OPEN" and mes.target == handshake_id and type(mes.rid) == "number" and
  160.                     string.len(srid) >= 5 and
  161.                     not crypt_precaps[srid] and
  162.                     not ongoing_handshakes[srid])
  163.              then
  164.                 local s1, b = ring.keyPair()
  165.                 crypt_precaps[srid] = s1
  166.                 ongoing_handshakes[srid] = true
  167.                 mod.transmit(
  168.                     sfrq,
  169.                     sfrq,
  170.                     {
  171.                         type = "RLWE_TUNNEL1",
  172.                         rid = mes.rid,
  173.                         from = handshake_id,
  174.                         capsule = b
  175.                     }
  176.                 )
  177.             elseif
  178.                 (clientMode and mes.type == "RLWE_TUNNEL1" and isOurRid(mes.rid) and ongoing_handshakes[srid] and
  179.                     type(mes.from) == "string" and
  180.                     string.len(mes.from) == 8)
  181.              then
  182.                 local mu, c = ring.encapsulate(mes.capsule)
  183.  
  184.                 local ekey = crypt.pbkdf2(mu, "1enc", 50, 32)
  185.                 local hkey = crypt.pbkdf2(mu, "2hmac", 50, 32)
  186.                 local cxkey = crypt.pbkdf2(mu, "3cxid", 50, 32)
  187.                 local ckey = crypt.pbkdf2(mu, "4channel", 50, 2)
  188.  
  189.                 local cid = cxkey:toHex()
  190.                 crypt_keys[cid] = {
  191.                     enckey = ekey,
  192.                     cidkey = cxkey,
  193.                     chankey = ckey,
  194.                     hmackey = hkey
  195.                 }
  196.                 crypt_channels[cid] = bit.bor(bit.blshift(ckey[1], 8), ckey[2])
  197.                 logDebug("Agreed on channel " .. tostring(crypt_channels[cid]) .. "!")
  198.                 ongoing_handshakes[srid] = false
  199.                 mod.transmit(
  200.                     sfrq,
  201.                     sfrq,
  202.                     textutils.serialize(
  203.                         {
  204.                             type = "RLWE_TUNNEL2",
  205.                             capsule = c,
  206.                             target = mes.from,
  207.                             rid = mes.rid
  208.                         }
  209.                     )
  210.                 )
  211.                 os.queueEvent("tunnel_key", cid)
  212.             elseif
  213.                 (not clientMode and mes.type == "RLWE_TUNNEL2" and mes.target == handshake_id and type(mes.rid) == "number" and
  214.                     string.len(srid) >= 5 and
  215.                     crypt_precaps[srid] and
  216.                     ongoing_handshakes[srid] and
  217.                     type(mes.capsule) == "table")
  218.              then
  219.                 local mu = ring.decapsulate(crypt_precaps[srid], mes.capsule)
  220.                 local ekey = crypt.pbkdf2(mu, "1enc", 50, 32)
  221.                 local hkey = crypt.pbkdf2(mu, "2hmac", 50, 32)
  222.                 local cxkey = crypt.pbkdf2(mu, "3cxid", 50, 32)
  223.                 local ckey = crypt.pbkdf2(mu, "4channel", 50, 2)
  224.  
  225.                 local cid = cxkey:toHex()
  226.                 crypt_keys[cid] = {
  227.                     enckey = ekey,
  228.                     cidkey = cxkey,
  229.                     chankey = ckey,
  230.                     hmackey = hkey
  231.                 }
  232.                 crypt_channels[cid] = bit.bor(bit.blshift(ckey[1], 8), ckey[2])
  233.                 logDebug("Agreed on channel " .. tostring(crypt_channels[cid]) .. "!")
  234.                 ongoing_handshakes[srid] = false
  235.                 os.queueEvent("tunnel_finish", cid)
  236.             elseif
  237.                 (mes.type == "RLWE_DATA" and type(mes.cid) == "string" and string.len(mes.cid) == 8 and
  238.                     type(crypt_keys[mes.cid]) == "table" and
  239.                     type(mes.dnonce) == "table" and
  240.                     type(mes.dctx) == "string" and
  241.                     type(mes.dhmac) == "string" and
  242.                     sfrq == crypt_channels[mes.cid])
  243.              then
  244.                 local ekey = crypt_keys[mes.cid]["enckey"]
  245.                 local hkey = crypt_keys[mes.cid]["hmackey"]
  246.                 local chmac = tostring(crypt.hmac(tostring(get_msg(mes.cid)) .. tostring(mes.dctx), hkey))
  247.                 logDebug("Message counter: " .. tostring(textutils.serialize(msg_counter)))
  248.                 logDebug("Our hmac: " .. tostring(chmac))
  249.                 logDebug("Their hmac: " .. tostring(mes.dhmac))
  250.                 logDebug("Our hkey: " .. tostring(hkey))
  251.                 logDebug("Our hstr:" .. tostring(get_msg(mes.cid)) .. tostring(mes.dctx))
  252.                 if (mes.dhmac == chmac) then
  253.                     msg_counter[mes.cid] = (get_msg(mes.cid) + 1)
  254.                     logDebug("HMAC matched!")
  255.                     local dctx = tostring(cc_decrypt(mes.dctx, ekey, mes.dnonce))
  256.                     logDebug("Decrypted: " .. dctx)
  257.                     logDebug("New message counter for " .. tostring(mes.cid) .. ": " .. tostring(get_msg(mes.cid)))
  258.                     os.queueEvent("secure_receive", mes.cid, dctx, dist)
  259.                 end
  260.             end
  261.         end
  262.     end
  263. end
  264.  
  265. function openTunnel(targetID, frq)
  266.     assert(type(targetID) == "string", "openTunnel requires a HUID!")
  267.     assert(type(frq) == "number", "openTunnel modem frequency must be a number!")
  268.     local rid = math.random(100000, 999999)
  269.     ongoing_handshakes[tostring(rid)] = true
  270.     table.insert(our_rids, rid)
  271.     logDebug("OUR RID IS  " .. tostring(rid))
  272.     mod.transmit(
  273.         frq,
  274.         frq,
  275.         textutils.serialize(
  276.             {
  277.                 type = "RLWE_OPEN",
  278.                 rid = rid,
  279.                 target = targetID
  280.             }
  281.         )
  282.     )
  283. end
  284.  
  285. function sendData(targetCID, data)
  286.     assert(type(targetCID) == "string", "targetCID must be a string!")
  287.     assert(string.len(targetCID) == 8, "targetCID must be an 8-character string!")
  288.     assert(type(data) == "string", "data must be a string!")
  289.     if (type(data) == "table") then
  290.         data = textutils.serialize(data)
  291.     end
  292.     data = tostring(data)
  293.     assert(type(crypt_keys) == "table", "Oh god, there is no key table!")
  294.     local keys = crypt_keys[targetCID]
  295.     assert(type(crypt_keys[targetCID]) == "table", "No encryption key for " .. tostring(targetCID))
  296.     assert(type(crypt_channels[targetCID]) == "number", "No channel for " .. tostring(targetCID))
  297.     local ekey = keys["enckey"]
  298.     local hkey = keys["hmackey"]
  299.     local dnonce, dctx = cc_encrypt(data, ekey)
  300.     logDebug("Message counter: " .. tostring(get_msg(targetCID)))
  301.     logDebug("Our hkey: " .. tostring(hkey))
  302.     logDebug("Our hstr: " .. tostring(get_msg(targetCID)) .. tostring(dctx))
  303.     mod.transmit(
  304.         crypt_channels[targetCID],
  305.         crypt_channels[targetCID],
  306.         textutils.serialize(
  307.             {
  308.                 type = "RLWE_DATA",
  309.                 cid = targetCID,
  310.                 dhmac = tostring(crypt.hmac(tostring(get_msg(targetCID)) .. tostring(dctx), hkey)),
  311.                 dctx = dctx,
  312.                 dnonce = dnonce
  313.             }
  314.         )
  315.     )
  316.     msg_counter[targetCID] = get_msg(targetCID) + 1
  317. end
Advertisement
Add Comment
Please, Sign In to add comment