Add some silly examples
This commit is contained in:
parent
02a1d78578
commit
3901045eef
3
example/encrypted_chat/README.md
Normal file
3
example/encrypted_chat/README.md
Normal 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
|
205
example/encrypted_chat/encchat.lua
Normal file
205
example/encrypted_chat/encchat.lua
Normal 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)
|
4
example/secure_login/README.md
Normal file
4
example/secure_login/README.md
Normal 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.
|
28
example/secure_login/passwd.lua
Normal file
28
example/secure_login/passwd.lua
Normal 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")
|
46
example/secure_login/startup.lua
Normal file
46
example/secure_login/startup.lua
Normal 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()
|
28
example/secure_login/useradd.lua
Normal file
28
example/secure_login/useradd.lua
Normal 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")
|
Loading…
Reference in a new issue