Add some silly examples

This commit is contained in:
Christopher Cookman 2024-10-28 00:36:51 -06:00
parent 02a1d78578
commit 3901045eef
Signed by: ChrisChrome
GPG key ID: A023A26E42C33A42
6 changed files with 314 additions and 0 deletions

View file

@ -0,0 +1,3 @@
# E2EE P2P RedNet chat.
This ones a hot mess, apologies for that.
Uses ed25519 keys to get a shared key that isn't transmitted, used to encrypt messages with chacha20

View file

@ -0,0 +1,205 @@
term.clear()
term.setCursorPos(1, 1)
-- Find modems
for _, sModem in ipairs(peripheral.getNames()) do
if peripheral.getType(sModem) == "modem" then rednet.open(sModem) end
end
local knownHosts = settings.get("knownhosts")
if knownHosts == nil then
settings.set("knownhosts", {})
settings.save()
end
local isClient = true
local PK = nil
local crypto = require("ccryptolib")
crypto.random.initWithTiming()
local to = arg[1] -- Who we're trying to talk to (computer id)
write("Your Nickname: ")
local from = read()
if to == nil then print("You need to provide a computer ID!") end
local hexPrivate = settings.get("keys.private")
local hexPublic = settings.get("keys.public")
if hexPrivate == nil then
settings.set("keys.private", crypto.util.toHex(crypto.random.random(32)))
hexPrivate = settings.get("keys.private")
settings.save()
end
if hexPublic == nil then
settings.set("keys.public", crypto.util.toHex(crypto.x25519.publicKey(crypto.util.fromHex(settings.get("keys.private")))))
hexPublic = settings.get("keys.public")
settings.save()
end
local privateKey = crypto.util.fromHex(hexPrivate)
local publicKey = crypto.util.fromHex(hexPublic)
local termX, termY = term.getSize()
function string.starts(String, Start)
return string.sub(String, 1, string.len(Start)) == Start
end
function rx()
while true do
sleep(0)
sender, rawData = rednet.receive("encChat")
if sender ~= tonumber(to) then return end
data = textutils.unserialise(crypto.chacha20.crypt(PK, rawData.nonce, rawData.data))
if not data.test then return end -- Failed decrypt, possible bad key exchange?
term.setCursorPos(1, termY)
term.clearLine()
print(data.from .. ":" .. data.msg)
term.blit("> ", "30", "ff")
term.setCursorPos(3, termY)
end
end
function tx()
while true do
sleep(0)
term.setCursorPos(1, termY)
term.blit("> ", "30", "ff")
local msg = read()
if (string.starts(msg, "/")) then
-- Command handler
msg = string.lower(msg)
if msg == ("/q" or "/quit" or "/exit") then
error("Goodbye!")
end
else
term.scroll(-1)
term.clearLine()
write(from .. ":" .. msg)
term.scroll(1)
nonce = crypto.random.random(12)
msgData = {
timestamp = os.epoch("utc"),
msg = msg,
from = from,
test = true
}
rednet.send(tonumber(to), {
nonce = nonce,
data = crypto.chacha20
.crypt(PK, nonce, textutils.serialise(msgData))
}, "encChat")
end
end
end
function ping()
local fails = 0
if isClient then
while true do
sleep(1)
nonce = crypto.random.random(12)
msgData = {timestamp = os.epoch("utc"), test = true}
rednet.send(tonumber(to), {
nonce = nonce,
data = crypto.chacha20
.crypt(PK, nonce, textutils.serialise(msgData))
}, "encPing")
-- Wait for reply
sender, reply = rednet.receive("encPingReply", 5)
if fails > 2 then
error(
"No response from other user, They likely closed their client exiting...")
end
if sender == nil or data == nil then
fails = fails + 1
elseif crypto.chacha20.crypt(PK, reply.nonce, reply.data) ~=
tostring(msgData.timestamp) then
error("Invalid reply from ping, exiting for security.")
else
fails = 0
end
end
else
while true do
sleep(1)
sender, data = rednet.receive("encPing", 10)
if fails > 1 then
error("No response from other user, They likely closed their client exiting...")
end
if sender == nil or data == nil then
fails = fails + 1
elseif sender == tonumber(to) then
timestamp = textutils.unserialise(crypto.chacha20.crypt(PK, data.nonce, data.data)).timestamp
if os.epoch("utc") > timestamp then
fails = 0
local nonce = crypto.random.random(12)
rednet.send(sender, {
nonce = nonce,
data = crypto.chacha20
.crypt(PK, nonce, tostring(timestamp))
}, "encPingReply")
end
end
end
end
end
function exchange()
print("sending ping to " .. to)
rednet.send(tonumber(to), publicKey, "keyExClient")
sender, data = rednet.receive("keyEx", 1)
if sender ~= tonumber(to) then -- Switch to server
print("no response from " .. to .. ". listening for ping...")
isClient = false
while true do
sender, data = rednet.receive("keyExClient")
if sender == tonumber(to) then
print("ping from " .. sender .. ". sending and generating keys...")
rednet.send(tonumber(to), publicKey, "keyEx")
if knownHosts[tonumber(to)] == nil then
write("remote pubkey is " .. crypto.util.toHex(data) ..". Do you trust it? (Y/N)")
local trust = string.lower(read())
if trust == "y" then
knownHosts[tonumber(to)] = data
settings.set("knownhosts", knownHosts)
settings.save()
PK = crypto.x25519.exchange(privateKey, data)
else
error("Exiting...")
end
elseif knownHosts[tonumber(to)] ~= data then
error("==DANGER== Remote pubkey differs from previous interaction!")
else
PK = crypto.x25519.exchange(privateKey, data)
end
break
end
end
else
print("response from " .. to)
if knownHosts[tonumber(to)] == nil then
write("remote pubkey is " .. crypto.util.toHex(data) ..". Do you trust it? (Y/N)")
local trust = string.lower(read())
if trust == "y" then
knownHosts[tonumber(to)] = data
settings.set("knownhosts", knownHosts)
settings.save()
PK = crypto.x25519.exchange(privateKey, data)
else
error("Exiting...")
end
elseif knownHosts[tonumber(to)] ~= data then
error("==DANGER== Remote pubkey differs from previous interaction!")
else
PK = crypto.x25519.exchange(privateKey, data)
end
PK = crypto.x25519.exchange(privateKey, data)
end
term.clear()
term.setCursorPos(1,1)
print("==BEGIN ENCRYPTED CONVERSATION==")
end
exchange()
parallel.waitForAll(rx, tx, ping)

