1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
|
--MESSENGER with rnd auth and key exchange v2
-- 'public' key is exchanged securely (2048 bit diffie-hellman in safe-prime group). After that chat will be secure in future.
-- Every session key is randomized and securely exchanged with srp (secure remote password) like protocol.
if not init then
msgerver = "05172018b"
targetid = {id = "quater", name = "quater"} -- WRITE IN WHO you want to talk to - id = real identity & name = current playername
myid = {id = "rnd", name = minetest.localplayer:get_name()} -- your identity
-- targetid = {id = "rnd", name = "rnd"} -- real identity & playername
-- myid = {id = "qtest", name = minetest.localplayer:get_name()}
------------------------------------------------------
DEBUG = false;
-- SECRET KEYS: for yourself write in: private key, public key. for other player write {} in place of private key.
-- keys are also loaded from mod_storage.
keys = minetest.deserialize(self.mod_storage:get_string("messenger_keys")); if not keys then keys = {} end
-- keys = {
-- ["qtest"] ={ -- example key
-- {48956649,6888054,39208061,49336825,13139894,28782086,33649864,52015757,41052181,6366916,19073280,28595777,9004077,49422303,3197447,56119809,34730143,60487773,51346526,36586011},
-- {10668758,19566477,29269435,16175584,54357471,16537273,10758806,19610241,2888871,9931787,22143488,49139611,41680003,63337704,54062559,9659600,2850950,62931196,37706701,11112986}
-- },
-- }
keygen = 0; -- both players set this to 1 to generate keys, 0 normal operation
timeout = 5; -- unused (yet)
chatchar1 = "''";
chatchar0 = ": ";
self.msg_filter(targetid.name .. chatchar0 .. chatchar1) -- PM from name to name: @@xxxx
init = true
mode = 0;
state = 0;
step = 0;
welcomemsg = function()
if keygen == 1 then
say(minetest.colorize("red", "#MESSENGER v" .. msgerver .. ". hold w+s to generate and exchange private/public key or wait to receive one."))
say(minetest.colorize("orange", "key management menu: say ,1 to view existing keys ,2 to delete all keys ,0 for main menu."))
else
say(minetest.colorize("red", "#MESSENGER v" .. msgerver .. ". hold w+s to establish authenticated secure connection with ") .. minetest.colorize("yellow",targetid.id) .. minetest.colorize("red"," or wait to receive one."))
say(minetest.colorize("orange", "main menu: say,1 to enter key management (generate & send, view, remove keys)."))
end
end
welcomemsg()
crypto = _G.crypto; bignum = _G.bignum;
crypto.randomseed(os.time()) -- weak, TODO: use better random generator with better randomness source
-- generate safe prime in openssl: openssl prime -generate -safe -bits 512 -hex
-- then import it here
local importsshprime = function(GH, base)
local G1 = bignum.importhex(GH); local G2 = bignum.base2binary(G1);
local G3 = bignum.binary2base(G2,base);return minetest.serialize(G3.digits)
end
--GH = "";local code = importsshprime(GH,2^26)
--local form = "size[5,5] textarea[0,0;6,6;MSG;MESSAGE;" .. minetest.formspec_escape(code) .. "]"
--local t = os.clock();local barrett = bignum.get_barrett(p512);say(os.clock()-t) -- precompute barrett form
--local code = minetest.serialize(barrett)
--minetest.show_formspec("robot", form)
--512 bit
--c1d3a133c9b3720da868dda10b6a0bde0e1a47d797d3e02f2673157ad26c33970553352abd72114a48813b3f1a3d86120c2150d9c33780bf0ce31acf2e28b813
p512 = {
base = 2^26, sgn = 1,
digits = {36222995, 13022155, 782542, 57085150, 34349392, 42951044, 1291249, 4532514, 19578226, 29447373, 19317561, 30168555, 65023782, 32892404, 31515044, 2992175, 6872481, 14451562, 34815131, 198478}
}
barrett512 = {
["k"] = 42, ["m"] = {["base"] = 67108864, ["sgn"] = 1,
["digits"] = {28949715, 54423101, 2288892, 15960629, 25093079, 30961036, 9893219, 18572583, 6060506, 53345934, 62824245, 21175570, 51585074, 64634085, 50626132, 23908947, 34461644, 49242303, 44848557, 11882353, 4640537, 7818826, 338}}, ["n"] = {["base"] = 67108864, ["sgn"] = 1, ["digits"] = {36222995, 13022155, 782542, 57085150, 34349392, 42951044, 1291249, 4532514, 19578226, 29447373, 19317561, 30168555, 65023782, 32892404, 31515044, 2992175, 6872481, 14451562, 34815131, 198478}}
}
--2048 bit
--db726369acb4a51666ee14e0dc4305afc11692cc0dfa9d06b399ebc7b541b095ca3f48633ed936e0d4633af1c8b72886829c5fdd98861c44acdadc54075dc3beeb3d4a4bf9fb13b2c943e8bcb8c8df4440a84753c87d1512ff3db5083941ac88764c674da50771fdd7f4db99d7281e653253191df1f0137004b81488ecf9d15c49462c5438d4c060fa5a36e3e8e73ca1969d312b1b11df3e6fa3ce0a87641f4007884470d4911da45df914143c2c446a51443d6595c84cf83467825cf08007546e04c5137acac3ec0f413c522f5904d3b5230b4f5f2a26a0a8ad318ab541d1cd69079b0cb040827e2eb48f4fb7bc76623b96c7d38c603a186e24ae70a3bd66b3
p2048 = {
base = 2^26, sgn = 1,
digits = {62744243, 19635240, 60917474, 55456128, 37459655, 32447896, 55112955, 34207930, 51163200, 56246758, 55844124, 45401642, 36085928, 47437770, 20664880, 12411923, 54606930, 45153027, 5322668, 22132755, 15761415, 18473111, 8703875, 16094807, 6967620, 17763089, 31428929, 38041233, 4485332, 63963618, 11040321, 29265720, 51502910, 55331526, 63576425, 59745180, 16407094, 37040152, 6473027, 54882597, 8973561, 77317, 52363575, 21783671, 1991986, 48657866, 64847693, 43261383, 38561613, 7021085, 55608212, 4979958, 63470869, 2757076, 9303108, 61010659, 62048579, 50233028, 45339812, 24579835, 47993863, 51456822, 31033441, 34238847, 12003462, 13548658, 57544006, 26016612, 30031688, 22047781, 27180155, 41163470, 46927354, 66078116, 29634650, 62411651, 10819174, 14314285, 898854}
}
barrett2048 = {
["k"] = 160, ["m"] = {["base"] = 67108864, ["sgn"] = 1,
["digits"] = {52173231, 58926316, 7134135, 58005281, 29642925, 1996, 43704342, 19181367, 51834951, 40753938, 5670116, 25083444, 53681109, 39194353, 21018693, 16186348, 52641345, 34474171, 45582158, 65632598, 6663244, 17715531, 46582518, 715815, 35941432, 62741031, 14063905, 37500214, 33724930, 25815530, 29521098, 42349641, 30021354, 56331771, 20197595, 44642351, 39774, 15935544, 18538053, 54085894, 20262092, 170794, 877950, 7075184, 15922733, 42275553, 19627281, 61124663, 6351068, 20488035, 52369744, 26751026, 17905178, 25990200, 47243983, 42954366, 65859731, 23375626, 40610711, 9951837, 9139091, 55630155, 4911180, 17490059, 43409254, 37055369, 1417704, 12145177, 9055946, 41623298, 33230333, 1111792, 21966597, 20877280, 44498082, 6831928, 22418430, 4437100, 27282748, 12568457, 44322344, 74}}, ["n"] = {["base"] = 67108864, ["sgn"] = 1, ["digits"] = {62744243, 19635240, 60917474, 55456128, 37459655, 32447896, 55112955, 34207930, 51163200, 56246758, 55844124, 45401642, 36085928, 47437770, 20664880, 12411923, 54606930, 45153027, 5322668, 22132755, 15761415, 18473111, 8703875, 16094807, 6967620, 17763089, 31428929, 38041233, 4485332, 63963618, 11040321, 29265720, 51502910, 55331526, 63576425, 59745180, 16407094, 37040152, 6473027, 54882597, 8973561, 77317, 52363575, 21783671, 1991986, 48657866, 64847693, 43261383, 38561613, 7021085, 55608212, 4979958, 63470869, 2757076, 9303108, 61010659, 62048579, 50233028, 45339812, 24579835, 47993863, 51456822, 31033441, 34238847, 12003462, 13548658, 57544006, 26016612, 30031688, 22047781, 27180155, 41163470, 46927354, 66078116, 29634650, 62411651, 10819174, 14314285, 898854}}
}
password0 = {123456789}; -- cosmetics only
get_randomness = function() -- ~ 100 bits. TODO: improve and use this to create better random integers
say(os.clock() .. minetest.serialize(minetest.localplayer:get_pos()) .. minetest.serialize(minetest.camera:get_look_dir()))
end
--get_randomness()
local DH_2048_test = function()
local base = 2^26
-- order of element in Z_p* must divide |Z_p*|= p-1. since p is safe prime, p-1=2q for prime q. so either order is 2 or q.
local g = bignum.new(base, 1, {2}) -- order of this is obviously not 2, so its (p-1)/2
local m = 80; -- 80*26 = 2080 bit exponent
local b = bignum.rnd(base, 1, m)
local c = bignum.rnd(base, 1, m)
local t = os.clock();
local resb = bignum.modpow(g,b, barrett2048); -- g^b mod p2048
say("g^b time " .. os.clock()-t)
local resc = bignum.modpow(g,c, barrett2048); -- g^c mod p2048
say("g^c time " .. os.clock()-t)
local resbc = bignum.modpow(resb,c, barrett2048); -- g^bc mod p2048
say("g^bc time " .. os.clock()-t)
local rescb = bignum.modpow(resc,b, barrett2048); -- g^cb mod p2048
say("g^cb time " .. os.clock()-t)
if bignum.is_equal(resbc,rescb) then say("equality check g^bc = g^cb PASSED.") else say("equality check g^bc = g^cb FAILED.")end
say(os.clock()-t)
end
--DH_2048_test()
local rndexchange_test = function()
local base = 2^26;
local g = bignum.new(base, 1, {2})
local m = 20; -- 20*26 = 520 bits
local t = os.clock();
local x = bignum.rnd(base, 1, m) -- use better randomseeds for real one
local v = bignum.modpow(g,x,barrett512); -- 'public' key that A(client alice) and B(server) both know.
say("RND KEY EXCHANGE PROTOCOL v2")
say("0. PUBLIC KEY v = " .. bignum.tostring(v))
-- 1. B picks random r and tells A y=g^r+v.
local r = bignum.rnd(base,1,m); local gr = bignum.modpow(g,r,barrett512);
local y = bignum.new(base,1,{}); bignum._add(gr,v,y); -- send y to other party
say(" 1.1 B sends A: y = " .. bignum.tostring(v))
say("2. IF CONFIRM IDENTIY : A confirms identity by sending back hash((y-v)^x) = hash(v^r) = hash(g^rx) to prove to B he know x.")
local temp = bignum.new(base,1,{}); bignum._sub(y,v,temp);
local yvx = bignum.modpow(temp, x, barrett512)
say(" 2.1 A computes (y-v)^x = " .. bignum.tostring(yvx))
say(" hash = " .. crypto.rndhash(bignum.tostring(yvx),512))
--
local vr = bignum.modpow(v, r, barrett512)
say(" 2.2 B computes v^r = " .. bignum.tostring(vr))
say(" hash = " .. crypto.rndhash(bignum.tostring(vr),512))
if bignum.is_equal(vr,yvx) then say("equality check PASSED.") else say("equality check FAILED.") end
say("3. SESSION KEY K=g^rx = (y-v)^x = v^r = " .. crypto.rndhash(" " .. bignum.tostring(vr),256))
say("time " .. os.clock()-t)
end
--rndexchange_test()
empty_chat_buffer = function()
local msg = ""; while msg do msg = self.listen_msg() end
end
empty_chat_buffer()
self.listen_msg(); -- empty sent msg buffer
extract_digits = function(msg)
local digits = {}
for word in string.gmatch(msg, "([^']+)") do
local c = tonumber(word);
if not c then return nil end
digits[#digits+1] = c
end
return digits
end
--self.remove()
end
msg = self.listen_msg();
if msg then msg = minetest.strip_colors(msg) end;
if keygen == 1 then -- generating & exchanging 'public' key for one of the clients
-- state 0: mode 0: receive G^b in 2 parts (step 1,2), compute session key -> mode 1: send G^c in 2 parts (step 1,2)
-- -> mode 2: receive v = g^x -> keygen = 0, state = 0 (key computed, ready to proceed with chat operations)
if state == 0 then -- receiving (state 0, mode 0 = idle )
if mode == 0 then
if msg then
local i = string.find(msg,chatchar1);
local dec = crypto.decrypt(string.sub(msg,i+string.len(chatchar1)), password0);
if string.sub(dec,1,1) ~= " " then
say("ERROR receiving Gb. cant decrypt. resetting."); step = 0
else
step = step+1;
if step<=2 then
if not Gb then Gb = {} end --dec = " sxxxxx", s = step
local part = string.sub(dec,2,2);
if part~="1" and part~="2" then
say("ERROR receiving Gb.") step = 0; mode = 0;
else
Gb[tonumber(part)] = string.sub(dec,3)
end
else
say("ERROR receiving Gb. step " .. step .. ". aborting."); step =0; mode = 0;
end
if step == 2 then -- received 2 parts of Gb
step = 0
mode = 1 -- sending Gc
-- extract & compute session key TODO
local digits = {};
for i = 1,2 do
local edigits = extract_digits(Gb[i]);
if not edigits then
say("ERROR, RECEIVED CORRUPTED Gb. ABORTING."); step = 0;mode = 0; i=3; break;
else
for i = 1,#edigits do
digits[#digits+1] = edigits[i]
end
end
end
if mode == 1 then -- was receipt ok?
Gb = {sgn=1,base = 2^26, digits = digits};
local m = 80; local base = 2^26
c = bignum.rnd(base, 1, m)
local G = bignum.new(base, 1, {2})
Gc = bignum.modpow(G,c, barrett2048)
Gbc = bignum.modpow(Gb,c, barrett2048) -- session key
local Gc_ = Gc.digits;
local n = math.floor(#Gc_/2); -- break in 2 parts
send = {}; local ret = {}; -- send = string of digits to send
for i = 1, n do ret[i] = Gc_[i] end
send[1] = table.concat(ret,"'"); ret = {};
for i = n+1, #Gc_ do ret[i-n] = Gc_[i] end
send[2] = table.concat(ret,"'");
say("RECEIVED Gb and computed Gc, session key Gbc. Sending Gc ")
end
end
end
else
local keypressed = minetest.localplayer:get_key_pressed()
--say("KEY " .. keypressed)
if keypressed == 3 then
if keys[myid.id] then
say("WARNING! key for " .. myid.id .. " already exists. hold SHIFT+w+s send existing key. hold shift+a+d to create new key.")
else
say("GENERATING PUBLIC/PRIVATE KEY PAIR & ESTABLISHING SECURE 2048 bit CONNECTION...")
state = 1; mode = 0; step = 0 --> sending Gb
end
elseif keypressed == 67 then
say("GENERATING PUBLIC/PRIVATE KEY PAIR & ESTABLISHING SECURE 2048 bit CONNECTION...")
state = 1; mode = 0; step = 0 --> sending Gb
elseif keypressed == 76 then
say("GENERATING PUBLIC/PRIVATE KEY PAIR & ESTABLISHING SECURE 2048 bit CONNECTION...")
keys[myid.id] = nil
state = 1; mode = 0; step = 0 --> sending Gb
end
end
msg = self.sent_msg();
if msg then
if msg == "1" then
local ret = {}
for k,v in pairs(keys) do ret[#ret+1] = k .. ":\n private = {" .. table.concat(keys[k][1],",").."}\n public = {" .. table.concat(keys[k][2],",").."}".."\n" end
msg = table.concat(ret)
local form = "size[10.5,10] textarea[0,0;11,12;MSG;KEYS;" .. minetest.formspec_escape(msg) .. "]"
minetest.show_formspec("robot", form);
elseif msg == "2" then
keys = {};
self.mod_storage:set_string("messenger_keys", "return {}")
say("ALL KEYS DELETED!")
elseif msg == "0" then
keygen = 0; state = 0; step = 0; welcomemsg()
end
end
elseif mode == 1 then -- sending Gc
step = step + 1
say("/msg " .. targetid.name .. " " .. chatchar1 .. crypto.encrypt(" " .. step..send[step], password0),true)
if step == 2 then mode = 2 say("Gc sent. Waiting to receive v= g^x") end -- receive public key g^x
elseif mode == 2 then -- receiving v
if msg then
local i = string.find(msg,chatchar1);
local dec = crypto.decrypt(string.sub(msg,i+string.len(chatchar1)), Gbc.digits);
if string.sub(dec,1,1) ~= " " then
say("ERROR receiving public key v = g^x. cant decrypt. ABORTING."); state = 0; mode = 0;
else
local digits = {};
local edigits = extract_digits(string.sub(dec,2));
if not edigits then
say("ERROR, RECEIVED CORRUPTED v");
else
msg = "public key = {"..table.concat(edigits,",").."}";
local form = "size[5,5] textarea[0,0;6,6;MSG;PUBLIC KEY FROM " .. targetid.name .. ";" .. minetest.formspec_escape(msg) .. "]"
minetest.show_formspec("robot", form);
keys[targetid.id] = {{},edigits}; -- store key
self.mod_storage:set_string("messenger_keys", minetest.serialize(keys)) -- save keys in mod_storage
say(minetest.colorize("orange","PUBLIC KEY FOR " .. targetid.id .. " RECEIVED AND SAVED. RESTART .b 1"))
send = nil; Gbc = nil; c = nil; Gb = nil; Gc = nil; --cleanup
self.remove()
end
end
end
end
-- state 1: mode 0: send G^b in 2 steps (step 1,2)-> mode 1: wait for G^c in 2 steps (step 1,2)->
-- compute session key and send encrypted public key v = g^x -> display public and private key, state = 0, keygen = 0
elseif state == 1 then -- sending
if mode == 0 then
step = step + 1
if step == 1 then
local m = 80; local base = 2^26
b = bignum.rnd(base, 1, m)
local G = bignum.new(base, 1, {2})
Gb = bignum.modpow(G,b, barrett2048)
local Gb_ = Gb.digits;
local n = math.floor(#Gb_/2); -- break in 2 parts
send = {}; local ret = {}; -- send = string of digits to send
for i = 1, n do ret[i] = Gb_[i] end
send[1] = table.concat(ret,"'"); ret = {};
for i = n+1, #Gb_ do ret[i-n] = Gb_[i] end
send[2] = table.concat(ret,"'");
say("Sending Gb ")
say("/msg " .. targetid.name .. " " .. chatchar1 .. crypto.encrypt(" " .. step..send[step], password0),true)
elseif step <= 2 then
say("/msg " .. targetid.name .. " " .. chatchar1 .. crypto.encrypt(" " .. step..send[step], password0),true)
if step == 2 then mode = 1;step = 0 say("waiting for Gc") end-- wait for Gc
end
elseif mode == 1 then
if msg then
local i = string.find(msg,chatchar1);
local dec = crypto.decrypt(string.sub(msg,i+string.len(chatchar1)), password0);
if string.sub(dec,1,1) ~= " " then
say("ERROR receiving G^c. cant decrypt. ABORTING."); state = 0; mode = 0;
else
step = step + 1
if not Gc then Gc = {} end -- dec = " sxxxxx", s = step
local part = string.sub(dec,2,2);
if part~="1" and part~="2" then say("ERROR, RECEIVED CORRUPTED Gc. ABORTING."); step = 0;mode = 0;
else
Gc[tonumber(part)] = string.sub(dec,3)
end
if step == 2 then
local digits = {};
for i = 1,2 do
local edigits = extract_digits(Gc[i]);
if not edigits then
say("ERROR, RECEIVED CORRUPTED Gc. ABORTING."); step = 0;mode = 0; i=3; break;
else
for i = 1,#edigits do
digits[#digits+1] = edigits[i]
end
end
end
Gc = {sgn=1,base = 2^26, digits = digits};
local m = 80; local base = 2^26
local G = bignum.new(base, 1, {2})
local Gcb = bignum.modpow(Gc,b, barrett2048) -- session key
if not keys[myid.id] then
-- compute v = g^x and send it
x = bignum.rnd(base, 1, m/4) -- private key: m=20, 520 bit!
local G = bignum.new(base, 1, {2})
v = bignum.modpow(G,x, barrett512) -- public key v = g^x
else -- take existing key
x = bignum.new(base, 1, keys[myid.id][1])
v = bignum.new(base, 1, keys[myid.id][2])
end
-- password is Gcb.digits - 2048 bit
say("/msg " .. targetid.name .. " " .. chatchar1 .. crypto.encrypt(" " .. table.concat(v.digits,"'"), Gcb.digits),true)
keygen = 0; mode = 0; state = 0 -- normal chat operation
-- display keys so they can be written down
msg = "private x = {"..table.concat(x.digits,",").."}\n public v = {" .. table.concat(v.digits,",").."}";
if not keys[myid.id] then
keys[myid.id] = {x.digits,v.digits}; -- store key
self.mod_storage:set_string("messenger_keys", minetest.serialize(keys)) -- save keys in mod_storage
end
local form = "size[5,5] textarea[0,0;6,6;MSG;PRIVATE/PUBLIC KEY;" .. minetest.formspec_escape(msg) .. "]"
send = nil; Gc = nil; Gcb = nil; x = nil; v = nil; b = nil; Gb = nil; --cleanup
minetest.show_formspec("robot", form);
self.remove()
end
end
end
end
end
else -- END OF KEYGEN & DH KEY EXCHANGE
-- 1. B picks random r and tells A y=g^r+v.
-- Note here that listeners only see g^r+v so they have no clue what v is or what g^r is. Even from multiple sessions they
-- learn nothing if g is generator of whole group and r truly random, since then g^r can be 'anything' with same probability.
-- 2. OPTIONAL: A confirms identity by sending back hash(g^rx) = hash(v^r) = hash((y-v)^x) to prove you know a.
-- 3. session key is then K=g^rx = (g^r)^x = (g^x)^r.
if state == 0 then -- idle
if mode == 0 then
if msg then -- received y
local i = string.find(msg,chatchar1);
msg = string.sub(msg,i+string.len(chatchar1));
msg = crypto.decrypt(msg, password0)
if string.sub(msg,1,1) == " " then
local base = 2^26;
local y = bignum.new(base,1,extract_digits(msg));
local key = keys[myid.id];
if not key or not key[2] or not key[1] then say("ERROR: you need to add private/public key for " .. myid.id ..". both player should enter ,1 (key management) and let " .. myid.id .. " hold w+s to (generate) and send you his public key."); self.remove() end
local x = bignum.new(base,1,key[1]);
local v = bignum.new(base,1,key[2]);
local yv = bignum.new(base,1,{});bignum._sub(y,v,yv); -- yv = y-v
local t = os.clock()
sessionkey = bignum.modpow(yv,x, barrett512).digits -- yv^x
if DEBUG then say("time " .. os.clock()-t) end
--say("DEBUG SESSION KEY " .. minetest.serialize(sessionkey))
say(minetest.colorize("yellow", "MESSENGER " .. msgerver .. " READY."))
--local response = crypto.rndhash(table.concat(sessionkey,"'"),512) -- OPTIONAL
state = 1;
else
say("ERROR: wrong init packet. resetting. ")
init = false
end
elseif minetest.localplayer:get_key_pressed() == 3 then
say(minetest.colorize("red","GENERATING challenge and sending it to " .. targetid.name))
local key = keys[targetid.id];
if not key or not key[2] then say("ERROR: you need to add private/public key for " .. targetid.id ..". both player should enter ,1 (key management) and let " .. targetid.id .. " hold w+s to (generate) and send you his public key."); self.remove() end
local base = 2^26; local m = 20;
local v = bignum.new(base,1,key[2]);
local r = bignum.rnd(base, 1, m)
local g = bignum.new(base, 1, {2})
local t = os.clock()
local gr = bignum.modpow(g,r, barrett512)
if DEBUG then say("time " .. os.clock()-t) end
local y = bignum.new(base,1,{});
bignum._add(gr,v,y) -- y = g^r+v
say("/msg " .. targetid.name .. " " .. chatchar1.. crypto.encrypt(" " .. table.concat(y.digits,"'"),password0),true) -- send challenge
sessionkey = bignum.modpow(v,r, barrett512).digits; -- v^r
say(minetest.colorize("yellow", "MESSENGER " .. msgerver .. " READY."))
--say("DEBUG SESSION KEY " .. minetest.serialize(sessionkey))
--response = crypto.rndhash(table.concat(sessionkey,"'"),512) -- OPTIONAL
state = 1; -- normal operation
end
msg = self.sent_msg();
if msg and msg == "1" then
keygen = 1; welcomemsg()
end
end
elseif state == 1 then
if msg then -- received message + decrypt it
local i = string.find(msg,chatchar1);
msg = string.sub(msg,i+string.len(chatchar1));
local dec = crypto.decrypt(msg, sessionkey);
if string.sub(dec,1,1)~=" " then
say(minetest.colorize("red", "WARNING: " .. targetid.name .. " is using different session key! Resetting." ))
-- reset target messenger by sending random garbage
minetest.after(crypto.random(3),
function() say("/msg " .. targetid.name .. " " .. chatchar1 .. crypto.rndhash(" " .. crypto.random(2^30)),true) end)
init = false;
else
say(minetest.colorize("lawngreen", "[" .. targetid.id .. "]" .. dec ))
end
end
msg = self.sent_msg(); -- sending encrypted message
if msg then
say(minetest.colorize("orange", "[" .. myid.id .. "] " .. msg ))
local length = string.len(msg); if length < 32 then msg = msg .. string.rep(" ",32-length) end
local t = os.clock()
say("/msg " .. targetid.name .. " " .. chatchar1 .. crypto.encrypt(" " .. msg,sessionkey),true)
if DEBUG then say("time " .. os.clock()-t) end
end
end
end
|