Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ---------------------------
- -- Initial Loading Start --
- ---------------------------
- local d = false
- local mod = nil
- for k, v in pairs(peripheral.getNames()) do
- if peripheral.getType(v) == "modem" then
- rednet.open(v)
- mod = peripheral.wrap(v)
- d = true
- end
- end
- if not d or not mod then
- error("A modem is required!")
- end
- local function gen_nonce(size)
- local n = {}
- for i = 1, size do
- n[#n + 1] = math.random(0, 255)
- end
- return n
- end
- local function cc_encrypt(msg, key)
- local nonce = gen_nonce(12)
- local ctx = chacha.crypt(msg, key, nonce)
- return nonce, ctx
- end
- local function cc_decrypt(ctx, key, nonce)
- return chacha.crypt(ctx, key, nonce)
- end
- local function download_file(url, target)
- local ht = http.get(url)
- local data = ht.readAll()
- ht.close()
- local file = fs.open(target, "w")
- file.write(data)
- file.close()
- end
- local function getAPI(url, name)
- local apiloc = "/" .. name
- if (not fs.exists(apiloc)) then
- local newapiloc = shell and shell.resolveProgram(name) or nil
- if type(newapiloc) ~= "string" then
- download_file(url, "/" .. name)
- else
- apiloc = newapiloc
- end
- end
- os.loadAPI(apiloc)
- if type(_G[name]) ~= "table" then
- error(name .. " failed to load!")
- return
- end
- end
- getAPI("https://pastebin.com/raw/hCbYTgRs", "ring")
- getAPI("https://pastebin.com/raw/GPzf9JSa", "chacha")
- getAPI("https://pastebin.com/raw/6UV4qfNF", "crypt")
- -------------------------
- -- Initial Loading End --
- -------------------------
- local crypt_keys = {}
- local crypt_precaps = {}
- local crypt_channels = {}
- local all_connections = {}
- local our_rids = {}
- local msg_counter = {}
- local ongoing_handshakes = {}
- if _G.snet_debug == nil then
- _G.snet_debug = false
- end
- local handshake_id =
- string.sub(crypt.digest(tostring(os.getComputerID()) .. tostring(math.random(1, 99999))):toHex(), 1, 8)
- ----------------------------
- -- Helper Functions Begin --
- ----------------------------
- local function mesoData(mes)
- if (type(mes) == "string") then
- return textutils.unserialize(mes) or {}
- elseif (type(mes) == "table") then
- return mes
- end
- return {}
- end
- local function get_msg(id)
- return msg_counter[id] or 0
- end
- local function get_frq(id)
- return last_frq[id] or 1337
- end
- local function logDebug(mes)
- if not _G.snet_debug then
- return false
- end
- print("[DEBUG] " .. tostring(mes))
- end
- local function isConnectionID(id)
- for k, v in pairs(all_connections) do
- if v == id then
- return true
- end
- end
- return false
- end
- local function isOurRid(id)
- for k, v in pairs(our_rids) do
- if v == id then
- return true
- end
- end
- return false
- end
- function openChannel(ch)
- mod.open(ch)
- end
- local function closeConnection(id)
- end
- --------------------------
- -- Helper Functions End --
- --------------------------
- logDebug("Our handshake-UID is " .. tostring(handshake_id) .. "!")
- ----------------------------
- -- Actual functions begin --
- ----------------------------
- function connectionHandler(clientMode)
- while true do
- local _, side, sfrq, rfrq, mes, dist = os.pullEvent("modem_message")
- if (type(mes) == "string") then
- mes = textutils.unserialize(mes)
- end
- if (type(mes) == "table") then
- local srid = tostring(mes.rid)
- logDebug(
- (mes.type or "invalid") ..
- " | " .. srid .. " (" .. ((isOurRid(mes.rid) and "Y") or "N") .. ") | " .. (mes.target or "none")
- )
- if
- (not clientMode and mes.type == "RLWE_OPEN" and mes.target == handshake_id and type(mes.rid) == "number" and
- string.len(srid) >= 5 and
- not crypt_precaps[srid] and
- not ongoing_handshakes[srid])
- then
- local s1, b = ring.keyPair()
- crypt_precaps[srid] = s1
- ongoing_handshakes[srid] = true
- mod.transmit(
- sfrq,
- sfrq,
- {
- type = "RLWE_TUNNEL1",
- rid = mes.rid,
- from = handshake_id,
- capsule = b
- }
- )
- elseif
- (clientMode and mes.type == "RLWE_TUNNEL1" and isOurRid(mes.rid) and ongoing_handshakes[srid] and
- type(mes.from) == "string" and
- string.len(mes.from) == 8)
- then
- local mu, c = ring.encapsulate(mes.capsule)
- local ekey = crypt.pbkdf2(mu, "1enc", 50, 32)
- local hkey = crypt.pbkdf2(mu, "2hmac", 50, 32)
- local cxkey = crypt.pbkdf2(mu, "3cxid", 50, 32)
- local ckey = crypt.pbkdf2(mu, "4channel", 50, 2)
- local cid = cxkey:toHex()
- crypt_keys[cid] = {
- enckey = ekey,
- cidkey = cxkey,
- chankey = ckey,
- hmackey = hkey
- }
- crypt_channels[cid] = bit.bor(bit.blshift(ckey[1], 8), ckey[2])
- logDebug("Agreed on channel " .. tostring(crypt_channels[cid]) .. "!")
- ongoing_handshakes[srid] = false
- mod.transmit(
- sfrq,
- sfrq,
- textutils.serialize(
- {
- type = "RLWE_TUNNEL2",
- capsule = c,
- target = mes.from,
- rid = mes.rid
- }
- )
- )
- os.queueEvent("tunnel_key", cid)
- elseif
- (not clientMode and mes.type == "RLWE_TUNNEL2" and mes.target == handshake_id and type(mes.rid) == "number" and
- string.len(srid) >= 5 and
- crypt_precaps[srid] and
- ongoing_handshakes[srid] and
- type(mes.capsule) == "table")
- then
- local mu = ring.decapsulate(crypt_precaps[srid], mes.capsule)
- local ekey = crypt.pbkdf2(mu, "1enc", 50, 32)
- local hkey = crypt.pbkdf2(mu, "2hmac", 50, 32)
- local cxkey = crypt.pbkdf2(mu, "3cxid", 50, 32)
- local ckey = crypt.pbkdf2(mu, "4channel", 50, 2)
- local cid = cxkey:toHex()
- crypt_keys[cid] = {
- enckey = ekey,
- cidkey = cxkey,
- chankey = ckey,
- hmackey = hkey
- }
- crypt_channels[cid] = bit.bor(bit.blshift(ckey[1], 8), ckey[2])
- logDebug("Agreed on channel " .. tostring(crypt_channels[cid]) .. "!")
- ongoing_handshakes[srid] = false
- os.queueEvent("tunnel_finish", cid)
- elseif
- (mes.type == "RLWE_DATA" and type(mes.cid) == "string" and string.len(mes.cid) == 8 and
- type(crypt_keys[mes.cid]) == "table" and
- type(mes.dnonce) == "table" and
- type(mes.dctx) == "string" and
- type(mes.dhmac) == "string" and
- sfrq == crypt_channels[mes.cid])
- then
- local ekey = crypt_keys[mes.cid]["enckey"]
- local hkey = crypt_keys[mes.cid]["hmackey"]
- local chmac = tostring(crypt.hmac(tostring(get_msg(mes.cid)) .. tostring(mes.dctx), hkey))
- logDebug("Message counter: " .. tostring(textutils.serialize(msg_counter)))
- logDebug("Our hmac: " .. tostring(chmac))
- logDebug("Their hmac: " .. tostring(mes.dhmac))
- logDebug("Our hkey: " .. tostring(hkey))
- logDebug("Our hstr:" .. tostring(get_msg(mes.cid)) .. tostring(mes.dctx))
- if (mes.dhmac == chmac) then
- msg_counter[mes.cid] = (get_msg(mes.cid) + 1)
- logDebug("HMAC matched!")
- local dctx = tostring(cc_decrypt(mes.dctx, ekey, mes.dnonce))
- logDebug("Decrypted: " .. dctx)
- logDebug("New message counter for " .. tostring(mes.cid) .. ": " .. tostring(get_msg(mes.cid)))
- os.queueEvent("secure_receive", mes.cid, dctx, dist)
- end
- end
- end
- end
- end
- function openTunnel(targetID, frq)
- assert(type(targetID) == "string", "openTunnel requires a HUID!")
- assert(type(frq) == "number", "openTunnel modem frequency must be a number!")
- local rid = math.random(100000, 999999)
- ongoing_handshakes[tostring(rid)] = true
- table.insert(our_rids, rid)
- logDebug("OUR RID IS " .. tostring(rid))
- mod.transmit(
- frq,
- frq,
- textutils.serialize(
- {
- type = "RLWE_OPEN",
- rid = rid,
- target = targetID
- }
- )
- )
- end
- function sendData(targetCID, data)
- assert(type(targetCID) == "string", "targetCID must be a string!")
- assert(string.len(targetCID) == 8, "targetCID must be an 8-character string!")
- assert(type(data) == "string", "data must be a string!")
- if (type(data) == "table") then
- data = textutils.serialize(data)
- end
- data = tostring(data)
- assert(type(crypt_keys) == "table", "Oh god, there is no key table!")
- local keys = crypt_keys[targetCID]
- assert(type(crypt_keys[targetCID]) == "table", "No encryption key for " .. tostring(targetCID))
- assert(type(crypt_channels[targetCID]) == "number", "No channel for " .. tostring(targetCID))
- local ekey = keys["enckey"]
- local hkey = keys["hmackey"]
- local dnonce, dctx = cc_encrypt(data, ekey)
- logDebug("Message counter: " .. tostring(get_msg(targetCID)))
- logDebug("Our hkey: " .. tostring(hkey))
- logDebug("Our hstr: " .. tostring(get_msg(targetCID)) .. tostring(dctx))
- mod.transmit(
- crypt_channels[targetCID],
- crypt_channels[targetCID],
- textutils.serialize(
- {
- type = "RLWE_DATA",
- cid = targetCID,
- dhmac = tostring(crypt.hmac(tostring(get_msg(targetCID)) .. tostring(dctx), hkey)),
- dctx = dctx,
- dnonce = dnonce
- }
- )
- )
- msg_counter[targetCID] = get_msg(targetCID) + 1
- end
Advertisement
Add Comment
Please, Sign In to add comment