Updated some old code to use new methods ECDH implementation now uses BitWriter/BitReader to serialize/deserialize Added error handling to NetClient for predictable cases of error Fixed regular SHA1 implementation Partially remade optimized SHA1 implementation as a hybrid implementation between minimum allocation and minimum processor overhead Fixed how Databse manages serialization/deserialization of Users Updated Output class to support any type Output now supports overwritable lines Added OutputFormatter to simplify creating-column output Sessions keys are no longer invalidated when client-server connection is closed Added command system to server for easier administration
82 lines
3.1 KiB
C#
82 lines
3.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Tofvesson.Common;
|
|
using Tofvesson.Crypto;
|
|
|
|
namespace Common.Cryptography.KeyExchange
|
|
{
|
|
public class EllipticDiffieHellman : IKeyExchange
|
|
{
|
|
private static readonly BigInteger c_25519_prime = (BigInteger.One << 255) - 19;
|
|
private static readonly BigInteger c_25519_order = (BigInteger.One << 252) + BigInteger.Parse("27742317777372353535851937790883648493"); // 27_742_317_777_372_353_535_851_937_790_883_648_493
|
|
private static readonly EllipticCurve c_25519 = new EllipticCurve(486662, 1, c_25519_prime, EllipticCurve.CurveType.Montgomery);
|
|
private static readonly Point c_25519_gen = new Point(9, BigInteger.Parse("14781619447589544791020593568409986887264606134616475288964881837755586237401"));
|
|
|
|
protected static readonly Random rand = new Random();
|
|
|
|
protected readonly EllipticCurve curve;
|
|
public readonly BigInteger priv;
|
|
protected readonly Point generator, pub;
|
|
|
|
|
|
public EllipticDiffieHellman(EllipticCurve curve, Point generator, BigInteger order, byte[] priv = null)
|
|
{
|
|
this.curve = curve;
|
|
this.generator = generator;
|
|
|
|
// Generate private key
|
|
if (priv == null)
|
|
{
|
|
byte[] max = order.ToByteArray();
|
|
do
|
|
{
|
|
byte[] p1 = new byte[5 /*rand.Next(max.Length) + 1*/];
|
|
|
|
rand.NextBytes(p1);
|
|
|
|
if (p1.Length == max.Length) p1[p1.Length - 1] %= max[max.Length - 1];
|
|
else p1[p1.Length - 1] &= 127;
|
|
|
|
this.priv = new BigInteger(p1);
|
|
} while (this.priv < 2);
|
|
}
|
|
else this.priv = new BigInteger(priv);
|
|
|
|
// Generate public key
|
|
pub = curve.Multiply(generator, this.priv);
|
|
}
|
|
|
|
public byte[] GetPublicKey()
|
|
{
|
|
using (BitWriter writer = new BitWriter())
|
|
{
|
|
writer.WriteByteArray(pub.X.ToByteArray());
|
|
writer.WriteByteArray(pub.Y.ToByteArray(), true);
|
|
return writer.Finalize();
|
|
}
|
|
}
|
|
|
|
public byte[] GetPrivateKey() => priv.ToByteArray();
|
|
|
|
public byte[] GetSharedSecret(byte[] pK)
|
|
{
|
|
BitReader reader = new BitReader(pK);
|
|
|
|
byte[] x = reader.ReadByteArray();
|
|
Point remotePublic = new Point(
|
|
new BigInteger(x),
|
|
new BigInteger(reader.ReadByteArray(pK.Length - BinaryHelpers.VarIntSize(x.Length) - x.Length))
|
|
);
|
|
|
|
return curve.Multiply(remotePublic, priv).X.ToByteArray(); // Use the x-coordinate as the shared secret
|
|
}
|
|
|
|
public static EllipticDiffieHellman Curve25519(BigInteger priv) => new EllipticDiffieHellman(c_25519, c_25519_gen, c_25519_order, priv.ToByteArray());
|
|
public static BigInteger Curve25519_GeneratePrivate(RandomProvider provider) => Support.GenerateRandom(provider, c_25519_order - 2) + 2;
|
|
}
|
|
}
|