254 lines
7.4 KiB
Lua
254 lines
7.4 KiB
Lua
--MSGER by rnd
|
||
--[[
|
||
INSTRUCTIONS:
|
||
|
||
1. set target player name bellow and encryption = true ( otherwise not encrypted)
|
||
2. start program and wait for session key or send one (hold W+S)
|
||
3. to send message just write: ,hello
|
||
|
||
--]]
|
||
|
||
if not init then
|
||
msgversion = "05042018a"
|
||
--- S E T T I N G S ---------------------------------------
|
||
target = "test" --write name of player you want to talk to
|
||
privatemsg = true -- false to chat, true for private msg
|
||
|
||
ack_timeout = 5; -- timeout after sending initial packet
|
||
state = 0; -- if sendkey: 0: sending key, 1: key receipt aknowledged, ready. if receieve key: 0: waiting for key, 1: ready
|
||
chatchar = "''" -- some servers end msg announce with :, some with %)
|
||
|
||
password = { -- ~30 bits per row, 10x ~ 300 bit, 2 consecutive passwords should be different!
|
||
1728096374,
|
||
1301007001,
|
||
1000050002,
|
||
1040053203,
|
||
1000000004,
|
||
1000600005,
|
||
1080156086,
|
||
1047302203,
|
||
1800100228,
|
||
1480500509,
|
||
}
|
||
|
||
password0 = {}; for i=1,#password do password0[i] = password[i] end
|
||
|
||
|
||
-- each password can be up to 10^10, plus random session key 4*10^13 for total 64*10^43 ~ 148.8 bits
|
||
-----------------------------------------------------------
|
||
|
||
init = true
|
||
say(minetest.colorize("lawngreen","#MESSENGER ".. msgversion .. " STARTED. Starting conversation with " .. target))
|
||
|
||
say(minetest.colorize("orange","wait for receipt of session key or hold W+S to send session key!"))
|
||
|
||
|
||
self.msg_filter(chatchar) -- only records messages that contain chatchar to prevent skipping if too many messages from server!
|
||
|
||
empty_chat_buffer = function()
|
||
local msg = ""; while msg do msg = self.listen_msg() end
|
||
end
|
||
empty_chat_buffer();
|
||
|
||
|
||
maxn = 1000000000;
|
||
|
||
rndm = 2^31 − 1; --C++11's minstd_rand
|
||
rnda = 48271; -- generator
|
||
random = function(n)
|
||
rndseed = (rnda*rndseed)% rndm;
|
||
return rndseed % n
|
||
end
|
||
|
||
rndseed = os.time(); session_key = random(maxn) -- derive session key
|
||
send_session_key = false
|
||
state = -1
|
||
|
||
scount = 0
|
||
wtime = 0
|
||
|
||
encrypt_ = function(input,password,sgn)
|
||
local n = 128-32+1; -- Z_97, 97 prime
|
||
local m = 32;
|
||
local ret = {};input = input or "";
|
||
rndseed = password;
|
||
local key = {};
|
||
local out = {};
|
||
for i=1, string.len(input) do
|
||
key[i] = random(n) -- generate keys from password
|
||
out[i] = string.byte(input,i)-m
|
||
if out[i] == -6 then out[i] = 96 end -- conversion back
|
||
end
|
||
|
||
if sgn > 0 then -- encrypt
|
||
|
||
for i=1, string.len(input) do
|
||
local offset=key[i]
|
||
local c = out[i];
|
||
|
||
local c0 = 0;
|
||
for j = 1,i-1 do c0 = c0 + (out[j])^3; c0 = c0 % n end
|
||
for j = i+1,string.len(input) do c0 = c0 + (out[j])^3; c0 = c0 % n end
|
||
|
||
c = (c+(c0+offset)*sgn) % n;
|
||
out[i] = c
|
||
end
|
||
else -- decrypt
|
||
local c0 = 0
|
||
for i = string.len(input),1,-1 do
|
||
local offset=key[i];
|
||
local c = out[i];
|
||
|
||
local c0 = 0;
|
||
for j = 1,i-1 do c0 = c0 + (out[j])^3; c0 = c0 % n end
|
||
for j = i+1,string.len(input) do c0 = c0 + (out[j])^3; c0 = c0 % n end
|
||
|
||
c = (c+(c0+offset)*sgn) % n;
|
||
out[i] = c
|
||
end
|
||
end
|
||
|
||
|
||
for i = 1, string.len(input) do
|
||
if out[i] == 96 then out[i]=-6 end -- 32 + 96 = 128 (bad char)
|
||
ret[#ret+1] = string.char(m+out[i])
|
||
end
|
||
|
||
return table.concat(ret,"")
|
||
end
|
||
|
||
|
||
encrypt = function(text,password)
|
||
local input = text;
|
||
local out = "";
|
||
for i = 1, #password do
|
||
input = encrypt_(input,password[i], (i%1)*2-1)
|
||
end
|
||
return input
|
||
end
|
||
|
||
decrypt = function(text, password)
|
||
local input = text;
|
||
local out = "";
|
||
for i = #password,1,-1 do
|
||
input = encrypt_(input,password[i], -(i%1)*2+1)
|
||
end
|
||
return input
|
||
end
|
||
|
||
|
||
unit_test = function()
|
||
local text = "Hello encrypted world! 12345 ..."
|
||
--local password = {1,2,session_key}
|
||
local enc = encrypt(text,password)
|
||
local dec = decrypt(enc,password)
|
||
say(text .. " -> " .. enc .. " -> " .. dec)
|
||
self.remove()
|
||
end
|
||
--unit_test()
|
||
end
|
||
|
||
|
||
if state == -1 then -- idle
|
||
msg = self.listen_msg()
|
||
if msg then
|
||
if string.find(msg,target) and string.find(msg,chatchar) then
|
||
msg = minetest.strip_colors(msg)
|
||
local i = string.find(msg, chatchar)
|
||
if i then -- ready to chat
|
||
msg = string.sub(msg,i+string.len(chatchar))
|
||
session_key = tonumber(decrypt(msg,password0))
|
||
if not session_key then
|
||
say(minetest.colorize("red","#MESSENGER: target uses wrong password! restarting...")) init = false
|
||
else
|
||
msg = encrypt("OK " .. session_key, password0)
|
||
say("/msg " .. target .. " " .. chatchar .. msg,true) -- send confirmation of receipt
|
||
msg = false
|
||
state = 1 scount = 1
|
||
say(minetest.colorize("lawngreen","#MESSENGER: RECEIVED SESSION KEY " .. session_key))
|
||
password[1] = session_key;password[#password] = password0[#password0] - session_key;
|
||
--say(password1 .. " " .. password2)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
if not msg and minetest.localplayer:get_key_pressed() == 3 then
|
||
say(minetest.colorize("red","SENDING SESSION KEY TO " .. target))
|
||
state = 0;
|
||
end
|
||
else -- receive/send
|
||
msg = self.listen_msg()
|
||
|
||
if state == 0 then
|
||
if minetest.localplayer:get_key_pressed() == 3 then scount = 0 wtime = 0 end
|
||
if scount == 0 then msg = "" end -- trigger sending key at start
|
||
|
||
wtime = wtime + 1
|
||
if wtime > ack_timeout then say(minetest.colorize("red","#MESSENGER: timeout while waiting for response from target. resetting")); init = false end
|
||
end
|
||
|
||
if msg then
|
||
if state == 0 then
|
||
|
||
-- SENDING KEY, listening for confirmation
|
||
if string.find(msg,target) and string.find(msg,chatchar) then -- did we receive confirmation?
|
||
msg = minetest.strip_colors(msg)
|
||
local i = string.find(msg, chatchar)
|
||
if i then
|
||
msg = string.sub(msg,i+string.len(chatchar))
|
||
msg = decrypt(msg,password0)
|
||
if msg == "OK " .. session_key then -- ready to chat
|
||
state = 1
|
||
say(minetest.colorize("lawngreen","#MESSENGER: TARGET CONFIRMS RECEIPT OF SESSION KEY " .. session_key))
|
||
password[1] = session_key;password[#password] = password0[#password0] - session_key;
|
||
--say(password1 .. " " .. password2)
|
||
end
|
||
end
|
||
elseif scount == 0 then -- send session key
|
||
scount = 1
|
||
msg = encrypt(session_key, password0)
|
||
say("/msg " .. target .. " " .. chatchar .. msg,true)
|
||
say(minetest.colorize("red","#MESSENGER: waiting for " .. target .. " to respond ..."))
|
||
wtime = 0
|
||
end
|
||
elseif state == 1 then -- NORMAL OPERATION: DECRYPT INCOMMING MESSAGES, SEND ENCRYPTED MESSAGES
|
||
if string.find(msg,target) and string.find(msg,chatchar) then
|
||
--say("D1")
|
||
msg = minetest.strip_colors(msg)
|
||
local i = string.find(msg, chatchar)
|
||
if i then
|
||
msg = string.sub(msg,i+string.len(chatchar))
|
||
--say("ENCRYPTED :" .. msg)
|
||
|
||
msg = decrypt(msg,password);
|
||
if string.byte(msg,1)~=32 then
|
||
say(minetest.colorize("red","#MESSENGER: DECRYPTION ERROR. TARGET USING DIFFERENT PASSWORD. RESTARTING MESSENGER."))
|
||
init = false
|
||
end
|
||
|
||
|
||
if string.sub(msg,2,2)=="$" then
|
||
form = "size[5,5] textarea[0,0;6,6;MSG;MESSAGE FROM " .. target .. ";" .. minetest.formspec_escape(msg) .. "]"
|
||
minetest.show_formspec("robot", form)
|
||
else
|
||
msg = minetest.colorize("LawnGreen","DECRYPTED from " .. target .. ">") .. minetest.colorize("yellow", msg)
|
||
say(msg)
|
||
end
|
||
end
|
||
end
|
||
|
||
end
|
||
end
|
||
end
|
||
|
||
msg = self.sent_msg() -- is there message to send?
|
||
if msg then
|
||
say(minetest.colorize("Pink", "MESSAGE SENT to " .. target .. "> " .. msg))
|
||
msg = encrypt(" " .. msg, password)
|
||
if privatemsg then
|
||
say("/msg " .. target .. " " .. chatchar .. msg,true)
|
||
else
|
||
say(chatchar .. msg,true)
|
||
end
|
||
end |