View file

@ -0,0 +1,4 @@
# SHA-512 hashed login system
This is a really simple setup to secure a computer in computercraft from them pesky fuckers in your server :P
Multi user support, but no separation of files or any file permissions at all for that matter. i.e if someone can log in, they can disable the login and change passwords, beware.

View file

@ -0,0 +1,28 @@
local username = arg[1] or _G.loggedInUser
local passwdData = settings.get("passwd")
if passwdData[username] == nil then
error("passwd: user '" .. username .. "' does not exist")
end
local crypto = require("ccryptolib")
crypto.random.initWithTiming()
print("Changing password for " .. username .. ".")
write("New password: ")
local pwd1 = crypto.sha512.digest(read(""))
write("Retype new password: ")
local pwd2 = crypto.sha512.digest(read(""))
if pwd1 ~= pwd2 then
error("Sorry, passwords do not match.")
end
if pwd1 == passwdData[username] then
error("The password has not been changed.")
end
passwdData[username] = crypto.util.toHex(pwd1)
settings.set("passwd", passwdData)
settings.save()
print("passwd: password updated successfully")

View file

@ -0,0 +1,46 @@
-- No term for you :)
Original_pullEvent = os.pullEvent
os.pullEvent = os.pullEventRaw
settings.set("shell.allow_disk_startup", false) -- Prevent disk startup bypass
-- Header stuff
local hostname = os.getComputerLabel() or "craftos"
term.clear()
term.setCursorPos(1,1)
write(_G._ENV._HOST .. " " .. hostname)
-- Load crypto library (slow, so we do it after everything else)
Crypto = require("ccryptolib")
Crypto.random.initWithTiming()
function checkCreds(username, hashed)
if Crypto.util.fromHex(settings.get("passwd")[username]) == hashed then
return true
else
return false
end
end
function login()
print()
write(hostname .. " login: ")
local username = read()
write("Password: ")
local passwordHash = Crypto.sha512.digest(read("")) -- Hash immidiately so password is not stored plaintext in memory
if checkCreds(username, passwordHash) then
print("Welcome ".. username)
_G.loggedInUser = username
else
print("Login incorrect")
login()
end
end
if not settings.get("passwd") then
print()
print("WARNING: passwd file does not exist, generating default login root:toor")
settings.set("passwd", { ["root"] = Crypto.util.toHex(Crypto.sha512.digest("toor")) })
settings.save()
end
login()

View file

@ -0,0 +1,28 @@
local username = arg[1]
local passwdData = settings.get("passwd")
if passwdData[username] then
error("useradd: user '" .. username .."' already exists")
end
local crypto = require("ccryptolib")
crypto.random.initWithTiming()
print("Changing password for " .. username .. ".")
write("New password: ")
local pwd1 = crypto.sha512.digest(read(""))
write("Retype new password: ")
local pwd2 = crypto.sha512.digest(read(""))
if pwd1 ~= pwd2 then
error("Sorry, passwords do not match.")
end
if pwd1 == passwdData[username] then
error("The password has not been changed.")
end
passwdData[username] = crypto.util.toHex(pwd1)
settings.set("passwd", passwdData)
settings.save()
print("useradd: password updated successfully")