Skip to content

Commit b618ec3

Browse files
authored
Merge pull request #29 from GabrielTofvesson/master
Added Diffie Hellman
2 parents 0593de4 + 944def3 commit b618ec3

File tree

4 files changed

+303
-0
lines changed

4 files changed

+303
-0
lines changed

MLAPI/MLAPI.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
4545
</PropertyGroup>
4646
<ItemGroup>
47+
<Reference Include="IntXLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1744b76c74eaee1e, processorArchitecture=MSIL">
48+
<HintPath>..\packages\IntX.1.0.1.0\lib\net20\IntXLib.dll</HintPath>
49+
</Reference>
4750
<Reference Include="System" />
4851
<Reference Include="System.Core" />
4952
<Reference Include="System.Xml.Linq" />
@@ -79,5 +82,8 @@
7982
<Compile Include="Data\ClientIdKey.cs" />
8083
<Compile Include="NetworkingManagerComponents\MessageChunker.cs" />
8184
</ItemGroup>
85+
<ItemGroup>
86+
<None Include="packages.config" />
87+
</ItemGroup>
8288
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
8389
</Project>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using System;
2+
using IntXLib;
3+
using System.Text;
4+
using System.Security.Cryptography;
5+
6+
namespace ECDH
7+
{
8+
public class EllipticDiffieHellman
9+
{
10+
protected static readonly RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();
11+
public static readonly IntX DEFAULT_PRIME = (new IntX(1) << 255) - 19;
12+
public static readonly IntX DEFAULT_ORDER = (new IntX(1) << 252) + IntX.Parse("27742317777372353535851937790883648493");
13+
public static readonly EllipticCurve DEFAULT_CURVE = new EllipticCurve(486662, 1, DEFAULT_PRIME, EllipticCurve.CurveType.Montgomery);
14+
public static readonly CurvePoint DEFAULT_GENERATOR = new CurvePoint(9, IntX.Parse("14781619447589544791020593568409986887264606134616475288964881837755586237401"));
15+
16+
protected readonly EllipticCurve curve;
17+
public readonly IntX priv;
18+
protected readonly CurvePoint generator, pub;
19+
20+
21+
public EllipticDiffieHellman(EllipticCurve curve, CurvePoint generator, IntX order, byte[] priv = null)
22+
{
23+
this.curve = curve;
24+
this.generator = generator;
25+
26+
// Generate private key
27+
if (priv == null)
28+
{
29+
byte[] max = order.ToArray();
30+
do
31+
{
32+
byte[] p1 = new byte[5 /*rand.Next(max.Length) + 1*/];
33+
34+
rand.GetBytes(p1);
35+
36+
if (p1.Length == max.Length) p1[p1.Length - 1] %= max[max.Length - 1];
37+
else p1[p1.Length - 1] &= 127;
38+
39+
this.priv = DHHelper.FromArray(p1);
40+
} while (this.priv<2);
41+
}
42+
else this.priv = DHHelper.FromArray(priv);
43+
44+
// Generate public key
45+
pub = curve.Multiply(generator, this.priv);
46+
}
47+
48+
public byte[] GetPublicKey()
49+
{
50+
byte[] p1 = pub.X.ToArray();
51+
byte[] p2 = pub.Y.ToArray();
52+
53+
byte[] ser = new byte[4 + p1.Length + p2.Length];
54+
ser[0] = (byte)(p1.Length & 255);
55+
ser[1] = (byte)((p1.Length >> 8) & 255);
56+
ser[2] = (byte)((p1.Length >> 16) & 255);
57+
ser[3] = (byte)((p1.Length >> 24) & 255);
58+
Array.Copy(p1, 0, ser, 4, p1.Length);
59+
Array.Copy(p2, 0, ser, 4 + p1.Length, p2.Length);
60+
61+
return ser;
62+
}
63+
64+
public byte[] GetPrivateKey() => priv.ToArray();
65+
66+
public byte[] GetSharedSecret(byte[] pK)
67+
{
68+
byte[] p1 = new byte[pK[0] | (pK[1]<<8) | (pK[2]<<16) | (pK[3]<<24)]; // Reconstruct x-axis size
69+
byte[] p2 = new byte[pK.Length - p1.Length - 4];
70+
Array.Copy(pK, 4, p1, 0, p1.Length);
71+
Array.Copy(pK, 4 + p1.Length, p2, 0, p2.Length);
72+
73+
CurvePoint remotePublic = new CurvePoint(DHHelper.FromArray(p1), DHHelper.FromArray(p2));
74+
75+
byte[] secret = curve.Multiply(remotePublic, priv).X.ToArray(); // Use the x-coordinate as the shared secret
76+
77+
// PBKDF2-HMAC-SHA1 (Common shared secret generation method)
78+
return new Rfc2898DeriveBytes(secret, Encoding.UTF8.GetBytes("P1sN0R4inb0wPl5P1sPls"), 1000).GetBytes(32);
79+
}
80+
}
81+
82+
public static class DHHelper
83+
{
84+
public static byte[] ToArray(this IntX v)
85+
{
86+
v.GetInternalState(out uint[] digits, out bool negative);
87+
byte[] b = DigitConverter.ToBytes(digits);
88+
byte[] b1 = new byte[b.Length];
89+
Array.Copy(b, b1, b.Length);
90+
b1[b.Length] = (byte)(negative ? 1 : 0);
91+
return b1;
92+
}
93+
public static IntX FromArray(byte[] b)
94+
{
95+
if (b.Length == 0) return new IntX();
96+
byte[] b1 = new byte[b.Length - 1];
97+
Array.Copy(b, b1, b1.Length);
98+
uint[] u = DigitConverter.FromBytes(b1);
99+
return new IntX(u, b[b.Length - 1]==1);
100+
}
101+
public static bool BitAt(this uint[] data, long index) => (data[index/8]&(1<<(int)(index%8)))!=0;
102+
public static IntX Abs(this IntX i) => i < 0 ? -i : i;
103+
}
104+
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using IntXLib;
4+
5+
namespace ECDH
6+
{
7+
public class CurvePoint
8+
{
9+
public static readonly CurvePoint POINT_AT_INFINITY = new CurvePoint();
10+
public IntX X { get; private set; }
11+
public IntX Y { get; private set; }
12+
private bool pai = false;
13+
public CurvePoint(IntX x, IntX y)
14+
{
15+
X = x;
16+
Y = y;
17+
}
18+
private CurvePoint() { pai = true; } // Accessing corrdinates causes undocumented behaviour
19+
public override string ToString()
20+
{
21+
return pai ? "(POINT_AT_INFINITY)" : "(" + X + ", " + Y + ")";
22+
}
23+
}
24+
25+
public class EllipticCurve
26+
{
27+
public enum CurveType { Weierstrass, Montgomery }
28+
29+
protected readonly IntX a, b, modulo;
30+
protected readonly CurveType type;
31+
32+
public EllipticCurve(IntX a, IntX b, IntX modulo, CurveType type = CurveType.Weierstrass)
33+
{
34+
if (
35+
(type==CurveType.Weierstrass && (4 * a * a * a) + (27 * b * b) == 0) || // Unfavourable Weierstrass curves
36+
(type==CurveType.Montgomery && b * (a * a - 4)==0) // Unfavourable Montgomery curves
37+
) throw new Exception("Unfavourable curve");
38+
this.a = a;
39+
this.b = b;
40+
this.modulo = modulo;
41+
this.type = type;
42+
}
43+
44+
public CurvePoint Add(CurvePoint p1, CurvePoint p2)
45+
{
46+
#if SAFE_MATH
47+
CheckOnCurve(p1);
48+
CheckOnCurve(p2);
49+
#endif
50+
51+
// Special cases
52+
if (p1 == CurvePoint.POINT_AT_INFINITY && p2 == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY;
53+
else if (p1 == CurvePoint.POINT_AT_INFINITY) return p2;
54+
else if (p2 == CurvePoint.POINT_AT_INFINITY) return p1;
55+
else if (p1.X == p2.X && p1.Y == Inverse(p2).Y) return CurvePoint.POINT_AT_INFINITY;
56+
57+
IntX x3 = 0, y3 = 0;
58+
if (type == CurveType.Weierstrass)
59+
{
60+
IntX slope = p1.X == p2.X && p1.Y == p2.Y ? Mod((3 * p1.X * p1.X + a) * MulInverse(2 * p1.Y)) : Mod(Mod(p2.Y - p1.Y) * MulInverse(p2.X - p1.X));
61+
x3 = Mod((slope * slope) - p1.X - p2.X);
62+
y3 = Mod(-((slope * x3) + p1.Y - (slope * p1.X)));
63+
}
64+
else if (type == CurveType.Montgomery)
65+
{
66+
if ((p1.X == p2.X && p1.Y == p2.Y))
67+
{
68+
IntX q = 3 * p1.X;
69+
IntX w = q * p1.X;
70+
71+
IntX e = 2 * a;
72+
IntX r = e * p1.X;
73+
74+
IntX t = 2 * b;
75+
IntX y = t * p1.Y;
76+
77+
IntX u = MulInverse(y);
78+
79+
IntX o = w + e + 1;
80+
IntX p = o * u;
81+
}
82+
IntX co = p1.X == p2.X && p1.Y == p2.Y ? Mod((3 * p1.X * p1.X + 2 * a * p1.X + 1) * MulInverse(2 * b * p1.Y)) : Mod(Mod(p2.Y - p1.Y) * MulInverse(p2.X - p1.X)); // Compute a commonly used coefficient
83+
x3 = Mod(b * co * co - a - p1.X - p2.X);
84+
y3 = Mod(((2 * p1.X + p2.X + a) * co) - (b * co * co * co) - p1.Y);
85+
}
86+
87+
return new CurvePoint(x3, y3);
88+
}
89+
90+
public CurvePoint Multiply(CurvePoint p, IntX scalar)
91+
{
92+
if (scalar <= 0) throw new Exception("Cannot multiply by a scalar which is <= 0");
93+
if (p == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY;
94+
95+
CurvePoint p1 = new CurvePoint(p.X, p.Y);
96+
scalar.GetInternalState(out uint[] u, out bool b);
97+
long high_bit = -1;
98+
for (int i = u.Length - 1; i>=0; --i)
99+
if (u[i] != 0)
100+
{
101+
for(int j = 31; j>=0; --j)
102+
if ((u[i] & (1<<j))!=0)
103+
{
104+
high_bit = j + i * 32;
105+
goto Next;
106+
}
107+
}
108+
Next:
109+
110+
// Double-and-add method
111+
while(high_bit >= 0)
112+
{
113+
p1 = Add(p1, p1); // Double
114+
if ((u.BitAt(high_bit)))
115+
p1 = Add(p1, p); // Add
116+
--high_bit;
117+
}
118+
119+
return p1;
120+
}
121+
122+
protected IntX MulInverse(IntX eq) => MulInverse(eq, modulo);
123+
public static IntX MulInverse(IntX eq, IntX modulo)
124+
{
125+
eq = Mod(eq, modulo);
126+
Stack<IntX> collect = new Stack<IntX>();
127+
IntX v = modulo; // Copy modulo
128+
IntX m;
129+
while((m = v % eq) != 0)
130+
{
131+
collect.Push(-v/eq/*-(m.l_div)*/);
132+
v = eq;
133+
eq = m;
134+
}
135+
if (collect.Count == 0) return 1;
136+
v = 1;
137+
m = collect.Pop();
138+
while (collect.Count > 0)
139+
{
140+
eq = m;
141+
m = v + (m * collect.Pop());
142+
v = eq;
143+
}
144+
return Mod(m, modulo);
145+
}
146+
147+
public CurvePoint Inverse(CurvePoint p) => Inverse(p, modulo);
148+
protected static CurvePoint Inverse(CurvePoint p, IntX modulo) => new CurvePoint(p.X, Mod(-p.Y, modulo));
149+
150+
public bool IsOnCurve(CurvePoint p)
151+
{
152+
try { CheckOnCurve(p); }
153+
catch { return false; }
154+
return true;
155+
}
156+
protected void CheckOnCurve(CurvePoint p)
157+
{
158+
if (
159+
p!=CurvePoint.POINT_AT_INFINITY && // The point at infinity is asserted to be on the curve
160+
(type == CurveType.Weierstrass && Mod(p.Y * p.Y) != Mod((p.X * p.X * p.X) + (p.X * a) + b)) || // Weierstrass formula
161+
(type == CurveType.Montgomery && Mod(b * p.Y * p.Y) != Mod((p.X * p.X * p.X) + (p.X * p.X * a) + p.X)) // Montgomery formula
162+
) throw new Exception("Point is not on curve");
163+
}
164+
165+
protected IntX Mod(IntX b) => Mod(b, modulo);
166+
167+
private static IntX Mod(IntX x, IntX m)
168+
{
169+
IntX r = x.Abs() > m ? x % m : x;
170+
return r < 0 ? r + m : r;
171+
}
172+
173+
protected static IntX ModPow(IntX x, IntX power, IntX prime)
174+
{
175+
IntX result = 1;
176+
bool setBit = false;
177+
while(power > 0)
178+
{
179+
x %= prime;
180+
setBit = (power & 1) == 1;
181+
power >>= 1;
182+
if (setBit) result *= x;
183+
x *= x;
184+
}
185+
186+
return result;
187+
}
188+
}
189+
}

MLAPI/packages.config

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="IntX" version="1.0.1.0" targetFramework="net35" />
4+
</packages>

0 commit comments

Comments
 (0)