Skip to content

Commit 1184eca

Browse files
GabrielTofvessonTwoTenPvP
authored andcommitted
Removed custom PBKDF2 implementation
Switched to cryptographically safe random provider
1 parent 2a26b24 commit 1184eca

File tree

2 files changed

+32
-191
lines changed

2 files changed

+32
-191
lines changed

MLAPI/NetworkingManagerComponents/DiffieHellman.cs

Lines changed: 14 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
using System;
22
using IntXLib;
33
using System.Text;
4+
using System.Security.Cryptography;
45

56
namespace ECDH
67
{
78
public class EllipticDiffieHellman
89
{
9-
protected static readonly Random rand = new Random();
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"));
1015

1116
protected readonly EllipticCurve curve;
1217
public readonly IntX priv;
13-
protected readonly Point generator, pub;
18+
protected readonly CurvePoint generator, pub;
1419

1520

16-
public EllipticDiffieHellman(EllipticCurve curve, Point generator, IntX order, byte[] priv = null)
21+
public EllipticDiffieHellman(EllipticCurve curve, CurvePoint generator, IntX order, byte[] priv = null)
1722
{
1823
this.curve = curve;
1924
this.generator = generator;
@@ -26,15 +31,15 @@ public EllipticDiffieHellman(EllipticCurve curve, Point generator, IntX order, b
2631
{
2732
byte[] p1 = new byte[5 /*rand.Next(max.Length) + 1*/];
2833

29-
rand.NextBytes(p1);
34+
rand.GetBytes(p1);
3035

3136
if (p1.Length == max.Length) p1[p1.Length - 1] %= max[max.Length - 1];
3237
else p1[p1.Length - 1] &= 127;
3338

34-
this.priv = Helper.FromArray(p1);
39+
this.priv = DHHelper.FromArray(p1);
3540
} while (this.priv<2);
3641
}
37-
else this.priv = Helper.FromArray(priv);
42+
else this.priv = DHHelper.FromArray(priv);
3843

3944
// Generate public key
4045
pub = curve.Multiply(generator, this.priv);
@@ -65,180 +70,16 @@ public byte[] GetSharedSecret(byte[] pK)
6570
Array.Copy(pK, 4, p1, 0, p1.Length);
6671
Array.Copy(pK, 4 + p1.Length, p2, 0, p2.Length);
6772

68-
Point remotePublic = new Point(Helper.FromArray(p1), Helper.FromArray(p2));
73+
CurvePoint remotePublic = new CurvePoint(DHHelper.FromArray(p1), DHHelper.FromArray(p2));
6974

7075
byte[] secret = curve.Multiply(remotePublic, priv).X.ToArray(); // Use the x-coordinate as the shared secret
7176

7277
// PBKDF2-HMAC-SHA1 (Common shared secret generation method)
73-
return PBKDF2(HMAC_SHA1, secret, Encoding.UTF8.GetBytes("P1sN0R4inb0wPl5P1sPls"), 1024, 32);
74-
}
75-
76-
77-
public delegate byte[] PRF(byte[] key, byte[] salt);
78-
private static byte[] PBKDF2(PRF function, byte[] password, byte[] salt, int iterations, int dklen)
79-
{
80-
byte[] dk = new byte[0]; // Create a placeholder for the derived key
81-
uint iter = 1; // Track the iterations
82-
while (dk.Length < dklen)
83-
{
84-
// F-function
85-
// The F-function (PRF) takes the amount of iterations performed in the opposite endianness format from what C# uses, so we have to swap the endianness
86-
byte[] u = function(password, Concatenate(salt, WriteToArray(new byte[4], SwapEndian(iter), 0)));
87-
byte[] ures = new byte[u.Length];
88-
Array.Copy(u, ures, u.Length);
89-
for (int i = 1; i < iterations; ++i)
90-
{
91-
// Iteratively apply the PRF
92-
u = function(password, u);
93-
for (int j = 0; j < u.Length; ++j) ures[j] ^= u[j];
94-
}
95-
96-
// Concatenate the result to the dk
97-
dk = Concatenate(dk, ures);
98-
99-
++iter;
100-
}
101-
102-
// Clip all bytes past what we needed (yes, that's really what the standard is)
103-
if (dk.Length != dklen)
104-
{
105-
var t1 = new byte[dklen];
106-
Array.Copy(dk, t1, Math.Min(dklen, dk.Length));
107-
return t1;
108-
}
109-
return dk;
110-
}
111-
public delegate byte[] HashFunction(byte[] message);
112-
private static byte[] HMAC(byte[] key, byte[] message, HashFunction func, int blockSizeBytes)
113-
{
114-
if (key.Length > blockSizeBytes) key = func(key);
115-
else if (key.Length < blockSizeBytes)
116-
{
117-
byte[] b = new byte[blockSizeBytes];
118-
Array.Copy(key, b, key.Length);
119-
key = b;
120-
}
121-
122-
byte[] o_key_pad = new byte[blockSizeBytes]; // Outer padding
123-
byte[] i_key_pad = new byte[blockSizeBytes]; // Inner padding
124-
for (int i = 0; i < blockSizeBytes; ++i)
125-
{
126-
// Combine padding with key
127-
o_key_pad[i] = (byte)(key[i] ^ 0x5c);
128-
i_key_pad[i] = (byte)(key[i] ^ 0x36);
129-
}
130-
return func(Concatenate(o_key_pad, func(Concatenate(message, i_key_pad))));
131-
}
132-
private static byte[] HMAC_SHA1(byte[] key, byte[] message) => HMAC(key, message, SHA1, 20);
133-
private static byte[] Concatenate(params byte[][] bytes)
134-
{
135-
int alloc = 0;
136-
foreach (byte[] b in bytes) alloc += b.Length;
137-
byte[] result = new byte[alloc];
138-
alloc = 0;
139-
for (int i = 0; i < bytes.Length; ++i)
140-
{
141-
Array.Copy(bytes[i], 0, result, alloc, bytes[i].Length);
142-
alloc += bytes[i].Length;
143-
}
144-
return result;
145-
}
146-
public static byte[] SHA1(byte[] message)
147-
{
148-
// Initialize buffers
149-
uint h0 = 0x67452301;
150-
uint h1 = 0xEFCDAB89;
151-
uint h2 = 0x98BADCFE;
152-
uint h3 = 0x10325476;
153-
uint h4 = 0xC3D2E1F0;
154-
155-
// Pad message
156-
int ml = message.Length + 1;
157-
byte[] msg = new byte[ml + ((960 - (ml * 8 % 512)) % 512) / 8 + 8];
158-
Array.Copy(message, msg, message.Length);
159-
msg[message.Length] = 0x80;
160-
long len = message.Length * 8;
161-
for (int i = 0; i < 8; ++i) msg[msg.Length - 1 - i] = (byte)((len >> (i * 8)) & 255);
162-
//Support.WriteToArray(msg, message.Length * 8, msg.Length - 8);
163-
//for (int i = 0; i <4; ++i) msg[msg.Length - 5 - i] = (byte)(((message.Length*8) >> (i * 8)) & 255);
164-
165-
int chunks = msg.Length / 64;
166-
167-
// Perform hashing for each 512-bit block
168-
for (int i = 0; i < chunks; ++i)
169-
{
170-
171-
// Split block into words
172-
uint[] w = new uint[80];
173-
for (int j = 0; j < 16; ++j)
174-
w[j] |= (uint)((msg[i * 64 + j * 4] << 24) | (msg[i * 64 + j * 4 + 1] << 16) | (msg[i * 64 + j * 4 + 2] << 8) | (msg[i * 64 + j * 4 + 3] << 0));
175-
176-
// Expand words
177-
for (int j = 16; j < 80; ++j)
178-
w[j] = Rot(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
179-
180-
// Initialize chunk-hash
181-
uint
182-
a = h0,
183-
b = h1,
184-
c = h2,
185-
d = h3,
186-
e = h4;
187-
188-
// Do hash rounds
189-
for (int t = 0; t < 80; ++t)
190-
{
191-
uint tmp = ((a << 5) | (a >> (27))) +
192-
( // Round-function
193-
t < 20 ? (b & c) | ((~b) & d) :
194-
t < 40 ? b ^ c ^ d :
195-
t < 60 ? (b & c) | (b & d) | (c & d) :
196-
/*t<80*/ b ^ c ^ d
197-
) +
198-
e +
199-
( // K-function
200-
t < 20 ? 0x5A827999 :
201-
t < 40 ? 0x6ED9EBA1 :
202-
t < 60 ? 0x8F1BBCDC :
203-
/*t<80*/ 0xCA62C1D6
204-
) +
205-
w[t];
206-
e = d;
207-
d = c;
208-
c = Rot(b, 30);
209-
b = a;
210-
a = tmp;
211-
}
212-
h0 += a;
213-
h1 += b;
214-
h2 += c;
215-
h3 += d;
216-
h4 += e;
217-
}
218-
219-
return WriteContiguous(new byte[20], 0, SwapEndian(h0), SwapEndian(h1), SwapEndian(h2), SwapEndian(h3), SwapEndian(h4));
220-
}
221-
222-
private static uint Rot(uint val, int by) => (val << by) | (val >> (32 - by));
223-
224-
// Swap endianness of a given integer
225-
private static uint SwapEndian(uint value) => (uint)(((value >> 24) & (255 << 0)) | ((value >> 8) & (255 << 8)) | ((value << 8) & (255 << 16)) | ((value << 24) & (255 << 24)));
226-
227-
private static byte[] WriteToArray(byte[] target, uint data, int offset)
228-
{
229-
for (int i = 0; i < 4; ++i)
230-
target[i + offset] = (byte)((data >> (i * 8)) & 255);
231-
return target;
232-
}
233-
234-
private static byte[] WriteContiguous(byte[] target, int offset, params uint[] data)
235-
{
236-
for (int i = 0; i < data.Length; ++i) WriteToArray(target, data[i], offset + i * 4);
237-
return target;
78+
return new Rfc2898DeriveBytes(secret, Encoding.UTF8.GetBytes("P1sN0R4inb0wPl5P1sPls"), 1000).GetBytes(32);
23879
}
23980
}
24081

241-
public static class Helper
82+
public static class DHHelper
24283
{
24384
public static byte[] ToArray(this IntX v)
24485
{

MLAPI/NetworkingManagerComponents/EllipticCurve.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@
44

55
namespace ECDH
66
{
7-
public class Point
7+
public class CurvePoint
88
{
9-
public static readonly Point POINT_AT_INFINITY = new Point();
9+
public static readonly CurvePoint POINT_AT_INFINITY = new CurvePoint();
1010
public IntX X { get; private set; }
1111
public IntX Y { get; private set; }
1212
private bool pai = false;
13-
public Point(IntX x, IntX y)
13+
public CurvePoint(IntX x, IntX y)
1414
{
1515
X = x;
1616
Y = y;
1717
}
18-
private Point() { pai = true; } // Accessing corrdinates causes undocumented behaviour
18+
private CurvePoint() { pai = true; } // Accessing corrdinates causes undocumented behaviour
1919
public override string ToString()
2020
{
2121
return pai ? "(POINT_AT_INFINITY)" : "(" + X + ", " + Y + ")";
@@ -41,18 +41,18 @@ public EllipticCurve(IntX a, IntX b, IntX modulo, CurveType type = CurveType.Wei
4141
this.type = type;
4242
}
4343

44-
public Point Add(Point p1, Point p2)
44+
public CurvePoint Add(CurvePoint p1, CurvePoint p2)
4545
{
4646
#if SAFE_MATH
4747
CheckOnCurve(p1);
4848
CheckOnCurve(p2);
4949
#endif
5050

5151
// Special cases
52-
if (p1 == Point.POINT_AT_INFINITY && p2 == Point.POINT_AT_INFINITY) return Point.POINT_AT_INFINITY;
53-
else if (p1 == Point.POINT_AT_INFINITY) return p2;
54-
else if (p2 == Point.POINT_AT_INFINITY) return p1;
55-
else if (p1.X == p2.X && p1.Y == Inverse(p2).Y) return Point.POINT_AT_INFINITY;
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;
5656

5757
IntX x3 = 0, y3 = 0;
5858
if (type == CurveType.Weierstrass)
@@ -84,15 +84,15 @@ public Point Add(Point p1, Point p2)
8484
y3 = Mod(((2 * p1.X + p2.X + a) * co) - (b * co * co * co) - p1.Y);
8585
}
8686

87-
return new Point(x3, y3);
87+
return new CurvePoint(x3, y3);
8888
}
8989

90-
public Point Multiply(Point p, IntX scalar)
90+
public CurvePoint Multiply(CurvePoint p, IntX scalar)
9191
{
9292
if (scalar <= 0) throw new Exception("Cannot multiply by a scalar which is <= 0");
93-
if (p == Point.POINT_AT_INFINITY) return Point.POINT_AT_INFINITY;
93+
if (p == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY;
9494

95-
Point p1 = new Point(p.X, p.Y);
95+
CurvePoint p1 = new CurvePoint(p.X, p.Y);
9696
scalar.GetInternalState(out uint[] u, out bool b);
9797
long high_bit = -1;
9898
for (int i = u.Length - 1; i>=0; --i)
@@ -144,19 +144,19 @@ public static IntX MulInverse(IntX eq, IntX modulo)
144144
return Mod(m, modulo);
145145
}
146146

147-
public Point Inverse(Point p) => Inverse(p, modulo);
148-
protected static Point Inverse(Point p, IntX modulo) => new Point(p.X, Mod(-p.Y, modulo));
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));
149149

150-
public bool IsOnCurve(Point p)
150+
public bool IsOnCurve(CurvePoint p)
151151
{
152152
try { CheckOnCurve(p); }
153153
catch { return false; }
154154
return true;
155155
}
156-
protected void CheckOnCurve(Point p)
156+
protected void CheckOnCurve(CurvePoint p)
157157
{
158158
if (
159-
p!=Point.POINT_AT_INFINITY && // The point at infinity is asserted to be on the curve
159+
p!=CurvePoint.POINT_AT_INFINITY && // The point at infinity is asserted to be on the curve
160160
(type == CurveType.Weierstrass && Mod(p.Y * p.Y) != Mod((p.X * p.X * p.X) + (p.X * a) + b)) || // Weierstrass formula
161161
(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
162162
) throw new Exception("Point is not on curve");

0 commit comments

Comments
 (0)