File: rndkeyexchange.lua

package info (click to toggle)
minetest-mod-basic-robot-csm 0.0~git20190703.e082c6a-2
  • links: PTS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 268 kB
  • sloc: makefile: 2
file content (140 lines) | stat: -rw-r--r-- 9,930 bytes parent folder | download
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
-- rnd key exchange v2 (improved key hide when doing verification)
-- v05152018

if not crypto then
	
	crypto = _G.crypto; bignum = _G.bignum;

	-- 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 = {198478,34815131,14451562,6872481,2992175,31515044,32892404,65023782,30168555,19317561,29447373,19578226,4532514,1291249,42951044,34349392,57085150,782542,13022155,36222995}
		}
		
	barrett512 = {
		["k"] = 42, ["m"] = {["base"] = 67108864, ["sgn"] = 1, 
		["digits"] = {35898149, 41794076, 18684097, 46016930, 38889135, 63030343, 34383953, 50385002, 5837211, 26975470, 58748693, 26637596, 30851364, 25453708, 59604851, 52048498, 48309457, 2932823, 30408552, 42076151, 59509517, 57220987, 1}}, ["n"] = {["base"] = 67108864, ["sgn"] = 1, ["digits"] = {198478, 34815131, 14451562, 6872481, 2992175, 31515044, 32892404, 65023782, 30168555, 19317561, 29447373, 19578226, 4532514, 1291249, 42951044, 34349392, 57085150, 782542, 13022155, 36222995}}
		}

	--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"] = 2^26, ["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
	
	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()
	
	self.remove()
end

-- auth + key exchange in one idea: A alice (client), B bob (server)
-- key generation: A generates its shared secret as v = g^x for secret random x and exchanges it with B. 
-- this initial exchange can use DH with very large group to prevent any snooping.

-- verification: 
-- 		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. A confirms identity by sending back hash(g^rx) = hash(v^r) = hash((y-v)^x) to prove you know a. 
-- 		3. shared secret is then another hash of K=g^rx = (g^r)^x =  (g^x)^r.

--
-- basic idea is this: i tell you y=g^r for random r, you need to tell me y^x, so i believe you know x. But hide y by adding v and with hash so
-- listeners dont get any clues.

--observations: 
-- 0. note that K lies in potentially smaller group generated by g^x, srp 6a is better here since for srp K = g^(b(a + ux)).
-- 		where a,b are random
-- 		The order of Z_p* is 2q for prime q, where p-1 = 2q ( p safe prime ). Order of g^x is either 2  or q or 2q (if (g^x)^2~= 1 then its not 2)
-- 		So order of g^x is still (p-1)/2 in this case.
-- thm: if G is finite group then order of any element divides |G|. Furthermore, if p is prime dividing |G| there exists element
-- in G of order p (cauchy thm)

-- 1. Suppose there is observer C. first time of interaction he can see v=g^x sent from  A to B, but getting x is not possible ( log problem )
-- 2. later C can see B send v+g^r, and if he doesnt know v already this does not reveal it to him.. If we encrypt this this might introduce
-- 		weakness if not properly done, cause only good password would encrypt to number, bad password would be random mess.

-- WEAKNESS: if C knows v ...?
-- idea: first time exchange uses larger DH group for more safety to exchange: v = g^x to prevent C from learning x.

--srp v6a : http://srp.stanford.edu/design.html
--NOTE: srp v1 http://srp.stanford.edu/design1.html used weak approach to compute secret: S = (Wp*Xp)^Ys, where Xp = could be leaked 
-- pass. verifier, Wp = controlled by client, Ys = random server secret
-- if rogue client know Xp he could select Wp so that Wp*Xp becomes value of his choice, hence controlling what the final shared secret
-- will be.
-- rnd key exchange v2 does not have that weakness. even if rogue learns v = g^x by other means he still needs to solve log problem for x.