stream ciphers do not work with udp FOOL
goon
This commit is contained in:
parent
ccc7ea5b25
commit
b49acd08d4
17 changed files with 295 additions and 113 deletions
29
protocol.md
29
protocol.md
|
@ -322,13 +322,32 @@ Communication between the master server and clients will be done over a WebSocke
|
||||||
</thead>
|
</thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="center">1</td>
|
<td class="center">1</td>
|
||||||
<td>Succeeded</td>
|
<td>Server Count (<i>n</i>)</td>
|
||||||
<td>Boolean</td>
|
<td>Packed Unsigned Short</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="center">2</td>
|
<td><i>r</i> > 1</td>
|
||||||
<td>Message</td>
|
<td colspan="2">Iterated over <i>n</i> (0 ≤ <i>i</i> ≤ <i>n - 1</i>)</td>
|
||||||
<td>String</td>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="center">2 + 4<i>i</i></td>
|
||||||
|
<td>Server Id</td>
|
||||||
|
<td>Packed Unsigned Short</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="center">3 + 4<i>i</i></td>
|
||||||
|
<td>User Count</td>
|
||||||
|
<td>Packed Unsigned Short</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="center">4 + 4<i>i</i></td>
|
||||||
|
<td>IP Address</td>
|
||||||
|
<td>IPv4 String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="center">5 + 4<i>i</i></td>
|
||||||
|
<td>Port</td>
|
||||||
|
<td>Packed Unsigned Short</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ namespace SockScape {
|
||||||
"Master Port",
|
"Master Port",
|
||||||
"Master Addr",
|
"Master Addr",
|
||||||
"Master Secret",
|
"Master Secret",
|
||||||
|
"Master IV",
|
||||||
"Max Users"
|
"Max Users"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
70
server/Encryption/BlockCipher.cs
Normal file
70
server/Encryption/BlockCipher.cs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Glove;
|
||||||
|
|
||||||
|
namespace SockScape.Encryption {
|
||||||
|
class BlockCipher {
|
||||||
|
public const int KeySize = 192;
|
||||||
|
public const int KeySizeBytes = KeySize / 8;
|
||||||
|
|
||||||
|
private readonly byte[] Key = new byte[KeySizeBytes];
|
||||||
|
private readonly byte[] IV;
|
||||||
|
|
||||||
|
public BlockCipher(BigInteger key) {
|
||||||
|
Key = Key.Select(x => (byte)0).ToArray();
|
||||||
|
Array.Copy(key.ToByteArray(), Key, Key.Length);
|
||||||
|
|
||||||
|
IV = Configuration.General["Master IV"].Str.HexStringToBytes()
|
||||||
|
?? new byte[] { 0x0b, 0xfc, 0xd7, 0x2d, 0x23, 0xb7, 0x83, 0xb2 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Encrypt(byte[] data) {
|
||||||
|
try {
|
||||||
|
var ms = new MemoryStream();
|
||||||
|
var cs = new CryptoStream(ms,
|
||||||
|
new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
|
||||||
|
CryptoStreamMode.Write);
|
||||||
|
|
||||||
|
cs.Write(data, 0, data.Length);
|
||||||
|
cs.FlushFinalBlock();
|
||||||
|
|
||||||
|
byte[] ret = ms.ToArray();
|
||||||
|
|
||||||
|
cs.Close();
|
||||||
|
ms.Close();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} catch(Exception e) {
|
||||||
|
Console.WriteLine($"TDES ENCRYPT ERROR: {e.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Decrypt(byte[] data) {
|
||||||
|
try {
|
||||||
|
var ms = new MemoryStream(data);
|
||||||
|
var cs = new CryptoStream(ms,
|
||||||
|
new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
|
||||||
|
CryptoStreamMode.Read);
|
||||||
|
|
||||||
|
byte[] ret = new byte[data.Length];
|
||||||
|
cs.Read(ret, 0, data.Length);
|
||||||
|
|
||||||
|
cs.Close();
|
||||||
|
ms.Close();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} catch(Exception e) {
|
||||||
|
Console.WriteLine($"TDES DECRYPT ERROR: {e.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,10 +6,14 @@ using System.Threading.Tasks;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Glove;
|
using Glove;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace SockScape.Encryption {
|
namespace SockScape.Encryption {
|
||||||
class Key {
|
class Key {
|
||||||
private static readonly BigInteger Secret = RNG.NextPrime(512 / 8);
|
public const int KeySize = 512;
|
||||||
|
public const int KeySizeBytes = KeySize / 8;
|
||||||
|
|
||||||
|
private static readonly BigInteger Secret = RNG.NextPrime(KeySizeBytes);
|
||||||
public BigInteger Generator { get; } = 2;
|
public BigInteger Generator { get; } = 2;
|
||||||
public BigInteger Modulus { get; }
|
public BigInteger Modulus { get; }
|
||||||
public BigInteger PrivateKey { get; private set; } = BigInteger.Zero;
|
public BigInteger PrivateKey { get; private set; } = BigInteger.Zero;
|
||||||
|
@ -17,7 +21,7 @@ namespace SockScape.Encryption {
|
||||||
=> !PrivateKey.IsZero;
|
=> !PrivateKey.IsZero;
|
||||||
|
|
||||||
public Key() {
|
public Key() {
|
||||||
Modulus = RNG.NextPrime(512 / 8);
|
Modulus = RNG.NextPrime(KeySizeBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Packet GenerateRequestPacket() {
|
public Packet GenerateRequestPacket() {
|
||||||
|
|
|
@ -7,11 +7,11 @@ using System.Numerics;
|
||||||
using Glove;
|
using Glove;
|
||||||
|
|
||||||
namespace SockScape.Encryption {
|
namespace SockScape.Encryption {
|
||||||
class Cipher {
|
class StreamCipher {
|
||||||
private readonly byte[] Key = new byte[512 / 8];
|
private readonly byte[] Key = new byte[Encryption.Key.KeySizeBytes];
|
||||||
private readonly byte[] State = new byte[256];
|
private readonly byte[] State = new byte[256];
|
||||||
|
|
||||||
public Cipher(BigInteger key) {
|
public StreamCipher(BigInteger key) {
|
||||||
int i = 0, j = 0;
|
int i = 0, j = 0;
|
||||||
State = State.Select(x => (byte)i++).ToArray();
|
State = State.Select(x => (byte)i++).ToArray();
|
||||||
Key = Key.Select(x => (byte)0).ToArray();
|
Key = Key.Select(x => (byte)0).ToArray();
|
|
@ -14,10 +14,20 @@ using MySql.Data.Entity;
|
||||||
|
|
||||||
namespace SockScape {
|
namespace SockScape {
|
||||||
static class ServerContext {
|
static class ServerContext {
|
||||||
public static Dictionary<int, Server<PlayerConnection>> Servers { get; }
|
public static Dictionary<ushort, Server<PlayerConnection>> Servers { get; }
|
||||||
= new Dictionary<int, Server<PlayerConnection>>();
|
= new Dictionary<ushort, Server<PlayerConnection>>();
|
||||||
public static Dictionary<int, Pool<PlayerConnection>> Pools { get; }
|
public static Dictionary<ushort, Pool<PlayerConnection>> Pools { get; }
|
||||||
= new Dictionary<int, Pool<PlayerConnection>>();
|
= new Dictionary<ushort, Pool<PlayerConnection>>();
|
||||||
|
|
||||||
|
public static Packet StatusUpdatePacket {
|
||||||
|
get {
|
||||||
|
var packet = new Packet(kIntraSlaveId.StatusUpdate, (byte)Servers.Count);
|
||||||
|
foreach(var pool in Pools)
|
||||||
|
packet.AddRegions(pool.Key.Pack(), ((ushort)pool.Value.ConnectionCount).Pack(), Servers[pool.Key].Port.Pack());
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Entrypoint {
|
class Entrypoint {
|
||||||
|
@ -33,8 +43,8 @@ namespace SockScape {
|
||||||
|
|
||||||
var serverHandle = new Server<PlayerConnection>((ushort)server["Port"], pool, server);
|
var serverHandle = new Server<PlayerConnection>((ushort)server["Port"], pool, server);
|
||||||
|
|
||||||
ServerContext.Pools.Add(server["Id"], pool);
|
ServerContext.Pools.Add((ushort)server["Id"], pool);
|
||||||
ServerContext.Servers.Add(server["Id"], serverHandle);
|
ServerContext.Servers.Add((ushort)server["Id"], serverHandle);
|
||||||
serverHandle.Start();
|
serverHandle.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,24 +12,29 @@ namespace Glove.INI {
|
||||||
Raw = raw;
|
Raw = raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator string(Value value) {
|
public string Str
|
||||||
return value.Raw;
|
=> this;
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator bool(Value value) {
|
public Int32 Int
|
||||||
return Boolean.TryParse(value.Raw, out bool retval) && retval;
|
=> this;
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Int32(Value value) {
|
public double Dbl
|
||||||
return Int32.TryParse(value.Raw, out Int32 retval)
|
=> this;
|
||||||
|
|
||||||
|
public static implicit operator string(Value value)
|
||||||
|
=> value.Raw;
|
||||||
|
|
||||||
|
public static implicit operator bool(Value value)
|
||||||
|
=> Boolean.TryParse(value.Raw, out bool retval) && retval;
|
||||||
|
|
||||||
|
public static implicit operator Int32(Value value)
|
||||||
|
=> Int32.TryParse(value.Raw, out Int32 retval)
|
||||||
? retval
|
? retval
|
||||||
: 0;
|
: 0;
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator double(Value value) {
|
public static implicit operator double(Value value)
|
||||||
return Double.TryParse(value.Raw, out double retval)
|
=> Double.TryParse(value.Raw, out double retval)
|
||||||
? retval
|
? retval
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,5 +60,23 @@ namespace Glove {
|
||||||
|
|
||||||
public static BigInteger HexStringToBigInt(this string value)
|
public static BigInteger HexStringToBigInt(this string value)
|
||||||
=> BigInteger.Parse(value, NumberStyles.HexNumber);
|
=> BigInteger.Parse(value, NumberStyles.HexNumber);
|
||||||
|
|
||||||
|
public static byte[] HexStringToBytes(this string value) {
|
||||||
|
if(value.Length % 2 == 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var bytes = new byte[value.Length / 2];
|
||||||
|
for(var i = 0; i < bytes.Length; ++i) {
|
||||||
|
char upperNibble = value[2 * i],
|
||||||
|
lowerNibble = value[2 * i + 1];
|
||||||
|
|
||||||
|
if(!upperNibble.IsHex() || !lowerNibble.IsHex())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
bytes[i] = (byte)((upperNibble.HexValue() << 4) | lowerNibble.HexValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,18 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Glove {
|
namespace Glove {
|
||||||
|
public static class CharExtensions {
|
||||||
|
public static bool IsHex(this char c) {
|
||||||
|
return (c >= '0' && c <= '9')
|
||||||
|
|| (c >= 'A' && c <= 'F')
|
||||||
|
|| (c >= 'a' && c <= 'f');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte HexValue(this char c) {
|
||||||
|
return (byte)(!c.IsHex() ? 0 : c - (c < 0x3A ? 0x30 : (c < 0x61 ? 0x37 : 0x57)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class StringExtensions {
|
public static class StringExtensions {
|
||||||
public static byte[] GetBytes(this string str, bool isUtf8 = true)
|
public static byte[] GetBytes(this string str, bool isUtf8 = true)
|
||||||
=> isUtf8 ? Encoding.UTF8.GetBytes(str)
|
=> isUtf8 ? Encoding.UTF8.GetBytes(str)
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace Kneesocks {
|
||||||
Service_Unavailable = 503,
|
Service_Unavailable = 503,
|
||||||
Gateway_Timeout = 504
|
Gateway_Timeout = 504
|
||||||
}
|
}
|
||||||
public kStatusCode? StatusCode { get; private set; } = null;
|
public kStatusCode? StatusCode { get; } = null;
|
||||||
protected string StatusCodeText
|
protected string StatusCodeText
|
||||||
=> Enum.GetName(typeof(kStatusCode), StatusCode).Replace('_', ' ');
|
=> Enum.GetName(typeof(kStatusCode), StatusCode).Replace('_', ' ');
|
||||||
|
|
||||||
|
|
50
server/MasterServerList.cs
Normal file
50
server/MasterServerList.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Glove;
|
||||||
|
|
||||||
|
namespace SockScape {
|
||||||
|
static class MasterServerList {
|
||||||
|
public static Dictionary<UInt16, Server> Servers { get; }
|
||||||
|
= new Dictionary<UInt16, Server>();
|
||||||
|
|
||||||
|
public static void Write(Server server) {
|
||||||
|
lock(Servers) {
|
||||||
|
if(HasId(server.Id) && !Servers[server.Id].Address.Equals(server.Address))
|
||||||
|
Console.WriteLine($"{DateTime.Now.ToShortTimeString()} - Server {server.Id} has changed IP addresses.");
|
||||||
|
|
||||||
|
Servers[server.Id] = server;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Packet ReportPacket {
|
||||||
|
get {
|
||||||
|
lock(Servers) {
|
||||||
|
var packet = new Packet(kInterMasterId.ServerListing, ((ushort)Servers.Count).Pack());
|
||||||
|
foreach(var server in Servers)
|
||||||
|
// TODO change this to support IPv6
|
||||||
|
packet.AddRegions(server.Key.Pack(), server.Value.UserCount.Pack(),
|
||||||
|
server.Value.Address.MapToIPv4().ToString(), server.Value.Port.Pack());
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasId(UInt16 id)
|
||||||
|
=> Servers.ContainsKey(id);
|
||||||
|
|
||||||
|
public static void Clear()
|
||||||
|
=> Servers.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Server {
|
||||||
|
public ushort Id { get; set; }
|
||||||
|
public ushort UserCount { get; set; }
|
||||||
|
public IPAddress Address { get; set; }
|
||||||
|
public ushort Port { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,56 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace SockScape {
|
|
||||||
static class ServerList {
|
|
||||||
private static ServerDictionary Servers { get; }
|
|
||||||
= new ServerDictionary();
|
|
||||||
|
|
||||||
private static Dictionary<UInt16, Server> List
|
|
||||||
=> Servers.List;
|
|
||||||
|
|
||||||
public static void Write(Server server) {
|
|
||||||
lock(Servers) {
|
|
||||||
if(HasId(server.Id) && !List[server.Id].Address.Equals(server.Address))
|
|
||||||
Console.WriteLine($"{DateTime.Now.ToShortTimeString()} - Server {server.Id} has changed IP addresses.");
|
|
||||||
|
|
||||||
List[server.Id] = server;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Packet ReportPacket {
|
|
||||||
get {
|
|
||||||
var packet = new Packet(kInterMasterId.);
|
|
||||||
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool HasId(UInt16 id)
|
|
||||||
=> List.ContainsKey(id);
|
|
||||||
|
|
||||||
public static void Clear()
|
|
||||||
=> List.Clear();
|
|
||||||
|
|
||||||
public class ServerDictionary {
|
|
||||||
public Dictionary<UInt16, Server> List { get; }
|
|
||||||
= new Dictionary<UInt16, Server>();
|
|
||||||
|
|
||||||
public Server this[UInt16 i] {
|
|
||||||
get => List.ContainsKey(i) ? List[i] : null;
|
|
||||||
set => List[i] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Server {
|
|
||||||
public ushort Id { get; set; }
|
|
||||||
public ushort UserCount { get; set; }
|
|
||||||
public IPAddress Address { get; set; }
|
|
||||||
public ushort Port { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -94,17 +94,18 @@
|
||||||
<Compile Include="DAL\ScapeDb.cs" />
|
<Compile Include="DAL\ScapeDb.cs" />
|
||||||
<Compile Include="DAL\Session.cs" />
|
<Compile Include="DAL\Session.cs" />
|
||||||
<Compile Include="DAL\User.cs" />
|
<Compile Include="DAL\User.cs" />
|
||||||
|
<Compile Include="Encryption\BlockCipher.cs" />
|
||||||
<Compile Include="Encryption\KeyExchange.cs" />
|
<Compile Include="Encryption\KeyExchange.cs" />
|
||||||
<Compile Include="Encryption\Cipher.cs" />
|
<Compile Include="Encryption\StreamCipher.cs" />
|
||||||
<Compile Include="Migrations\201708251600325_Initial.cs" />
|
<Compile Include="Migrations\201708251600325_Initial.cs" />
|
||||||
<Compile Include="Migrations\201708251600325_Initial.Designer.cs">
|
<Compile Include="Migrations\201708251600325_Initial.Designer.cs">
|
||||||
<DependentUpon>201708251600325_Initial.cs</DependentUpon>
|
<DependentUpon>201708251600325_Initial.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Migrations\Configuration.cs" />
|
<Compile Include="Migrations\Configuration.cs" />
|
||||||
<Compile Include="ServerList.cs" />
|
<Compile Include="MasterServerList.cs" />
|
||||||
<Compile Include="Socks\MasterConnection.cs" />
|
<Compile Include="Socks\MasterConnection.cs" />
|
||||||
<Compile Include="Socks\MasterUdpClient.cs" />
|
<Compile Include="Socks\MasterIntraClient.cs" />
|
||||||
<Compile Include="Socks\MasterUdpServer.cs" />
|
<Compile Include="Socks\MasterIntraServer.cs" />
|
||||||
<Compile Include="Socks\Protocols\ClientServerIds.cs" />
|
<Compile Include="Socks\Protocols\ClientServerIds.cs" />
|
||||||
<Compile Include="Socks\Protocols\InterMasterIds.cs" />
|
<Compile Include="Socks\Protocols\InterMasterIds.cs" />
|
||||||
<Compile Include="Socks\Protocols\IntraMasterIds.cs" />
|
<Compile Include="Socks\Protocols\IntraMasterIds.cs" />
|
||||||
|
|
|
@ -10,7 +10,7 @@ using SockScape.Encryption;
|
||||||
namespace SockScape {
|
namespace SockScape {
|
||||||
class MasterConnection : Connection {
|
class MasterConnection : Connection {
|
||||||
private Key Key;
|
private Key Key;
|
||||||
public Cipher Encryptor { get; private set; }
|
public StreamCipher Encryptor { get; private set; }
|
||||||
|
|
||||||
protected override void OnOpen() {
|
protected override void OnOpen() {
|
||||||
Key = new Key();
|
Key = new Key();
|
||||||
|
@ -39,7 +39,7 @@ namespace SockScape {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Encryptor = new Cipher(Key.PrivateKey);
|
Encryptor = new StreamCipher(Key.PrivateKey);
|
||||||
break;
|
break;
|
||||||
case kInterMasterId.LoginAttempt:
|
case kInterMasterId.LoginAttempt:
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,8 @@ using Glove;
|
||||||
using SockScape.Encryption;
|
using SockScape.Encryption;
|
||||||
|
|
||||||
namespace SockScape {
|
namespace SockScape {
|
||||||
static class MasterUdpClient {
|
static class MasterIntraClient {
|
||||||
private static Key Key;
|
private static Key Key;
|
||||||
private static Cipher Encryptor;
|
|
||||||
|
|
||||||
private static UdpClient Sock;
|
private static UdpClient Sock;
|
||||||
private static Thread ListeningThread;
|
private static Thread ListeningThread;
|
||||||
|
@ -55,10 +54,9 @@ namespace SockScape {
|
||||||
switch((kIntraMasterId)packet.Id) {
|
switch((kIntraMasterId)packet.Id) {
|
||||||
case kIntraMasterId.KeyExchange:
|
case kIntraMasterId.KeyExchange:
|
||||||
var responsePacket = Key.ParseRequestPacket(packet);
|
var responsePacket = Key.ParseRequestPacket(packet);
|
||||||
Encryptor = new Cipher(Key.PrivateKey);
|
Encryptor = new StreamCipher(Key.PrivateKey);
|
||||||
if(responsePacket != null)
|
if(responsePacket != null)
|
||||||
Send(responsePacket);
|
Send(responsePacket);
|
||||||
|
|
||||||
else
|
else
|
||||||
LastMessageIn = new DateTime(0);
|
LastMessageIn = new DateTime(0);
|
||||||
break;
|
break;
|
||||||
|
@ -72,6 +70,8 @@ namespace SockScape {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kIntraMasterId.EncryptionError:
|
case kIntraMasterId.EncryptionError:
|
||||||
|
NextSendId = NextRecvId = 0;
|
||||||
|
Buffer.Clear();
|
||||||
Key = new Key();
|
Key = new Key();
|
||||||
Encryptor = null;
|
Encryptor = null;
|
||||||
LastMessageIn = new DateTime(0);
|
LastMessageIn = new DateTime(0);
|
||||||
|
@ -79,9 +79,9 @@ namespace SockScape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LastMessageIn.Ticks != 0) {
|
if(LastMessageIn.Ticks != 0) {
|
||||||
if(DeltaLastOut.TotalSeconds > 2)
|
if(DeltaLastOut.TotalSeconds > 2)
|
||||||
Send(new Packet());
|
Send(Encryptor.Parse(ServerContext.StatusUpdatePacket.GetBytes()));
|
||||||
} else
|
} else
|
||||||
if(DeltaLastOut.TotalSeconds > 10)
|
if(DeltaLastOut.TotalSeconds > 10)
|
||||||
Send(new Packet(kIntraSlaveId.InitiationAttempt, Configuration.General["Master Secret"]));
|
Send(new Packet(kIntraSlaveId.InitiationAttempt, Configuration.General["Master Secret"]));
|
||||||
|
@ -91,9 +91,14 @@ namespace SockScape {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Send(Packet packet) {
|
public static void Send(Packet packet) {
|
||||||
var message = packet.GetBytes();
|
Send(packet.GetBytes());
|
||||||
Sock.Send(message, message.Length);
|
}
|
||||||
|
|
||||||
|
public static void Send(byte[] bytes) {
|
||||||
|
Sock.Send(bytes, bytes.Length);
|
||||||
LastMessageOut = DateTime.Now;
|
LastMessageOut = DateTime.Now;
|
||||||
|
Buffer.Add(NextSendId, bytes);
|
||||||
|
++NextSendId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Close() {
|
public static void Close() {
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -23,7 +24,7 @@ namespace SockScape {
|
||||||
if(IsOpen || ListeningThread != null)
|
if(IsOpen || ListeningThread != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ServerList.Clear();
|
MasterServerList.Clear();
|
||||||
Prospects = new Dictionary<string, Client>();
|
Prospects = new Dictionary<string, Client>();
|
||||||
Clients = new Dictionary<string, Client>();
|
Clients = new Dictionary<string, Client>();
|
||||||
|
|
||||||
|
@ -49,8 +50,11 @@ namespace SockScape {
|
||||||
encryptor == null ? Packet.FromBytes(data)
|
encryptor == null ? Packet.FromBytes(data)
|
||||||
: Packet.FromBytes(encryptor.Parse(data));
|
: Packet.FromBytes(encryptor.Parse(data));
|
||||||
|
|
||||||
if(packet == null)
|
if(packet == null) {
|
||||||
|
if(encryptor != null)
|
||||||
|
EncryptionError(endPoint);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Clients[client].LastReceive = DateTime.Now;
|
Clients[client].LastReceive = DateTime.Now;
|
||||||
switch((kIntraSlaveId)packet.Id) {
|
switch((kIntraSlaveId)packet.Id) {
|
||||||
|
@ -76,7 +80,8 @@ namespace SockScape {
|
||||||
|
|
||||||
var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
|
var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
|
||||||
if(privateKey != -1) {
|
if(privateKey != -1) {
|
||||||
Prospects[client].Encryptor = new Cipher(privateKey);
|
Prospects[client].LastReceive = DateTime.Now;
|
||||||
|
Prospects[client].Encryptor = new StreamCipher(privateKey);
|
||||||
Clients[client] = Prospects[client];
|
Clients[client] = Prospects[client];
|
||||||
Prospects.Remove(client);
|
Prospects.Remove(client);
|
||||||
} else
|
} else
|
||||||
|
@ -88,13 +93,13 @@ namespace SockScape {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(packet.CheckRegions(0, 1)) {
|
if(packet.CheckRegions(0, 1)) {
|
||||||
NegativeAck(endPoint, kIntraSlaveId.StatusUpdate, "Server count is malformed.");
|
NegativeAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate, "Server count is malformed.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte serverCount = packet[0].Raw[0];
|
byte serverCount = packet[0].Raw[0];
|
||||||
if(packet.RegionCount != 1 + 3 * serverCount) {
|
if(packet.RegionCount != 1 + 3 * serverCount) {
|
||||||
NegativeAck(endPoint, kIntraSlaveId.StatusUpdate, "Region count does not match server count");
|
NegativeAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate, "Region count does not match server count");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +107,7 @@ namespace SockScape {
|
||||||
if(!packet.CheckRegions(2 + 3 * i, 2, 2, 2))
|
if(!packet.CheckRegions(2 + 3 * i, 2, 2, 2))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ServerList.Write(new Server {
|
MasterServerList.Write(new Server {
|
||||||
Id = packet[2 + 3 * i].Raw.UnpackUInt16(),
|
Id = packet[2 + 3 * i].Raw.UnpackUInt16(),
|
||||||
UserCount = packet[3 + 3 * i].Raw.UnpackUInt16(),
|
UserCount = packet[3 + 3 * i].Raw.UnpackUInt16(),
|
||||||
Address = endPoint.Address,
|
Address = endPoint.Address,
|
||||||
|
@ -110,7 +115,7 @@ namespace SockScape {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PositiveAck(endPoint, kIntraSlaveId.StatusUpdate);
|
PositiveAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,8 +127,11 @@ namespace SockScape {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Send(Packet packet, IPEndPoint client) {
|
private static void Send(Packet packet, IPEndPoint client) {
|
||||||
var message = packet.GetBytes();
|
Send(packet.GetBytes(), client);
|
||||||
Sock.Send(message, message.Length, client);
|
}
|
||||||
|
|
||||||
|
private static void Send(byte[] bytes, IPEndPoint client) {
|
||||||
|
Sock.Send(bytes, bytes.Length, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Close() {
|
public static void Close() {
|
||||||
|
@ -141,12 +149,12 @@ namespace SockScape {
|
||||||
return Clients.ContainsKey(client);
|
return Clients.ContainsKey(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PositiveAck(IPEndPoint endPoint, kIntraSlaveId id) {
|
private static void PositiveAck(IPEndPoint endPoint, StreamCipher cipher, kIntraSlaveId id) {
|
||||||
Send(new Packet(kIntraMasterId.PositiveAck, id), endPoint);
|
Send(cipher.Parse(new Packet(kIntraMasterId.PositiveAck, id).GetBytes()), endPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void NegativeAck(IPEndPoint endPoint, kIntraSlaveId id, string message = "An error occurred while parsing a packet.") {
|
private static void NegativeAck(IPEndPoint endPoint, StreamCipher cipher, kIntraSlaveId id, string message = "An error occurred while parsing a packet.") {
|
||||||
Send(new Packet(kIntraMasterId.NegativeAck, id, message), endPoint);
|
Send(cipher.Parse(new Packet(kIntraMasterId.NegativeAck, id, message).GetBytes()), endPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EncryptionError(IPEndPoint endPoint, string message = "A general encryption error has occurred. Renegotiation required.") {
|
private static void EncryptionError(IPEndPoint endPoint, string message = "A general encryption error has occurred. Renegotiation required.") {
|
||||||
|
@ -157,7 +165,7 @@ namespace SockScape {
|
||||||
public IPEndPoint Address { get; set; }
|
public IPEndPoint Address { get; set; }
|
||||||
public DateTime LastReceive { get; set; }
|
public DateTime LastReceive { get; set; }
|
||||||
public TimeSpan ReceiveDelta => DateTime.Now - LastReceive;
|
public TimeSpan ReceiveDelta => DateTime.Now - LastReceive;
|
||||||
public Cipher Encryptor { get; set; }
|
public StreamCipher Encryptor { get; set; }
|
||||||
public Key Key { get; set; }
|
public Key Key { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -92,6 +92,13 @@ namespace SockScape {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Packet AddRegions(params object[] regions) {
|
||||||
|
foreach(var region in regions)
|
||||||
|
AddRegion(region);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public bool CheckRegions(int startIndex, params int[] lengths) {
|
public bool CheckRegions(int startIndex, params int[] lengths) {
|
||||||
if(startIndex + lengths.Length > RegionCount)
|
if(startIndex + lengths.Length > RegionCount)
|
||||||
return false;
|
return false;
|
||||||
|
@ -150,4 +157,32 @@ namespace SockScape {
|
||||||
=> this;
|
=> this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PacketBuffer {
|
||||||
|
private short MaxSize;
|
||||||
|
private Dictionary<uint, byte[]> Buffer
|
||||||
|
= new Dictionary<uint, byte[]>();
|
||||||
|
|
||||||
|
public PacketBuffer(short maxSize = 10) {
|
||||||
|
MaxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(uint id, byte[] packet) {
|
||||||
|
Buffer[id] = packet;
|
||||||
|
|
||||||
|
if(Buffer.Count > 10)
|
||||||
|
Buffer =
|
||||||
|
Buffer.Where(x => x.Key >= id - 10)
|
||||||
|
.ToDictionary(x => x.Key, x => x.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] this[uint i]
|
||||||
|
=> Buffer[i];
|
||||||
|
|
||||||
|
public bool HasId(uint id)
|
||||||
|
=> Buffer.ContainsKey(id);
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
=> Buffer.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue